diff --git a/README.md b/README.md index 62f42f5e..0091557d 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ CAD program, and create G-Code for Isolation routing. - fixed an issue with the tool table context menu in Paint Tool - made some changes in the GUI in Paint Tool, NCC Tool and SolderPaste Tool - changed some of the icons; added attributions for icons source in the About FlatCAM window +- added a new tool in the Geometry Editor named Explode which is the opposite of Union Tool: it will explode the polygons into lines 4.10.2019 diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py index 1cb1d797..9e68b684 100644 --- a/flatcamEditors/FlatCAMGeoEditor.py +++ b/flatcamEditors/FlatCAMGeoEditor.py @@ -1324,7 +1324,7 @@ class TransformEditorTool(FlatCAMTool): # get mirroring coords from the point entry if self.flip_ref_cb.isChecked(): px, py = eval('{}'.format(self.flip_ref_entry.text())) - # get mirroing coords from the center of an all-enclosing bounding box + # get mirroring coords from the center of an all-enclosing bounding box else: # first get a bounding box to fit all for sha in shape_list: @@ -2455,6 +2455,61 @@ class FCSelect(DrawTool): return "" +class FCExplode(FCShapeTool): + def __init__(self, draw_app): + FCShapeTool.__init__(self, draw_app) + self.name = 'explode' + + self.draw_app = draw_app + + try: + QtGui.QGuiApplication.restoreOverrideCursor() + except Exception as e: + pass + + self.storage = self.draw_app.storage + self.origin = (0, 0) + self.destination = None + + self.draw_app.active_tool = self + if len(self.draw_app.get_selected()) == 0: + self.draw_app.app.inform.emit('[WARNING_NOTCL] %s...' % + _("No shape selected. Select a shape to explode")) + else: + self.make() + + def make(self): + to_be_deleted_list = list() + lines = list() + + for shape in self.draw_app.get_selected(): + to_be_deleted_list.append(shape) + geo = shape.geo + ext_coords = list(geo.exterior.coords) + + for c in range(len(ext_coords)): + if c < len(ext_coords) - 1: + lines.append(LineString([ext_coords[c], ext_coords[c + 1]])) + + for int_geo in geo.interiors: + int_coords = list(int_geo.coords) + for c in range(len(int_coords)): + if c < len(int_coords): + lines.append(LineString([int_coords[c], int_coords[c + 1]])) + + for shape in to_be_deleted_list: + self.draw_app.storage.remove(shape) + if shape in self.draw_app.selected: + self.draw_app.selected.remove(shape) + + geo_list = list() + for line in lines: + geo_list.append(DrawToolShape(line)) + self.geometry = geo_list + self.draw_app.on_shape_complete() + self.draw_app.app.inform.emit('[success] %s...' % _("Done. Polygons exploded into lines.")) + + class FCMove(FCShapeTool): def __init__(self, draw_app): FCShapeTool.__init__(self, draw_app) @@ -3015,7 +3070,9 @@ class FlatCAMGeoEditor(QtCore.QObject): "transform": {"button": self.app.ui.geo_transform_btn, "constructor": FCTransform}, "copy": {"button": self.app.ui.geo_copy_btn, - "constructor": FCCopy} + "constructor": FCCopy}, + "explode": {"button": self.app.ui.geo_explode_btn, + "constructor": FCExplode} } # # ## Data @@ -4041,7 +4098,8 @@ class FlatCAMGeoEditor(QtCore.QObject): if type(geometry) == LineString or type(geometry) == LinearRing: plot_elements.append(self.shapes.add(shape=geometry, color=color, layer=0, - tolerance=self.fcgeometry.drawing_tolerance)) + tolerance=self.fcgeometry.drawing_tolerance, + linewidth=linewidth)) if type(geometry) == Point: pass @@ -4098,9 +4156,14 @@ class FlatCAMGeoEditor(QtCore.QObject): pl.append(Polygon(p.exterior.coords[::-1], p.interiors)) elif isinstance(p, LinearRing): pl.append(Polygon(p.coords[::-1])) - # elif isinstance(p, LineString): - # pl.append(LineString(p.coords[::-1])) - geom = MultiPolygon(pl) + elif isinstance(p, LineString): + pl.append(LineString(p.coords[::-1])) + try: + geom = MultiPolygon(pl) + except TypeError: + # this may happen if the geom elements are made out of LineStrings because you can't create a + # MultiPolygon out of LineStrings + pass except TypeError: if isinstance(geom, Polygon) and geom is not None: geom = Polygon(geom.exterior.coords[::-1], geom.interiors) diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index 5a3018bb..0e20a8bf 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -775,6 +775,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.geo_edit_toolbar.addSeparator() self.geo_union_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/union32.png'), _('Polygon Union')) + self.geo_explode_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/explode32.png'), _('Polygon Explode')) + self.geo_intersection_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/intersection32.png'), _('Polygon Intersection')) self.geo_subtract_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/subtract32.png'), @@ -2174,6 +2176,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.geo_edit_toolbar.addSeparator() self.geo_union_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/union32.png'), _('Polygon Union')) + self.geo_explode_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/explode32.png'), _('Polygon Explode')) + self.geo_intersection_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/intersection32.png'), _('Polygon Intersection')) self.geo_subtract_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/subtract32.png'), diff --git a/flatcamGUI/PlotCanvasLegacy.py b/flatcamGUI/PlotCanvasLegacy.py index 4be2fb3e..cc6abf3a 100644 --- a/flatcamGUI/PlotCanvasLegacy.py +++ b/flatcamGUI/PlotCanvasLegacy.py @@ -810,7 +810,8 @@ class ShapeCollectionLegacy: self.axes = self.app.plotcanvas.new_axes(axes_name) def add(self, shape=None, color=None, face_color=None, alpha=None, visible=True, - update=False, layer=1, tolerance=0.01, obj=None, gcode_parsed=None, tool_tolerance=None, tooldia=None): + update=False, layer=1, tolerance=0.01, obj=None, gcode_parsed=None, tool_tolerance=None, tooldia=None, + linewidth=None): """ This function will add shapes to the shape collection @@ -826,6 +827,7 @@ class ShapeCollectionLegacy: :param gcode_parsed: not used; just for compatibility with VIsPy canvas :param tool_tolerance: just for compatibility with VIsPy canvas :param tooldia: + :param linewidth: the width of the line :return: """ self._color = color[:-2] if color is not None else None @@ -853,6 +855,7 @@ class ShapeCollectionLegacy: self.shape_dict.update({ 'color': self._color, 'face_color': self._face_color, + 'linewidth': linewidth, 'alpha': self._alpha, 'shape': sh }) @@ -865,6 +868,7 @@ class ShapeCollectionLegacy: self.shape_dict.update({ 'color': self._color, 'face_color': self._face_color, + 'linewidth': linewidth, 'alpha': self._alpha, 'shape': shape }) @@ -928,15 +932,21 @@ class ShapeCollectionLegacy: elif obj_type == 'geometry': if type(local_shapes[element]['shape']) == Polygon: x, y = local_shapes[element]['shape'].exterior.coords.xy - self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-') + self.axes.plot(x, y, local_shapes[element]['color'], + linestyle='-', + linewidth=local_shapes[element]['linewidth']) for ints in local_shapes[element]['shape'].interiors: x, y = ints.coords.xy - self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-') + self.axes.plot(x, y, local_shapes[element]['color'], + linestyle='-', + linewidth=local_shapes[element]['linewidth']) elif type(local_shapes[element]['shape']) == LineString or \ type(local_shapes[element]['shape']) == LinearRing: x, y = local_shapes[element]['shape'].coords.xy - self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-') + self.axes.plot(x, y, local_shapes[element]['color'], + linestyle='-', + linewidth=local_shapes[element]['linewidth']) elif obj_type == 'gerber': if self.obj.options["multicolored"]: diff --git a/flatcamGUI/VisPyVisuals.py b/flatcamGUI/VisPyVisuals.py index dd7c6ef8..3bc70723 100644 --- a/flatcamGUI/VisPyVisuals.py +++ b/flatcamGUI/VisPyVisuals.py @@ -235,7 +235,7 @@ class ShapeCollectionVisual(CompoundVisual): self.freeze() def add(self, shape=None, color=None, face_color=None, alpha=None, visible=True, - update=False, layer=1, tolerance=0.01): + update=False, layer=1, tolerance=0.01, linewidth=None): """ Adds shape to collection :return: @@ -253,6 +253,8 @@ class ShapeCollectionVisual(CompoundVisual): Layer number. 0 - lowest. :param tolerance: float Geometry simplifying tolerance + :param linewidth: int + Not used, for compatibility :return: int Index of shape """ diff --git a/share/explode32.png b/share/explode32.png new file mode 100644 index 00000000..9eae75e6 Binary files /dev/null and b/share/explode32.png differ