From c3c37d1473e14b4ab98af116d2a197f234825ffb Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Tue, 30 Apr 2019 03:29:46 +0300 Subject: [PATCH] - finished the Silkscreen Tool --- README.md | 3 +- camlib.py | 4 +- flatcamTools/ToolSilk.py | 116 ++++++++++++--------------------------- 3 files changed, 38 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index dba3c45f..54456f87 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,10 @@ CAD program, and create G-Code for Isolation routing. 29.04.2019 -- soled bug in Gerber Editor: the '0' aperture (the region aperture) had no size which created errors. Made the size to be zero. +- solved bug in Gerber Editor: the '0' aperture (the region aperture) had no size which created errors. Made the size to be zero. - solved bug in editors: the canvas selection shape was not deleted on mouse release if the grid snap was OFF - solved bug in Excellon Editor: when selecting a drill hole on canvas the selected row in the Tools Table was not the correct onw but the next highest row +- finished the Silkscreen Tool 26.04.2019 diff --git a/camlib.py b/camlib.py index 523311e2..66118866 100644 --- a/camlib.py +++ b/camlib.py @@ -2461,7 +2461,7 @@ class Gerber (Geometry): match = self.tool_re.search(gline) if match: current_aperture = match.group(1) - log.debug("Line %d: Aperture change to (%s)" % (line_num, current_aperture)) + # log.debug("Line %d: Aperture change to (%s)" % (line_num, current_aperture)) # If the aperture value is zero then make it something quite small but with a non-zero value # so it can be processed by FlatCAM. @@ -2470,7 +2470,7 @@ class Gerber (Geometry): if self.apertures[current_aperture]["type"] is not "AM": if self.apertures[current_aperture]["size"] == 0: self.apertures[current_aperture]["size"] = 1e-12 - log.debug(self.apertures[current_aperture]) + # log.debug(self.apertures[current_aperture]) # Take care of the current path with the previous tool if len(path) > 1: diff --git a/flatcamTools/ToolSilk.py b/flatcamTools/ToolSilk.py index 50d21378..ee055b5a 100644 --- a/flatcamTools/ToolSilk.py +++ b/flatcamTools/ToolSilk.py @@ -14,7 +14,6 @@ import time import gettext import FlatCAMTranslation as fcTranslate -from shapely.geometry import base import builtins fcTranslate.apply_language('strings') @@ -64,7 +63,6 @@ class ToolSilk(FlatCAMTool): _("Silkscreen Gerber object to be adjusted\n" "so it does not intersects the soldermask.") ) - e_lab_0 = QtWidgets.QLabel('') form_layout.addRow(self.silk_object_label, self.silk_object_combo) @@ -151,6 +149,11 @@ class ToolSilk(FlatCAMTool): self.tools_frame.show() def on_intersection_click(self): + # reset previous values + self.new_apertures.clear() + self.new_solid_geometry = [] + self.solder_union = [] + self.silk_obj_name = self.silk_object_combo.currentText() # Get source object. try: @@ -159,7 +162,7 @@ class ToolSilk(FlatCAMTool): self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve object: %s") % self.obj_name) return "Could not retrieve object: %s" % self.silk_obj_name - self.sm_obj_name = self.silk_object_combo.currentText() + self.sm_obj_name = self.sm_object_combo.currentText() # Get source object. try: self.sm_obj = self.app.collection.get_by_name(self.sm_obj_name) @@ -174,42 +177,41 @@ class ToolSilk(FlatCAMTool): self.new_apertures[apid]['size'] = self.silk_obj.apertures[apid]['size'] self.new_apertures[apid]['solid_geometry'] = [] - # geo_union_list = [] - # for apid1 in self.sm_obj.apertures: - # geo_union_list += self.sm_obj.apertures[apid1]['solid_geometry'] - # self.solder_union = cascaded_union(geo_union_list) + geo_union_list = [] + for apid1 in self.sm_obj.apertures: + geo_union_list += self.sm_obj.apertures[apid1]['solid_geometry'] + self.solder_union = cascaded_union(geo_union_list) # start the QTimer with 1 second period check - self.periodic_check(1000) + self.periodic_check(1000, reset=True) for apid in self.silk_obj.apertures: - ap_size = self.silk_obj.apertures[apid]['size'] geo = self.silk_obj.apertures[apid]['solid_geometry'] + while apid not in self.promises: + self.promises.append(apid) self.app.worker_task.emit({'fcn': self.aperture_intersection, 'params': [apid, geo]}) def aperture_intersection(self, apid, geo): - self.promises.append(apid) new_solid_geometry = [] with self.app.proc_container.new(_("Parsing aperture %s geometry ..." % str(apid))): for geo_silk in geo: - for ap in self.sm_obj.apertures: - for solder_poly in self.sm_obj.apertures[ap]['solid_geometry']: - if geo_silk.intersects(solder_poly): - - new_geo = self.subtract_polygon(geo_silk, solder_poly.exterior) - - if not new_geo.is_empty: - new_solid_geometry.append(new_geo) + if geo_silk.intersects(self.solder_union): + new_geo = geo_silk.difference(self.solder_union) + if new_geo: + if not new_geo.is_empty: + new_solid_geometry.append(new_geo) else: - new_solid_geometry.append(geo) + new_solid_geometry.append(geo_silk) + else: + new_solid_geometry.append(geo_silk) + else: + new_solid_geometry.append(geo_silk) if new_solid_geometry: - while True: - if self.new_apertures[apid]['solid_geometry']: - break - self.new_apertures[apid]['solid_geometry'] = new_solid_geometry + while not self.new_apertures[apid]['solid_geometry']: + self.new_apertures[apid]['solid_geometry'] = deepcopy(new_solid_geometry) time.sleep(0.5) while True: @@ -217,65 +219,12 @@ class ToolSilk(FlatCAMTool): # so we keep trying until it's done if apid not in self.promises: break + self.promises.remove(apid) time.sleep(0.5) log.debug("Promise fulfilled: %s" % str(apid)) - def subtract_polygon(self, silk_geo, sm_exterior): - """ - Subtract polygon from the given object. This only operates on the paths in the original geometry, i.e. - it converts polygons into paths. - - :param silk_geo: The geometry from which to substract. - :param sm_exterior: The substractor geometry - :return: none - """ - - geo = cascaded_union(silk_geo) - diff_geo = geo.difference(sm_exterior) - return diff_geo - - def flatten(self, geometry=None, reset=True, pathonly=False): - """ - Creates a list of non-iterable linear geometry objects. - Polygons are expanded into its exterior and interiors if specified. - - Results are placed in self.flat_geometry - - :param geometry: Shapely type or list or list of list of such. - :param reset: Clears the contents of self.flat_geometry. - :param pathonly: Expands polygons into linear elements. - """ - - if geometry is None: - log.debug("ToolSilk.flatten() --> There is no Geometry to flatten") - return - - if reset: - self.flat_geometry = [] - - # If iterable, expand recursively. - try: - for geo in geometry: - if geo is not None: - self.flatten(geometry=geo, - reset=False, - pathonly=pathonly) - - # Not iterable, do the actual indexing and add. - except TypeError: - if pathonly and type(geometry) == Polygon: - self.flat_geometry.append(geometry.exterior) - self.flatten(geometry=geometry.interiors, - reset=False, - pathonly=True) - else: - self.flat_geometry.append(geometry) - - log.debug("%d paths" % len(self.flat_geometry)) - return self.flat_geometry - def periodic_check(self, check_period, reset=False): """ This function starts an QTimer and it will periodically check if intersections are done @@ -330,11 +279,10 @@ class ToolSilk(FlatCAMTool): poly_buff = [] for ap in self.new_apertures: - for k in self.new_apertures[ap]: - if k == 'solid_geometry': - poly_buff += self.new_apertures[ap][k] + for poly in self.new_apertures[ap]['solid_geometry']: + poly_buff.append(poly) - poly_buff = unary_union(poly_buff) + poly_buff = MultiPolygon(poly_buff) try: poly_buff = poly_buff.buffer(0.0000001) except ValueError: @@ -345,7 +293,6 @@ class ToolSilk(FlatCAMTool): pass grb_obj.solid_geometry = deepcopy(poly_buff) - # self.new_apertures.clear() with self.app.proc_container.new(_("Generating cleaned SS object ...")): ret = self.app.new_object('gerber', outname, obj_init, autoselected=False) @@ -357,6 +304,11 @@ class ToolSilk(FlatCAMTool): # GUI feedback self.app.inform.emit(_("[success] Created: %s") % outname) + # cleanup + self.new_apertures.clear() + self.new_solid_geometry[:] = [] + self.solder_union[:] = [] + def reset_fields(self): self.silk_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex())) self.sm_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))