Просмотр исходного кода

First write (untested) of paint_connect.

jpcaram 11 лет назад
Родитель
Сommit
9632d9a98f
1 измененных файлов с 115 добавлено и 52 удалено
  1. 115 52
      camlib.py

+ 115 - 52
camlib.py

@@ -141,6 +141,36 @@ class Geometry(object):
         else:
             return self.solid_geometry.bounds
 
+    def find_polygon(self, point, geoset=None):
+        """
+        Find an object that object.contains(Point(point)) in
+        poly, which can can be iterable, contain iterable of, or
+        be itself an implementer of .contains().
+
+        :param poly: See description
+        :return: Polygon containing point or None.
+        """
+
+        if geoset is None:
+            geoset = self.solid_geometry
+
+        try:  # Iterable
+            for sub_geo in geoset:
+                p = self.find_polygon(point, geoset=sub_geo)
+                if p is not None:
+                    return p
+
+        except TypeError:  # Non-iterable
+
+            try:  # Implements .contains()
+                if geoset.contains(Point(point)):
+                    return geoset
+
+            except AttributeError:  # Does not implement .contains()
+                return None
+
+        return None
+
     def flatten(self, geometry=None, reset=True, pathonly=False):
         """
         Creates a list of non-iterable linear geometry objects.
@@ -178,26 +208,26 @@ class Geometry(object):
 
         return self.flat_geometry
 
-    def make2Dstorage(self):
-
-        self.flatten()
-
-        def get_pts(o):
-            pts = []
-            if type(o) == Polygon:
-                g = o.exterior
-                pts += list(g.coords)
-                for i in o.interiors:
-                    pts += list(i.coords)
-            else:
-                pts += list(o.coords)
-            return pts
-
-        storage = FlatCAMRTreeStorage()
-        storage.get_points = get_pts
-        for shape in self.flat_geometry:
-            storage.insert(shape)
-        return storage
+    # def make2Dstorage(self):
+    #
+    #     self.flatten()
+    #
+    #     def get_pts(o):
+    #         pts = []
+    #         if type(o) == Polygon:
+    #             g = o.exterior
+    #             pts += list(g.coords)
+    #             for i in o.interiors:
+    #                 pts += list(i.coords)
+    #         else:
+    #             pts += list(o.coords)
+    #         return pts
+    #
+    #     storage = FlatCAMRTreeStorage()
+    #     storage.get_points = get_pts
+    #     for shape in self.flat_geometry:
+    #         storage.insert(shape)
+    #     return storage
 
     # def flatten_to_paths(self, geometry=None, reset=True):
     #     """
@@ -298,9 +328,9 @@ class Geometry(object):
         :param overlap: Overlap of toolpasses.
         :return:
         """
-        poly_cuts = [polygon.buffer(-tooldia/2.0)]
+        poly_cuts = [polygon.buffer(-tooldia / 2.0)]
         while True:
-            polygon = poly_cuts[-1].buffer(-tooldia*(1-overlap))
+            polygon = poly_cuts[-1].buffer(-tooldia * (1 - overlap))
             if polygon.area > 0:
                 poly_cuts.append(polygon)
             else:
@@ -388,6 +418,69 @@ class Geometry(object):
         """
         return
 
+    def paint_connect(self, geolist, boundary, tooldia):
+        """
+        Connects paths that results in a connection segment that is
+        within the paint area. This avoids unnecessary tool lifting.
+
+        :return:
+        """
+
+        # Assuming geolist is a flat list of flat elements
+
+        ## Index first and last points in paths
+        def get_pts(o):
+            return [o.coords[0], o.coords[-1]]
+
+        storage = FlatCAMRTreeStorage()
+        storage.get_points = get_pts
+
+        for shape in geolist:
+            if shape is not None:  # TODO: This shouldn't have happened.
+                storage.insert(shape)
+
+        ## Iterate over geometry paths getting the nearest each time.
+        optimized_paths = []
+        temp_path = None
+        path_count = 0
+        current_pt = (0, 0)
+        pt, geo = storage.nearest(current_pt)
+        try:
+            while True:
+                path_count += 1
+
+                # Remove before modifying, otherwise
+                # deletion will fail.
+                storage.remove(geo)
+
+                # If last point in geometry is the nearest
+                # then reverse coordinates.
+                if list(pt) == list(geo.coords[-1]):
+                    geo.coords = list(geo.coords)[::-1]
+
+                # Straight line from current_pt to pt.
+                # Is the toolpath inside the geometry?
+                jump = LineString([current_pt, pt]).buffer(tooldia / 2)
+                if jump.within(boundary):
+                    # Completely inside. Append...
+                    if temp_path is None:
+                        temp_path = geo
+                    else:
+                        temp_path.coords = list(temp_path.coords) + list(geo.coords)
+                else:
+                    # Have to lift tool. End path.
+                    optimized_paths.append(temp_path)
+                    temp_path = geo
+
+                current_pt = geo.coords[-1]
+
+                # Next
+                pt, geo = storage.nearest(current_pt)
+
+        except StopIteration:  # Nothing found in storage.
+            if not temp_path.equals(optimized_paths[-1]):
+                optimized_paths.append(temp_path)
+
     def path_connect(self):
         """
         Simplifies a list of paths by joining those whose ends touch.
@@ -533,36 +626,6 @@ class Geometry(object):
         """
         self.solid_geometry = [cascaded_union(self.solid_geometry)]
 
-    def find_polygon(self, point, geoset=None):
-        """
-        Find an object that object.contains(Point(point)) in
-        poly, which can can be iterable, contain iterable of, or
-        be itself an implementer of .contains().
-
-        :param poly: See description
-        :return: Polygon containing point or None.
-        """
-
-        if geoset is None:
-            geoset = self.solid_geometry
-
-        try:  # Iterable
-            for sub_geo in geoset:
-                p = self.find_polygon(point, geoset=sub_geo)
-                if p is not None:
-                    return p
-
-        except TypeError:  # Non-iterable
-
-            try:  # Implements .contains()
-                if geoset.contains(Point(point)):
-                    return geoset
-
-            except AttributeError:  # Does not implement .contains()
-                return None
-
-        return None
-
 
 class ApertureMacro:
     """