Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error while running meshfix.repair() #41

Open
MarcelHeu opened this issue Feb 24, 2022 · 10 comments
Open

Error while running meshfix.repair() #41

MarcelHeu opened this issue Feb 24, 2022 · 10 comments

Comments

@MarcelHeu
Copy link

Hey,

If i try to repair an input mesh file, the following error will follow:

Windows fatal exception: access violation


Main thread:
Current thread 0x000031d4 (most recent call first):
  File "C:\Developer\WPy64-3950\python-3.9.5.amd64\lib\site-packages\pymeshfix\meshfix.py", line 207 in repair
  File "C:\Users\Marcel\Desktop\untitled5.py", line 84 in <module>
  File "C:\Developer\WPy64-3950\python-3.9.5.amd64\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 465 in exec_code
  File "C:\Developer\WPy64-3950\python-3.9.5.amd64\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 585 in runfile
  File "C:\Users\Marcel\AppData\Local\Temp\ipykernel_6628\358323758.py", line 1 in <module>


Restarting kernel...

i got the following pyvista Report:

--------------------------------------------------------------------------------
  Date: Thu Feb 24 12:00:46 2022 Mitteleuropäische Zeit

                OS : Windows
            CPU(s) : 8
           Machine : AMD64
      Architecture : 64bit
               RAM : 31.7 GiB
       Environment : IPython
       File system : unknown
       GPU Details : None

  Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC v.1928 64 bit
  (AMD64)]

           pyvista : 0.33.2
               vtk : 9.1.0
             numpy : 1.21.0
           imageio : 2.9.0
           appdirs : 1.4.4
            scooby : 0.5.11
        matplotlib : 3.4.2
             PyQt5 : 5.12.3
           IPython : 7.25.0
          colorcet : 1.0.0
             scipy : 1.7.0
              tqdm : 4.61.1

  Intel(R) Math Kernel Library Version 2020.0.4 Product Build 20200917 for
  Intel(R) 64 architecture applications
--------------------------------------------------------------------------------
@banesullivan
Copy link
Member

Could you share the mesh file?

@MarcelHeu
Copy link
Author

MarcelHeu commented Mar 9, 2022

@MarcelHeu
Copy link
Author

hey @banesullivan,

can you assume what could be the issue or do i have to pass maybe another parameter to the function?

best regards,
Marcel

@adeak
Copy link
Member

adeak commented May 9, 2022

I can reproduce a segfault on my debian linux (which is the same thing as "Windows fatal exception: access violation" in your case). Here's the snippet I used, taken from your question on Stack Overflow:

import pymeshfix
import trimesh

model = trimesh.load("waxup_slm_cad.stl")

# Create object from vertex and face arrays
meshfix = pymeshfix.MeshFix(model.vertices, model.faces)

# Repair the mesh
meshfix.repair()

I don't know exactly what's going on, but I've investigated a bit:

  1. Your mesh reads fine, and according to pyvista.wrap(model) it's composed entirely of triangles, and .clean() does nothing with the mesh. This suggests no funny business with degenerate cells.
  2. The segfault happens deep inside the call stack, during a call to duplicateNonManifoldVertices().

Here's the layout of execution:
meshfix.repair() ->

self.v, self.f = _meshfix.clean_from_arrays(self.v, self.f,
verbose, joincomp,
remove_smallest_components)

->

# Create mesh object and load from file
tin = PyTMesh(verbose)
tin.load_array(v, f)

(note that this is before the actual repairing starts; the segfault happens during tin.load_array())

# Load to C object
self.c_tmesh.loadArray(nv, &points[0], nt, &faces[0])

-> Basic_TMesh_wrap::loadArray()

// Fix connectivity
fixConnectivity();

->

///// Fix geometric connectivity //////////
bool Basic_TMesh::fixConnectivity(){ //!< AMF_ADD 1.1>
bool retval = true;
int i;
if ((i = removeVertices())) { retval = false; TMesh::warning("%d isolated vertices have been removed.\n", i); }
if (cutAndStitch()) { retval=false; TMesh::warning("Some cuts were necessary to cope with non manifold configuration.\n"); }
if (forceNormalConsistence()) { retval = false; TMesh::warning("Some triangles have been reversed to achieve orientation.\n"); }
if ((i=duplicateNonManifoldVertices())) { retval=false; TMesh::warning("%d non-manifold vertices have been duplicated.\n",i); }
if ((i=removeDuplicatedTriangles())) { retval=false; TMesh::warning("%d double-triangles have been removed.\n",i); }
return retval;
}

