diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 96ce05c4..1400727b 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -1308,14 +1308,18 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): #assert isinstance(app_obj, App) if self.options["paintmethod"] == "seed": + # Type(cp) == FlatCAMRTreeStorage | None cp = self.clear_polygon2(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap) else: + # Type(cp) == FlatCAMRTreeStorage | None cp = self.clear_polygon(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap) - geo_obj.solid_geometry = list(cp.get_objects()) + if cp is not None: + geo_obj.solid_geometry = list(cp.get_objects()) + geo_obj.options["cnctooldia"] = tooldia # Experimental... @@ -1347,6 +1351,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): name = outname or self.options["name"] + "_paint" + # This is a recursive generator of individual Polygons. + # Note: Double check correct implementation. Might exit + # early if it finds something that is not a Polygon? def recurse(geo): try: for subg in geo: @@ -1368,14 +1375,17 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): for poly in recurse(self.solid_geometry): if self.options["paintmethod"] == "seed": + # Type(cp) == FlatCAMRTreeStorage | None cp = self.clear_polygon2(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap) else: + # Type(cp) == FlatCAMRTreeStorage | None cp = self.clear_polygon(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap) - geo_obj.solid_geometry += list(cp.get_objects()) + if cp is not None: + geo_obj.solid_geometry += list(cp.get_objects()) geo_obj.options["cnctooldia"] = tooldia @@ -1391,6 +1401,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): app_obj.new_object("geometry", name, gen_paintarea) except Exception as e: proc.done() + traceback.print_stack() raise e proc.done() diff --git a/camlib.py b/camlib.py index 86186c30..40586260 100644 --- a/camlib.py +++ b/camlib.py @@ -501,7 +501,12 @@ class Geometry(object): geoms.get_points = get_pts # Can only result in a Polygon or MultiPolygon + # NOTE: The resulting polygon can be "empty". current = polygon.buffer(-tooldia / 2.0) + if current.area == 0: + # Otherwise, trying to to insert current.exterior == None + # into the FlatCAMStorage will fail. + return None # current can be a MultiPolygon try: @@ -559,6 +564,7 @@ class Geometry(object): :param seedpoint: Shapely.geometry.Point or None :param overlap: Tool fraction overlap bewteen passes :return: List of toolpaths covering polygon. + :rtype: FlatCAMRTreeStorage | None """ log.debug("camlib.clear_polygon2()") @@ -652,6 +658,8 @@ class Geometry(object): :type storage: FlatCAMRTreeStorage :param boundary: Polygon defining the limits of the paintable area. :type boundary: Polygon + :param tooldia: Tool diameter. + :rtype tooldia: float :param max_walk: Maximum allowable distance without lifting tool. :type max_walk: float or None :return: Optimized geometry. @@ -744,6 +752,8 @@ class Geometry(object): Simplifies paths in the FlatCAMRTreeStorage storage by connecting paths that touch on their enpoints. + :param storage: Storage containing the initial paths. + :rtype storage: FlatCAMRTreeStorage :return: Simplified storage. :rtype: FlatCAMRTreeStorage """