jimy-byerley / pymadcad

Simple yet powerful CAD (Computer Aided Design) library, written with Python.
https://madcad.netlify.app/
GNU Lesser General Public License v3.0
208 stars 16 forks source link

Triangulation Error on madcad.union() #41

Closed Yarkane closed 2 years ago

Yarkane commented 2 years ago

Hello to Jimy and the community, thank you for the hard work !

For a project, we need to compute the union of n Meshes. The user can select 2 meshes or more and we need to "merge" them in only one Mesh. These meshes are imported via an STL file. We use madcad.read() to import them in the scene :

def load_stl(self, filename):
        _mesh_stl = madcad.read(filename)
        _mesh_stl.mergeclose()
[...]

We are then using the function madcad.union() to achieve this fusion, in this way :

def merge_meshes(a_key, b_key):
        self.shapes3d[a_key].finish()
        self.shapes3d[b_key].finish()
        _union = madcad.union(
            self.shapes3d[a_key],
            self.shapes3d[b_key])
        _union.finish()

In some cases, it does work pretty well : when the shapes are simple especially. It is, for example, easy to compute these unions of meshes to achieve this "complex" mesh : image For this mesh, we used a tube and a sphere.

But now let's use a slightly more complex shape to replace the sphere. image When trying to compute the fusion with a tube... (Moving the new shape to have an intersection, unless it simply doesn't work) image We get an error :

Traceback (most recent call last):
  File "c:\Users\yarkane\source\repos\project\model\view_3d.py", line 324, in merge_list_meshes
    _union_key = self.merge_meshes(_union_key, _key_b, keep_other_items)
  File "c:\Users\yarkane\source\repos\project\model\view_3d.py", line 294, in merge_meshes
    _union = madcad.union(
  File "C:\Users\yarkane\source\repos\project\lib\site-packages\madcad\boolean.py", line 608, in union
    return boolean(a,b, (False,False))
  File "C:\Users\yarkane\source\repos\project\lib\site-packages\madcad\boolean.py", line 602, in boolean
    return op(a, b, sides, prec)
  File "C:\Users\yarkane\source\repos\project\lib\site-packages\madcad\boolean.py", line 248, in boolean_mesh
    mc2 = pierce_mesh(m2, m1, selector[1], prec)
  File "C:\Users\yarkane\source\repos\project\lib\site-packages\madcad\boolean.py", line 164, in pierce_mesh
    m1, frontier = cut_mesh(m1, m2, prec)
  File "C:\Users\yarkane\source\repos\project\lib\site-packages\madcad\boolean.py", line 145, in cut_mesh
    flat = triangulation.triangulation_closest(segts, normal)
  File "C:\Users\yarkane\source\repos\project\lib\site-packages\madcad\triangulation.py", line 814, in triangulation_closest
    result += triangulation_outline(loop, z)
  File "C:\Users\yarkane\source\repos\project\lib\site-packages\madcad\triangulation.py", line 289, in triangulation_outline
    raise TriangulationError("no more feasible triangles (algorithm failure or bad input outline)", [outline.indices[i] for i in hole])
madcad.triangulation.TriangulationError: ('no more feasible triangles (algorithm failure or bad input outline)', [109, 87, 100])

I guess this is because boolean operations are very sensible, and the meshes too complex. Is there at least a way to "simplify" the mesh ? For example, we also got TriangulationErrors when trying to extrude from polygons that were quite "complex", and we managed to fix the issue by calling an opencv function to "smooth" the polygon. Maybe there is a way for this 3D operation to smooth the meshes ?

Anyway, we will continue to dig on this topic. Thanks for the hard work and all the help you could give ! :)

jimy-byerley commented 2 years ago

Hello @Yarkane and welcome there !

What version of pymadcad are you working with ? (there was a bug remaning in the boolean operations before v0.12) Could you send me the mesh files causing the error, so I can investigate on my side ?

Also did you already tries the slight shift trick ? performing the boolean operation after translating one of the meshes from almost nothing (that's a good trick to check if the probleme comes from an intersection/numeric-precision issue) like this:

madcad.union( a, b.transform(vec3(1e-4)) )   # the current translation direction could be tuned, and its length also in term of the mesh size

I was recently notified by a friend that there is still a bug occuring in those boolean operations even after v0.12, so this could be the same cause here ;)

jimy-byerley commented 2 years ago

Looks like it works quite well on my side, but I'm generating the parts using pymadcad, not importing them ... so I might not have the same placements, dimensions and mesh triangulations ...

p3 = difference(
    icosphere(O, 1),
    union(cylinder(-2*X, 2*X, 0.6), cylinder(-2*Z, 2*Z, 0.6)),
    )

p4 = union(p3, cylinder(-2*X-0.6*Z, 2*X-0.6*Z, 0.7))

image

Yarkane commented 2 years ago

Hi there ! Thank you for your quick answer !

I can't give you stl files right now, but I know that we may usse pymadcad v0.11 . I'll keep you in touch, thanks for your help !

Yarkane commented 2 years ago

Hi there, sorry for the long week between the two messages.

The project was using pymadcad 0.11. Updating it to 0.12 resolved a lot of issues including the one I presented as an example that works well now.

We still have problems when faces are overlapping but as I see on the github, this is a common issue and for now we will have to deal with small translations tricks. We're going to work on it but I hope you will find a way to solve this issue too !

Thanks for your help :) Have a good day !

jimy-byerley commented 2 years ago

Nice it solved it, good luck for your project !

jimy-byerley commented 2 years ago

Also don't hesitate to come back if you have new bugs ;)