orbingol / NURBS-Python

Object-oriented pure Python B-Spline and NURBS library
https://onurraufbingol.com/NURBS-Python/
MIT License
637 stars 156 forks source link

Problem with tesselation when using periodic surfaces #128

Open LorenzSLH opened 3 years ago

LorenzSLH commented 3 years ago

Dear Bingol, i would like to know if you have any idea on how to solve that issue. For one part of my project, I am using your libary to create an airfoil. As it is a closed (periodic) NURB curve, i have set according to the course of the MTU, the knotvector and the control points. Which perfectly works and i get a closed curve.

My problem is now that when extruding the surface in z-direction (in v direction i have the closed NURB curve of degree 3, and in the u-direction i have a degree 1 curve - linear). Therefore the curves v[0] and v[1] only differ by an offset in the z-direction. When trying to export it now as a .stl file, i have an issue with the faces it creates. I checked already the evaluation points if there are any double points but that algorithm of yours seem to work fine. Also when plotting it with VisMPL.VisSurfWireframe it looks fine. However when plotting it with VisMPL.VisSurface i have the same error as with the stl file. Wrong faces in the area of the double ctrlpts. So my guess there is an issue with the tesselation when the surface is closed. Picture of failed faces: failedFaces

Do you have any ideas on that? Would be great help. I will attach you a json file of the curve i am using as well as the surface. airfoilHull.zip

With best regards, Lorenz

orbingol commented 3 years ago

Tessellation included in geomdl is not perfect and it might have some issues. 'VisSurface' classes use the tessellator assigned to the Surface class. However, VisSurfaceWireframe is a wrapper for the matplotlib function. It is always possible to extend the tessellator class with another one, and all exporters and visualizers will use the new tessellator.

For the default tessellator, I'd try a smaller/larger delta or reducing/increasing the vertex spacing in the tessellation function.

LorenzSLH commented 3 years ago

After running your tessellation with the debugger, i think i found the problem and maybe you have a smart idea to give it a work around: The curve in the parameterized space is running from 0 to 1. When wrapping around the ctrlpts (e.g. a 3rd degree curve needs three double ctrlpts) the curve overlays at some points. Therefore some parts of the curve lay over each other. Could the tesselation process created vertices and therefore faces at not the exact spot?

I guess the best idea to overcome that issue (if i am right), would be to tell the tell the tesselation process to stop when reaching the beginning of the curve and not run till the end of the curve? I was thinking of trimming the curve exactly at that point before creating the surface, but i do not know if it doesn't loose its periodic property and therfore its shape. Is there any function that would return the u-value of a specific point on the curve?

with best regards Lorenz

orbingol commented 3 years ago

Could the tesselation process created vertices and therefore faces at not the exact spot?

I couldn't understand this question. Would you please elaborate a bit? Also, the triangles in your screenshot are very big. Could you try a smaller delta to see if it fixes the issue?

would be to tell the tell the tesselation process to stop when reaching the beginning of the curve and not run till the end of the curve?

TrimTesselate class is doing this but only for trimmed surfaces. As you suggested it might be fixed by adding trims to the surface.

LorenzSLH commented 3 years ago

I couldn't understand this question. Would you please elaborate a bit? Also, the triangles in your screenshot are very big. Could you try a smaller delta to see if it fixes the issue?

sorry for the unclear formulation on that issue. If i understand your code right the vertices for the triangulation are formed from the evaluation points (in u and v direction). By numbering them, making squares and then split them into two triangles. The evaluation points look perfectly fine, but somehow the creation of the vertices seem to fail for closed curves. You find three images appended, hoping they highlight the problem evalpts failedFaces vertices

TrimTesselate class is doing this but only for trimmed surfaces. As you suggested it might be fixed by adding trims to the surface.

Is there an exact way to extract that point at which i must insert a trim? Or would you suggest to iterate with a varying "u" until i find the point in an acceptable tolerance?

EDIT:

I can't really explain why, but i think the error in the [u,v] coordinates of the vertices. By theory the evaluation_single() should return the exact position of the evaluation point that was used for the vertices. Maybe it is numerial inaccuary, but when executing the method, the points (vertices.data from evalpts and pt = evaluation_single(vertices.uv) do not match. Therefore i turned off the code section in abstract.py :: def tessellate( )

# Re-evaluate vertex coordinates
        """
        for idx in range(len(self._tsl_component.vertices)):
            uv = self._tsl_component.vertices[idx].uv
            if self._kv_normalize and not utilities.check_params(uv):
                continue
            self._tsl_component.vertices[idx].data = self.evaluate_single(uv)
        """

Not sure if there any other side effects by doing so, but at least i suppress the reevaluation of the vertices and i get a goodlooking .stl file exported :)

orbingol commented 3 years ago

@LorenzSLH thank you so much for the detailed explanation. I appreciate it. I also would like to thank you for pinpointing the issue and the solution. I am glad you solved it and also posting the solution is very much appreciated. I really appreciate your efforts and time.

I'll try my best to figure out if it is some kind of floating-point error or a bug in the algorithm implementation. I have tested the algorithm implementation extensively with many examples throughout the years but it is always good to take a look at it again. It could be something very similar to the issue on #118.

I am going to leave this issue open for now. I have been planning to move to decimal.Decimal to fix the numerical errors but it requires a lot of changes and time which I haven't been able to find for a while.