diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 85340c8a..8c764115 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -4798,13 +4798,17 @@ class App(QtCore.QObject): def convert_any2gerber(self): self.report_usage("convert_any2gerber()") - def initialize(obj_init, app): + def initialize_geometry(obj_init, app): apertures = {} apid = 0 apertures[str(apid)] = {} - apertures[str(apid)]['solid_geometry'] = [] - apertures[str(apid)]['solid_geometry'] = deepcopy(obj.solid_geometry) + apertures[str(apid)]['geometry'] = [] + for obj_orig in obj.solid_geometry: + new_elem = dict() + new_elem['solid'] = obj_orig + new_elem['follow'] = obj_orig.exterior + apertures[str(apid)]['geometry'].append(deepcopy(new_elem)) apertures[str(apid)]['size'] = 0.0 apertures[str(apid)]['type'] = 'C' @@ -4817,9 +4821,12 @@ class App(QtCore.QObject): apid = 10 for tool in obj.tools: apertures[str(apid)] = {} - apertures[str(apid)]['solid_geometry'] = [] + apertures[str(apid)]['geometry'] = [] for geo in obj.tools[tool]['solid_geometry']: - apertures[str(apid)]['solid_geometry'].append(geo) + new_el = dict() + new_el['solid'] = geo + new_el['follow'] = geo.exterior + apertures[str(apid)]['geometry'].append(deepcopy(new_el)) apertures[str(apid)]['size'] = float(obj.tools[tool]['C']) apertures[str(apid)]['type'] = 'C' @@ -4828,8 +4835,8 @@ class App(QtCore.QObject): # create solid_geometry solid_geometry = [] for apid in apertures: - for geo in apertures[apid]['solid_geometry']: - solid_geometry.append(geo) + for geo_el in apertures[apid]['geometry']: + solid_geometry.append(geo_el['solid']) solid_geometry = MultiPolygon(solid_geometry) solid_geometry = solid_geometry.buffer(0.0000001) @@ -4851,8 +4858,10 @@ class App(QtCore.QObject): try: if isinstance(obj, FlatCAMExcellon): self.new_object("gerber", str(obj_name) + "_conv", initialize_excellon) + elif isinstance(obj, FlatCAMGeometry): + self.new_object("gerber", str(obj_name) + "_conv", initialize_geometry) else: - self.new_object("gerber", str(obj_name) + "_conv", initialize) + log.warning("App.convert_any2gerber --> This is no vaild object for conversion.") except Exception as e: return "Operation failed: %s" % str(e) diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 68aad1d7..38cf1a52 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -17,9 +17,9 @@ import itertools import gettext import FlatCAMTranslation as fcTranslate +import builtins fcTranslate.apply_language('strings') -import builtins if '_' not in builtins.__dict__: _ = gettext.gettext @@ -35,9 +35,9 @@ class ValidationError(Exception): self.errors = errors -######################################## -## FlatCAMObj ## -######################################## +# ####################################### +# # FlatCAMObj ## +# ####################################### class FlatCAMObj(QtCore.QObject): @@ -122,7 +122,8 @@ class FlatCAMObj(QtCore.QObject): try: setattr(self, attr, d[attr]) except KeyError: - log.debug("FlatCAMObj.from_dict() --> KeyError: %s. Means that we are loading an old project that don't" + log.debug("FlatCAMObj.from_dict() --> KeyError: %s. " + "Means that we are loading an old project that don't" "have all attributes in the latest FlatCAM." % str(attr)) pass @@ -203,8 +204,8 @@ class FlatCAMObj(QtCore.QObject): self.app.report_usage("obj_on_offset_button") self.read_form() - vect = self.ui.offsetvector_entry.get_value() - self.offset(vect) + vector_val = self.ui.offsetvector_entry.get_value() + self.offset(vector_val) self.plot() self.app.object_changed.emit(self) @@ -219,9 +220,9 @@ class FlatCAMObj(QtCore.QObject): def on_skew_button_click(self): self.app.report_usage("obj_on_skew_button") self.read_form() - xangle = self.ui.xangle_entry.get_value() - yangle = self.ui.yangle_entry.get_value() - self.skew(xangle, yangle) + x_angle = self.ui.xangle_entry.get_value() + y_angle = self.ui.yangle_entry.get_value() + self.skew(x_angle, y_angle) self.plot() self.app.object_changed.emit(self) @@ -420,7 +421,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber): if option is not 'name': try: grb_final.options[option] = grb.options[option] - except: + except KeyError: log.warning("Failed to copy option.", option) try: @@ -440,10 +441,10 @@ class FlatCAMGerber(FlatCAMObj, Gerber): # and finally made string because the apertures dict keys are strings max_ap = str(max([int(k) for k in grb_final.apertures.keys()]) + 1) grb_final.apertures[max_ap] = {} - grb_final.apertures[max_ap]['solid_geometry'] = [] + grb_final.apertures[max_ap]['geometry'] = [] for k, v in grb.apertures[ap].items(): - grb_final.apertures[max_ap][k] = v + grb_final.apertures[max_ap][k] = deepcopy(v) grb_final.solid_geometry = MultiPolygon(grb_final.solid_geometry) grb_final.follow_geometry = MultiPolygon(grb_final.follow_geometry) diff --git a/README.md b/README.md index 2515e7f9..3cf467bf 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing. 18.05.2019 - added a new toggle option in Edit -> Preferences -> General Tab -> App Preferences -> "Open" Behavior. It controls which path is used when opening a new file. If checked the last saved path is used when saving files and the last opened path is used when opening files. If unchecked then the path for the last action (either open or save) is used. +- fixed App.convert_any2gerber to work with the new Gerber apertures data structure +- fixed Tool Sub to work with the new Gerber apertures data structure 17.05.2019 diff --git a/flatcamTools/ToolProperties.py b/flatcamTools/ToolProperties.py index 8eeb59ed..6b2ac1a8 100644 --- a/flatcamTools/ToolProperties.py +++ b/flatcamTools/ToolProperties.py @@ -189,7 +189,7 @@ class Properties(FlatCAMTool): if 'clear' in el: clear_nr += 1 temp_ap['Solid_Geo'] = '%s Polygons' % str(solid_nr) - temp_ap['Follow_Geo'] = '%s Polygons' % str(follow_nr) + temp_ap['Follow_Geo'] = '%s LineStrings' % str(follow_nr) temp_ap['Clear_Geo'] = '%s Polygons' % str(clear_nr) apid = self.addParent(apertures, str(ap), expanded=False, color=QtGui.QColor("#000000"), font=font) diff --git a/flatcamTools/ToolSub.py b/flatcamTools/ToolSub.py index 7f386722..5d8a40a2 100644 --- a/flatcamTools/ToolSub.py +++ b/flatcamTools/ToolSub.py @@ -151,7 +151,10 @@ class ToolSub(FlatCAMTool): self.new_tools = {} self.new_solid_geometry = [] - self.sub_union = None + self.sub_solid_union = None + self.sub_follow_union = None + self.sub_clear_union = None + self.sub_grb_obj = None self.sub_grb_obj_name = None @@ -251,12 +254,25 @@ class ToolSub(FlatCAMTool): self.new_apertures[apid] = {} self.new_apertures[apid]['type'] = 'C' self.new_apertures[apid]['size'] = self.target_grb_obj.apertures[apid]['size'] - self.new_apertures[apid]['solid_geometry'] = [] + self.new_apertures[apid]['geometry'] = [] + + geo_solid_union_list = [] + geo_follow_union_list = [] + geo_clear_union_list = [] - geo_union_list = [] for apid1 in self.sub_grb_obj.apertures: - geo_union_list += self.sub_grb_obj.apertures[apid1]['solid_geometry'] - self.sub_union = cascaded_union(geo_union_list) + if 'geometry' in self.sub_grb_obj.apertures[apid1]: + for elem in self.sub_grb_obj.apertures[apid1]['geometry']: + if 'solid' in elem: + geo_solid_union_list.append(elem['solid']) + if 'follow' in elem: + geo_follow_union_list.append(elem['follow']) + if 'clear' in elem: + geo_clear_union_list.append(elem['clear']) + + self.sub_solid_union = cascaded_union(geo_solid_union_list) + self.sub_follow_union = cascaded_union(geo_follow_union_list) + self.sub_clear_union = cascaded_union(geo_clear_union_list) # add the promises for apid in self.target_grb_obj.apertures: @@ -266,32 +282,78 @@ class ToolSub(FlatCAMTool): self.periodic_check(500, reset=True) for apid in self.target_grb_obj.apertures: - geo = self.target_grb_obj.apertures[apid]['solid_geometry'] + geo = self.target_grb_obj.apertures[apid]['geometry'] self.app.worker_task.emit({'fcn': self.aperture_intersection, 'params': [apid, geo]}) def aperture_intersection(self, apid, geo): - new_solid_geometry = [] + new_geometry = [] + log.debug("Working on promise: %s" % str(apid)) with self.app.proc_container.new(_("Parsing aperture %s geometry ..." % str(apid))): - for geo_silk in geo: - if geo_silk.intersects(self.sub_union): - new_geo = geo_silk.difference(self.sub_union) - new_geo = new_geo.buffer(0) - if new_geo: - if not new_geo.is_empty: - new_solid_geometry.append(new_geo) - else: - new_solid_geometry.append(geo_silk) - else: - new_solid_geometry.append(geo_silk) - else: - new_solid_geometry.append(geo_silk) + for geo_el in geo: + new_el = dict() - if new_solid_geometry: - while not self.new_apertures[apid]['solid_geometry']: - self.new_apertures[apid]['solid_geometry'] = deepcopy(new_solid_geometry) + if 'solid' in geo_el: + work_geo = geo_el['solid'] + if self.sub_solid_union: + if work_geo.intersects(self.sub_solid_union): + new_geo = work_geo.difference(self.sub_solid_union) + new_geo = new_geo.buffer(0) + if new_geo: + if not new_geo.is_empty: + new_el['solid'] = new_geo + else: + new_el['solid'] = work_geo + else: + new_el['solid'] = work_geo + else: + new_el['solid'] = work_geo + else: + new_el['solid'] = work_geo + + if 'follow' in geo_el: + work_geo = geo_el['follow'] + if self.sub_follow_union: + if work_geo.intersects(self.sub_follow_union): + new_geo = work_geo.difference(self.sub_follow_union) + new_geo = new_geo.buffer(0) + if new_geo: + if not new_geo.is_empty: + new_el['follow'] = new_geo + else: + new_el['follow'] = work_geo + else: + new_el['follow'] = work_geo + else: + new_el['follow'] = work_geo + else: + new_el['follow'] = work_geo + + if 'clear' in geo_el: + work_geo = geo_el['clear'] + if self.sub_clear_union: + if work_geo.intersects(self.sub_clear_union): + new_geo = work_geo.difference(self.sub_clear_union) + new_geo = new_geo.buffer(0) + if new_geo: + if not new_geo.is_empty: + new_el['clear'] = new_geo + else: + new_el['clear'] = work_geo + else: + new_el['clear'] = work_geo + else: + new_el['clear'] = work_geo + else: + new_el['clear'] = work_geo + + new_geometry.append(deepcopy(new_el)) + + if new_geometry: + while not self.new_apertures[apid]['geometry']: + self.new_apertures[apid]['geometry'] = deepcopy(new_geometry) time.sleep(0.5) while True: @@ -312,9 +374,11 @@ class ToolSub(FlatCAMTool): grb_obj.apertures = deepcopy(self.new_apertures) poly_buff = [] + follow_buff = [] for ap in self.new_apertures: - for poly in self.new_apertures[ap]['solid_geometry']: - poly_buff.append(poly) + for elem in self.new_apertures[ap]['geometry']: + poly_buff.append(elem['solid']) + follow_buff.append(elem['follow']) work_poly_buff = cascaded_union(poly_buff) try: @@ -327,14 +391,14 @@ class ToolSub(FlatCAMTool): pass grb_obj.solid_geometry = deepcopy(poly_buff) + grb_obj.follow_geometry = deepcopy(follow_buff) with self.app.proc_container.new(_("Generating new object ...")): ret = self.app.new_object('gerber', outname, obj_init, autoselected=False) if ret == 'fail': self.app.inform.emit(_('[ERROR_NOTCL] Generating new object failed.')) return - # Register recent file - self.app.file_opened.emit('gerber', outname) + # GUI feedback self.app.inform.emit(_("[success] Created: %s") % outname)