From 0b26a901751466fac739818b9a52d0c23ebca87b Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Thu, 27 Oct 2016 16:57:36 -0400 Subject: [PATCH] Support for parallel-line painting. --- FlatCAMObj.py | 9 +++++++ ObjectUI.py | 3 ++- camlib.py | 71 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 62503110..3746bf51 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -1312,6 +1312,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): cp = self.clear_polygon2(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap) + elif self.options["paintmethod"] == "lines": + # Type(cp) == FlatCAMRTreeStorage | None + cp = self.clear_polygon3(poly.buffer(-self.options["paintmargin"]), + tooldia, overlap=overlap) else: # Type(cp) == FlatCAMRTreeStorage | None cp = self.clear_polygon(poly.buffer(-self.options["paintmargin"]), @@ -1387,6 +1391,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): cp = self.clear_polygon2(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap) + elif self.options["paintmethod"] == "lines": + # Type(cp) == FlatCAMRTreeStorage | None + cp = self.clear_polygon3(poly.buffer(-self.options["paintmargin"]), + tooldia, overlap=overlap) + else: # Type(cp) == FlatCAMRTreeStorage | None cp = self.clear_polygon(poly.buffer(-self.options["paintmargin"]), diff --git a/ObjectUI.py b/ObjectUI.py index 7e3d341d..08214032 100644 --- a/ObjectUI.py +++ b/ObjectUI.py @@ -393,7 +393,8 @@ class GeometryObjectUI(ObjectUI): grid2.addWidget(methodlabel, 3, 0) self.paintmethod_combo = RadioSet([ {"label": "Standard", "value": "standard"}, - {"label": "Seed-based", "value": "seed"} + {"label": "Seed-based", "value": "seed"}, + {"label": "Straight lines", "value": "lines"} ]) grid2.addWidget(self.paintmethod_combo, 3, 1) diff --git a/camlib.py b/camlib.py index de0ab3a4..b6e69a29 100644 --- a/camlib.py +++ b/camlib.py @@ -31,7 +31,7 @@ from rtree import index as rtindex from shapely.geometry import Polygon, LineString, Point, LinearRing from shapely.geometry import MultiPoint, MultiPolygon from shapely.geometry import box as shply_box -from shapely.ops import cascaded_union +from shapely.ops import cascaded_union, unary_union import shapely.affinity as affinity from shapely.wkt import loads as sloads from shapely.wkt import dumps as sdumps @@ -627,6 +627,72 @@ class Geometry(object): return geoms + @staticmethod + def clear_polygon3(polygon, tooldia, overlap=0.15, connect=True): + """ + Creates geometry inside a polygon for a tool to cover + the whole area. + + This algorithm draws horizontal lines inside the polygon. + + :param polygon: The polygon being painted. + :type polygon: shapely.geometry.Polygon + :param tooldia: Tool diameter. + :param overlap: Tool path overlap percentage. + :param connect: Connect lines to avoid tool lifts. + :return: + """ + + log.debug("camlib.clear_polygon3()") + + ## The toolpaths + # Index first and last points in paths + def get_pts(o): + return [o.coords[0], o.coords[-1]] + + geoms = FlatCAMRTreeStorage() + geoms.get_points = get_pts + + lines = [] + + # Bounding box + left, bot, right, top = polygon.bounds + + # First line + y = top - tooldia / 2 + while y > bot + tooldia / 2: + line = LineString([(left, y), (right, y)]) + lines.append(line) + y -= tooldia * (1 - overlap) + + # Last line + y = bot + tooldia / 2 + line = LineString([(left, y), (right, y)]) + lines.append(line) + + # Combine + linesgeo = unary_union(lines) + + # Trim to the polygon + margin_poly = polygon.buffer(-tooldia / 2) + lines_trimmed = linesgeo.intersection(margin_poly) + + # Add lines to storage + for line in lines_trimmed: + geoms.insert(line) + + # Add margin to storage + # geoms.insert(margin_poly.exterior) + # for ints in margin_poly.interiors: + # geoms.insert(ints) + + # Optimization: Reduce lifts + if connect: + log.debug("Reducing tool lifts...") + geoms = Geometry.paint_connect(geoms, polygon, tooldia) + + return geoms + def scale(self, factor): """ Scales all of the object's geometry by a given factor. Override @@ -967,10 +1033,11 @@ class Geometry(object): new_obj.append(mirror_geom(g)) return new_obj else: - return affinity.scale(obj,xscale,yscale,origin=(px,py)) + return affinity.scale(obj, xscale, yscale, origin=(px,py)) self.solid_geometry = mirror_geom(self.solid_geometry) + class ApertureMacro: """ Syntax of aperture macros.