diff --git a/README.md b/README.md index 81cfcc2f..5a0b2fcd 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing. ================================================= +25.04.2019 + +- Geometry Editor: modified the intersection (if the selected shapes don't intersects preserve them) and substract functions (delete all shapes that were used in the process) +- work in the ToolSilk + 24.04.2019 - PDF import tool: working in making the PDF layer rendering multithreaded in itself (one layer rendered on each worker) diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py index 33cb6312..d37cfc3e 100644 --- a/flatcamEditors/FlatCAMGeoEditor.py +++ b/flatcamEditors/FlatCAMGeoEditor.py @@ -18,7 +18,7 @@ from FlatCAMTool import FlatCAMTool from flatcamGUI.ObjectUI import LengthEntry, RadioSet from shapely.geometry import LineString, LinearRing, MultiLineString -from shapely.ops import cascaded_union +from shapely.ops import cascaded_union, unary_union import shapely.affinity as affinity from numpy import arctan2, Inf, array, sqrt, sign, dot @@ -3117,31 +3117,6 @@ class FlatCAMGeoEditor(QtCore.QObject): self.tool_shape.clear(update=True) self.tool_shape.redraw() - def cutpath(self): - selected = self.get_selected() - tools = selected[1:] - toolgeo = cascaded_union([shp.geo for shp in tools]) - - target = selected[0] - if type(target.geo) == Polygon: - for ring in poly2rings(target.geo): - self.add_shape(DrawToolShape(ring.difference(toolgeo))) - self.delete_shape(target) - elif type(target.geo) == LineString or type(target.geo) == LinearRing: - self.add_shape(DrawToolShape(target.geo.difference(toolgeo))) - self.delete_shape(target) - elif type(target.geo) == MultiLineString: - try: - for linestring in target.geo: - self.add_shape(DrawToolShape(linestring.difference(toolgeo))) - except: - self.app.log.warning("Current LinearString does not intersect the target") - self.delete_shape(target) - else: - self.app.log.warning("Not implemented. Object type: %s" % str(type(target.geo))) - - self.replot() - def toolbar_tool_toggle(self, key): self.options[key] = self.sender().isChecked() if self.options[key] == True: @@ -3781,7 +3756,7 @@ class FlatCAMGeoEditor(QtCore.QObject): :return: None. """ - results = cascaded_union([t.geo for t in self.get_selected()]) + results = unary_union([t.geo for t in self.get_selected()]) # Delete originals. for_deletion = [s for s in self.get_selected()] @@ -3795,9 +3770,9 @@ class FlatCAMGeoEditor(QtCore.QObject): self.replot() - def intersection(self): + def intersection_2(self): """ - Makes intersectino of selected polygons. Original polygons are deleted. + Makes intersection of selected polygons. Original polygons are deleted. :return: None """ @@ -3827,11 +3802,67 @@ class FlatCAMGeoEditor(QtCore.QObject): self.replot() + def intersection(self): + """ + Makes intersection of selected polygons. Original polygons are deleted. + + :return: None + """ + + shapes = self.get_selected() + results = [] + intact = [] + + try: + intersector = shapes[0].geo + except Exception as e: + log.debug("FlatCAMGeoEditor.intersection() --> %s" % str(e)) + self.app.inform.emit(_("[WARNING_NOTCL] A selection of at least 2 geo items is required to do Intersection.")) + self.select_tool('select') + return + + for shape in shapes[1:]: + if intersector.intersects(shape.geo): + results.append(intersector.intersection(shape.geo)) + else: + intact.append(shape) + + if len(results) != 0: + # Delete originals. + for_deletion = [s for s in self.get_selected()] + for shape in for_deletion: + if shape not in intact: + self.delete_shape(shape) + + for geo in results: + self.add_shape(DrawToolShape(geo)) + + # Selected geometry is now gone! + self.selected = [] + self.replot() + def subtract(self): selected = self.get_selected() try: tools = selected[1:] - toolgeo = cascaded_union([shp.geo for shp in tools]) + toolgeo = unary_union([shp.geo for shp in tools]) + result = selected[0].geo.difference(toolgeo) + + for_deletion = [s for s in self.get_selected()] + for shape in for_deletion: + self.delete_shape(shape) + + self.add_shape(DrawToolShape(result)) + + self.replot() + except Exception as e: + log.debug(str(e)) + + def subtract_2(self): + selected = self.get_selected() + try: + tools = selected[1:] + toolgeo = unary_union([shp.geo for shp in tools]) result = selected[0].geo.difference(toolgeo) self.delete_shape(selected[0]) @@ -3841,6 +3872,30 @@ class FlatCAMGeoEditor(QtCore.QObject): except Exception as e: log.debug(str(e)) + def cutpath(self): + selected = self.get_selected() + tools = selected[1:] + toolgeo = unary_union([shp.geo for shp in tools]) + + target = selected[0] + if type(target.geo) == Polygon: + for ring in poly2rings(target.geo): + self.add_shape(DrawToolShape(ring.difference(toolgeo))) + elif type(target.geo) == LineString or type(target.geo) == LinearRing: + self.add_shape(DrawToolShape(target.geo.difference(toolgeo))) + elif type(target.geo) == MultiLineString: + try: + for linestring in target.geo: + self.add_shape(DrawToolShape(linestring.difference(toolgeo))) + except: + self.app.log.warning("Current LinearString does not intersect the target") + else: + self.app.log.warning("Not implemented. Object type: %s" % str(type(target.geo))) + return + + self.delete_shape(target) + self.replot() + def buffer(self, buf_distance, join_style): selected = self.get_selected() diff --git a/flatcamTools/ToolPDF.py b/flatcamTools/ToolPDF.py index 9e3f0dfb..55f4fd59 100644 --- a/flatcamTools/ToolPDF.py +++ b/flatcamTools/ToolPDF.py @@ -18,6 +18,7 @@ import numpy as np import zlib import re +import time import gettext import FlatCAMTranslation as fcTranslate @@ -201,8 +202,11 @@ class ToolPDF(FlatCAMTool): self.pdf_decompressed[short_name] = '' # removal from list is done in a multithreaded way therefore not always the removal can be done + # try to remove until it's done try: - self.parsing_promises.remove(short_name) + while True: + self.parsing_promises.remove(short_name) + time.sleep(0.1) except: pass self.app.inform.emit(_("[success] Opened: %s") % filename) @@ -1057,7 +1061,7 @@ class ToolPDF(FlatCAMTool): # with the final point P3. Intermediate values of t generate intermediate points along the curve. # The curve does not, in general, pass through the two control points P1 and P2 - :return: LineString geometry + :return: A list of point coordinates tuples (x, y) """ # here we store the geometric points diff --git a/flatcamTools/ToolSilk.py b/flatcamTools/ToolSilk.py index aa8f79bb..7c0db6c8 100644 --- a/flatcamTools/ToolSilk.py +++ b/flatcamTools/ToolSilk.py @@ -173,46 +173,48 @@ class ToolSilk(FlatCAMTool): ap_size = self.silk_obj.apertures[apid]['size'] geo_list = self.silk_obj.apertures[apid]['solid_geometry'] self.app.worker_task.emit({'fcn': self.aperture_intersection, - 'params': [apid, ap_size, geo_list]}) + 'params': [apid, geo_list]}) - def aperture_intersection(self, aperture_id, aperture_size, geo_list): - self.promises.append(aperture_id) + def aperture_intersection(self, apid, geo_list): + self.promises.append(apid) new_solid_geometry = [] + for g in geo_list: + print(g.exterior.wkt) - with self.app.proc_container.new(_("Parsing aperture %s geometry ..." % str(aperture_id))): + with self.app.proc_container.new(_("Parsing aperture %s geometry ..." % str(apid))): for geo_silk in geo_list: - for sm_ap in self.sm_obj.apertures: - for key in self.sm_obj.apertures[sm_ap]: - if key == 'solid_geometry': - if geo_silk.intersects(self.solder_union): - new_geo = geo_silk.symmetric_difference(self.solder_union) - # if the resulting geometry is not empty add it to the new_apertures solid_geometry - if type(new_geo) == MultiPolygon: - for g in new_geo: - new_solid_geometry.append(g) - else: - new_solid_geometry.append(new_geo) + if geo_silk.exterior.intersects(self.solder_union.exterior): + print("yes") + new_geo = geo_silk.exterior.difference(self.solder_union.exterior) + # if the resulting geometry is not empty add it to the new_apertures solid_geometry + try: + for g in new_geo: + new_solid_geometry.append(g) + except TypeError: + new_solid_geometry.append(new_geo) - else: - new_solid_geometry.append(geo_silk) + else: + print("no") + new_solid_geometry.append(geo_silk) - try: - while not self.new_apertures[aperture_id]['solid_geometry']: - self.new_apertures[aperture_id]['solid_geometry'] = new_solid_geometry - time.sleep(0.1) - except: - pass + if new_solid_geometry: + try: + while not self.new_apertures[apid]['solid_geometry']: + self.new_apertures[apid]['solid_geometry'] = new_solid_geometry + time.sleep(0.1) + except: + pass try: while True: # removal from list is done in a multithreaded way therefore not always the removal can be done # so we keep trying until it's done - self.promises.remove(aperture_id) + self.promises.remove(apid) time.sleep(0.1) except: pass - def periodic_check(self, check_period): + def periodic_check(self, check_period, reset=False): """ This function starts an QTimer and it will periodically check if intersections are done @@ -227,11 +229,12 @@ class ToolSilk(FlatCAMTool): except: pass - self.check_thread.setInterval(check_period) - try: - self.check_thread.timeout.disconnect(self.periodic_check_handler) - except: - pass + if reset: + self.check_thread.setInterval(check_period) + try: + self.check_thread.timeout.disconnect(self.periodic_check_handler) + except: + pass self.check_thread.timeout.connect(self.periodic_check_handler) self.check_thread.start(QtCore.QThread.HighPriority)