We're getting close: the segfault happens on line 317, inside the call to Basic_TMesh::cutAndStitch():

forceNormalConsistence();
duplicateNonManifoldVertices();

And the final destination is Basic_TMesh::duplicateNonManifoldVertices():

int Basic_TMesh::duplicateNonManifoldVertices()
{
Vertex *v;
Edge *e, *f;
Node *n, *m;
List *ve;
int dv = 0;
FOREACHEDGE(e, n)
{
ve = e->v1->VE();
if (ve->containsNode(e) == NULL)
{
v = newVertex(e->v1); //!
v->info = e->v1->info; //! < AMF_CHANGE 1.1-2 >
v->mask = 0; //!
V.appendHead(v);
FOREACHVEEDGE(ve, f, m) f->replaceVertex(e->v1, v);
v->e0 = e->v1->e0;
e->v1->e0 = e;
dv++;
}
delete(ve);
}
FOREACHEDGE(e, n)
{
ve = e->v2->VE();
if (ve->containsNode(e) == NULL)
{
v = newVertex(e->v2); //!
v->info = e->v2->info; //! < AMF_CHANGE 1.1-2 >
v->mask = 0; //!
V.appendHead(v);
FOREACHVEEDGE(ve, f, m) f->replaceVertex(e->v2, v);
v->e0 = e->v2->e0;
e->v2->e0 = e;
dv++;
}
delete(ve);
}

The segfault seems to happen on line 138 of the above:

FOREACHEDGE(e, n)
{
ve = e->v1->VE();

Since I'm not familiar with the library I'm not going to try and reverse-engineer that data structure with somewhat opaque member names :) Hopefully this will help someone who knows the library figure out what's wrong.

@chen112p
Copy link

chen112p commented Jul 3, 2022

maybe this problem has been fixed. I didnt run into any issue loading the geometry with pyvista

@adeak
Copy link
Member

adeak commented Jul 3, 2022

@chen112p loading the mesh is fine. What breaks is repair() of pymeshfix, see my snippet in #41 (comment).

@MarioAuditore
Copy link

Got similar error, while trying to repair my mesh. Any workarounds?

@carbocation
Copy link

carbocation commented Apr 9, 2023

For what it's worth, I get this error nondeterministically. When using faulthandler to try to localize it, I see the following:

Current thread 0x000000020b9b3a80 (most recent call first):
  File "/opt/homebrew/lib/python3.10/site-packages/pymeshfix/meshfix.py", line 201 in repair

That line number is the point at which clean_from_arrays gets called:

self.v, self.f = _meshfix.clean_from_arrays(
self.v, self.f, verbose, joincomp, remove_smallest_components
)

(Actually, I see this is the exact same problem that @adeak has already pinpointed more precisely.)

@adeak
Copy link
Member

adeak commented Apr 9, 2023

For what it's worth, I get this error nondeterministically.

Unfortunately segfaults inherently have a tendency to be nondeterministic. The reason for a segfault is that the process tries to access (actually, write to) memory that doesn't belong to it. When you have a minor off-by-few indexing issue you might end up addressing memory that is out of bounds for the given object (say, an array), but still within the memory allocated to your process. In this situation you can normally change the value at the corresponding memory address, so instead of a segfault you get silently corrupted state for your program (something somewhere changed accidentally). But when the referenced memory address is so far from the intended place (or when the constellation of memory allocation in a modern operating system is such) that it doesn't belong to the same process, you get the segfault.

@MarioAuditore
Copy link

MarioAuditore commented Apr 10, 2023

Hello again. I managed to avoid this problem by using pyvista like this:

    pv_mesh = pv.wrap(model.get_mesh())
    pv_mesh.save('pyvista_mesh.ply')

    tin = PyTMesh(False)

    tin.load_file('pyvista_mesh.ply')
    tin.fill_small_boundaries(nbe=nbe, refine=refine)

P.S.
model.get_mesh() is my class, which returns trimesh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants