Browse Source

Fix segfault when arranging without any disallowed areas

So libnest2d is giving a segfault when it's being triggered without any disallowed areas. This is because we then give a single disallowed area for the border around the build plate, and give this disallowed area 0 vertices. Because libnest2d doesn't do defensive coding here, it's going to crash, taking Cura along with it. The crash is in libnest2d's function 'libnest2d::_Item<ClipperLib::Polygon>::rightmostTopVertex()'.

This segfault started happening recently in Cura. However it only happens when there are no disallowed areas. Steps to reproduce the error are:
- Use Custom FFF Printer.
- Set the Adhesion Type setting to 'None'.
- Load any two models.

I tracked the segfault down to this commit: https://github.com/Ultimaker/Uranium/pull/684/commits/74ddbaab4bb4737367ad2f82698ee7422305a047 . That commit by itself is slightly mysterious but looks fine to me. It did give the hint that this segfault might be caused by empty polygons though. So for that reason, I figured that filtering out the empty polygons here in the arranger might fix it; and indeed it does. Passing empty polygons as fixed/disallowed areas is useless and invalid anyway. Apparently libnest2d doesn't deal well with it, but we might as well not send those polygons over then.
Ghostkeeper 3 years ago
parent
commit
9dba4d554f
1 changed files with 2 additions and 2 deletions
  1. 2 2
      cura/Arranging/Nest2DArrange.py

+ 2 - 2
cura/Arranging/Nest2DArrange.py

@@ -75,7 +75,7 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV
         # Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise)
         clipped_area = area.intersectionConvexHulls(build_plate_polygon)
 
-        if clipped_area.getPoints() is not None:  # numpy array has to be explicitly checked against None
+        if clipped_area.getPoints() is not None and len(clipped_area.getPoints()) > 2:  # numpy array has to be explicitly checked against None
             for point in clipped_area.getPoints():
                 converted_points.append(Point(int(point[0] * factor), int(point[1] * factor)))
 
@@ -88,7 +88,7 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV
         converted_points = []
         hull_polygon = node.callDecoration("getConvexHull")
 
-        if hull_polygon is not None and hull_polygon.getPoints() is not None:  # numpy array has to be explicitly checked against None
+        if hull_polygon is not None and hull_polygon.getPoints() is not None and len(hull_polygon.getPoints()) > 2:  # numpy array has to be explicitly checked against None
             for point in hull_polygon.getPoints():
                 converted_points.append(Point(point[0] * factor, point[1] * factor))
             item = Item(converted_points)