From 2ba0b494ff23549b8394057a4f4584515e5d1fb6 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Mon, 15 Apr 2019 22:48:22 +0300 Subject: [PATCH] - Gerber Editor: finished a new tool: Poligonize Tool (ALT+N in Editor). It will fuse a selection of tracks into a polygon. It will fill a selection of polygons if they are apart and it will make a single polygon if the selection is overlapped. All the newly created filled polygons will be stored in aperture '0' (if it does not exist it will be automatically created) - fixed a bug in Move command in context menu who crashed the app when triggered - Gerber Editor: when adding a new aperture it will be store as the last selected and it will be used for any tools that are triggered until a new aperture is selected. --- FlatCAMApp.py | 2 +- README.md | 5 ++- camlib.py | 12 ++--- flatcamEditors/FlatCAMGrbEditor.py | 69 ++++++++++++++++++----------- flatcamGUI/FlatCAMGUI.py | 11 ++++- share/poligonize32.png | Bin 0 -> 522 bytes 6 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 share/poligonize32.png diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 850f3da8..d563be51 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -5653,7 +5653,7 @@ class App(QtCore.QObject): def obj_move(self): self.report_usage("obj_move()") - self.move_tool.run() + self.move_tool.run(toggle=False) def on_fileopengerber(self): """ diff --git a/README.md b/README.md index 8a2adb8a..a73e875c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,10 @@ CAD program, and create G-Code for Isolation routing. - update the order of event handlers connection in Editors to first connect new handlers then disconnect old handlers. It seems that if nothing is connected some VispY functions like canvas panning no longer works if there is at least once nothing connected to the 'mouse_move' event - Excellon Editor: update so always there is a tool selected even after the Execllon object was just edited; before it always required a click inside of the tool table, not you do it only if needed. - fixed the menu File -> Edit -> Edit/Close Editor entry to reflect the status of the app (Editor active or not) -- added support in Excellon parser for autodetection of Excellon file format for the Excellon files generate by the following ECAD sw: DipTrace, Eagle, Altium, Sprint Layout +- added support in Excellon parser for autodetection of Excellon file format for the Excellon files generated by the following ECAD sw: DipTrace, Eagle, Altium, Sprint Layout +- Gerber Editor: finished a new tool: Poligonize Tool (ALT+N in Editor). It will fuse a selection of tracks into a polygon. It will fill a selection of polygons if they are apart and it will make a single polygon if the selection is overlapped. All the newly created filled polygons will be stored in aperture '0' (if it does not exist it will be automatically created) +- fixed a bug in Move command in context menu who crashed the app when triggered +- Gerber Editor: when adding a new aperture it will be store as the last selected and it will be used for any tools that are triggered until a new aperture is selected. 14.04.2019 diff --git a/camlib.py b/camlib.py index 05773d7c..41d03454 100644 --- a/camlib.py +++ b/camlib.py @@ -3928,9 +3928,10 @@ class Excellon(Geometry): log.warning("Found ALLEGRO start of the header: %s" % eline) continue - # Header End # - # Since there might be comments in the header that include char % or M95 - # we ignore the lines starting with ';' which show they are comments + # Search for Header End # + # Since there might be comments in the header that include header end char (% or M95) + # we ignore the lines starting with ';' that contains such header end chars because it is not a + # real header end. if self.comm_re.search(eline): match = self.tool_units_re.search(eline) if match: @@ -3938,7 +3939,7 @@ class Excellon(Geometry): line_units_found = True line_units = match.group(3) self.convert_units({"MILS": "IN", "MM": "MM"}[line_units]) - log.warning("Type of Allegro UNITS found inline: %s" % line_units) + log.warning("Type of Allegro UNITS found inline in comments: %s" % line_units) if match.group(2): name_tool += 1 @@ -3960,7 +3961,8 @@ class Excellon(Geometry): self.excellon_format_upper_in = match.group(1) self.excellon_format_lower_in = match.group(2) - log.warning("Altium Excellon format preset found: %s:%s" % (match.group(1), match.group(2))) + log.warning("Altium Excellon format preset found in comments: %s:%s" % + (match.group(1), match.group(2))) continue else: log.warning("Line ignored, it's a comment: %s" % eline) diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py index e29b1137..d94ebb9d 100644 --- a/flatcamEditors/FlatCAMGrbEditor.py +++ b/flatcamEditors/FlatCAMGrbEditor.py @@ -2,7 +2,7 @@ from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5.QtCore import Qt, QSettings 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 @@ -497,39 +497,42 @@ class FCPoligonize(FCShapeTool): self.make() def click(self, point): - # self.draw_app.in_action = True - # if self.draw_app.selected: - # self.make() - # else: - # self.draw_app.app.inform.emit(_("[WARNING_NOTCL] No shapes are selected. Select shapes and try again ...")) - return "" def make(self): - geo = [] - for shape in self.draw_app.selected: - current_storage = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['solid_geometry'] - print(self.draw_app.active_tool) - aha = [] - if shape.geo: - shape_points = list(shape.geo.exterior.coords) - for pt in shape_points: - aha.append(Point(pt)) - concave_hull, bla_bla = alpha_shape(points=aha, alpha=0.5) - geo.append(concave_hull) - print(geo) - self.geometry = DrawToolShape(geo) - self.draw_app.on_grb_shape_complete(current_storage) + if not self.draw_app.selected: + self.draw_app.in_action = False + self.complete = True + self.draw_app.app.inform.emit(_("[ERROR_NOTCL] Failed. Nothing selected.")) + self.draw_app.select_tool("select") + return + + try: + current_storage = self.draw_app.storage_dict['0']['solid_geometry'] + except KeyError: + self.draw_app.on_aperture_add(apid='0') + current_storage = self.draw_app.storage_dict['0']['solid_geometry'] + + fused_geo = [Polygon(sh.geo.exterior) for sh in self.draw_app.selected] + + fused_geo = MultiPolygon(fused_geo) + fused_geo = fused_geo.buffer(0.0000001) + if isinstance(fused_geo, MultiPolygon): + for geo in fused_geo: + self.draw_app.on_grb_shape_complete(current_storage, specific_shape=DrawToolShape(geo)) + else: + self.draw_app.on_grb_shape_complete(current_storage, specific_shape=DrawToolShape(fused_geo)) + + self.draw_app.delete_selected() + self.draw_app.plot_all() self.draw_app.in_action = False self.complete = True self.draw_app.app.inform.emit(_("[success] Done. Poligonize completed.")) - self.draw_app.build_ui() # MS: always return to the Select Tool if modifier key is not pressed # else return to the current tool - key_modifier = QtWidgets.QApplication.keyboardModifiers() if self.draw_app.app.defaults["global_mselect_key"] == 'Control': modifier_to_use = Qt.ControlModifier @@ -1472,6 +1475,7 @@ class FlatCAMGrbEditor(QtCore.QObject): self.app.ui.grb_add_track_menuitem.triggered.connect(self.on_track_add) self.app.ui.grb_add_region_menuitem.triggered.connect(self.on_region_add) + self.app.ui.grb_convert_poly_menuitem.triggered.connect(self.on_poligonize) self.app.ui.grb_add_buffer_menuitem.triggered.connect(self.on_buffer) self.app.ui.grb_add_scale_menuitem.triggered.connect(self.on_scale) self.app.ui.grb_transform_menuitem.triggered.connect(self.transform_tool.run) @@ -1760,6 +1764,8 @@ class FlatCAMGrbEditor(QtCore.QObject): self.build_ui() + self.last_aperture_selected = ap_id + # make a quick sort through the tool2tooldia dict so we find which row to select row_to_be_selected = None for key in sorted(self.tool2tooldia): @@ -2346,15 +2352,22 @@ class FlatCAMGrbEditor(QtCore.QObject): self.options[key] = self.sender().isChecked() return self.options[key] - def on_grb_shape_complete(self, storage=None): + def on_grb_shape_complete(self, storage=None, specific_shape=None): self.app.log.debug("on_shape_complete()") + if specific_shape: + geo = specific_shape + else: + geo = self.active_tool.geometry + if geo is None: + return + if storage is not None: # Add shape - self.add_gerber_shape(self.active_tool.geometry, storage) + self.add_gerber_shape(geo, storage) else: stora = self.storage_dict[self.last_aperture_selected]['solid_geometry'] - self.add_gerber_shape(self.active_tool.geometry, storage=stora) + self.add_gerber_shape(geo, storage=stora) # Remove any utility shapes self.delete_utility_geometry() @@ -2372,6 +2385,7 @@ class FlatCAMGrbEditor(QtCore.QObject): :return: None """ # List of DrawToolShape? + if isinstance(shape, list): for subshape in shape: self.add_gerber_shape(subshape, storage) @@ -2859,6 +2873,9 @@ class FlatCAMGrbEditor(QtCore.QObject): def on_region_add(self): self.select_tool('region') + def on_poligonize(self): + self.select_tool('poligonize') + def on_buffer(self): buff_value = 0.01 log.debug("FlatCAMGrbEditor.on_buffer()") diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index 37914892..d8b37baf 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -470,6 +470,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): _('Add Region\tN')) self.grb_editor_menu.addSeparator() + self.grb_convert_poly_menuitem = self.grb_editor_menu.addAction(QtGui.QIcon('share/poligonize32.png'), + _("Poligonize\tALT+N")) self.grb_add_buffer_menuitem = self.grb_editor_menu.addAction(QtGui.QIcon('share/buffer16-2.png'), _('Buffer\tB')) self.grb_add_scale_menuitem = self.grb_editor_menu.addAction(QtGui.QIcon('share/scale32.png'), @@ -690,7 +692,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.add_pad_ar_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/padarray32.png'), _('Add Pad Array')) self.grb_add_track_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/track32.png'), _("Add Track")) self.grb_add_region_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/polygon32.png'), _("Add Region")) - self.grb_convert_poly_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/polygon32.png'), _("Poligonize")) + self.grb_convert_poly_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/poligonize32.png'), + _("Poligonize")) self.grb_edit_toolbar.addSeparator() @@ -2529,11 +2532,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow): elif modifiers == QtCore.Qt.ShiftModifier: pass elif modifiers == QtCore.Qt.AltModifier: + # Poligonize Tool + if key == QtCore.Qt.Key_N or key == 'N': + self.app.grb_editor.on_poligonize() + return + # Transformation Tool if key == QtCore.Qt.Key_R or key == 'R': self.app.grb_editor.on_transform() return - elif modifiers == QtCore.Qt.NoModifier: # Abort the current action if key == QtCore.Qt.Key_Escape or key == 'Escape': diff --git a/share/poligonize32.png b/share/poligonize32.png new file mode 100644 index 0000000000000000000000000000000000000000..95a5e3863f99259a8ecf23f96e3b596bf1ae976a GIT binary patch literal 522 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE zr>`sfV-|j9Yk4PW%{~SOMj=lZ#}JR>Z>QMi9dZz8wYTnUQN0v2Nl*R6%pDTBD(f6F zHF;TudQ}4gCS?5Z4p^g58I*A5*6+th^JeO`pw^Vzv_VmUMdszl<(z^^VtH)(DL-3W zQ|n^pXz(!kA68la=h@C1+-HQ&6|Q>1$j-1d*7f4Dr6o3R$_!TI$M526JyIlp^!^cH ze_vG|hBcil|2$`#SrmBg$jHeWM8P_Say}BTLKo=IEp-h{bPY{I3=OPIEv<|Vbq&m|3=B5!+rAY= dLvDUbW?Cg~4Tm1{a{@Imc)I$ztaD0e0sy|S!DRpd literal 0 HcmV?d00001