From 9632d9a98f9eacd34436e449cba69b866b336ee9 Mon Sep 17 00:00:00 2001 From: jpcaram Date: Thu, 22 Jan 2015 21:23:10 -0500 Subject: [PATCH] First write (untested) of paint_connect. --- camlib.py | 167 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 115 insertions(+), 52 deletions(-) diff --git a/camlib.py b/camlib.py index 2fb32b20..5971a68e 100644 --- a/camlib.py +++ b/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: """