Преглед изворни кода

- added new option in ToolSub: the ability to close (or not) the resulting paths when using tool on Geometry objects. Added also a new category in the Edit -> Preferences -> Tools, the Substractor Tool Options

Marius Stanciu пре 6 година
родитељ
комит
ee3b38327e
4 измењених фајлова са 99 додато и 10 уклоњено
  1. 5 2
      FlatCAMApp.py
  2. 4 0
      README.md
  3. 26 0
      flatcamGUI/FlatCAMGUI.py
  4. 64 8
      flatcamTools/ToolSub.py

+ 5 - 2
FlatCAMApp.py

@@ -590,7 +590,8 @@ class App(QtCore.QObject):
             "tools_solderpaste_dwellfwd": self.ui.tools_defaults_form.tools_solderpaste_group.dwellfwd_entry,
             "tools_solderpaste_speedrev": self.ui.tools_defaults_form.tools_solderpaste_group.speedrev_entry,
             "tools_solderpaste_dwellrev": self.ui.tools_defaults_form.tools_solderpaste_group.dwellrev_entry,
-            "tools_solderpaste_pp": self.ui.tools_defaults_form.tools_solderpaste_group.pp_combo
+            "tools_solderpaste_pp": self.ui.tools_defaults_form.tools_solderpaste_group.pp_combo,
+            "tools_sub_close_paths": self.ui.tools_defaults_form.tools_sub_group.close_paths_cb
 
         }
 
@@ -922,7 +923,9 @@ class App(QtCore.QObject):
             "tools_solderpaste_dwellfwd": 1,
             "tools_solderpaste_speedrev": 10,
             "tools_solderpaste_dwellrev": 1,
-            "tools_solderpaste_pp": 'Paste_1'
+            "tools_solderpaste_pp": 'Paste_1',
+
+            "tools_sub_close_paths": True
         })
 
         # ##############################

+ 4 - 0
README.md

@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+13.08.2019
+
+- added new option in ToolSub: the ability to close (or not) the resulting paths when using tool on Geometry objects. Added also a new category in the Edit -> Preferences -> Tools, the Substractor Tool Options
+
 12.08.2019
 
 - done regression to solve the bug with multiple passes cutting from the copper features (I should remember not to make mods here)

+ 26 - 0
flatcamGUI/FlatCAMGUI.py

@@ -3280,6 +3280,9 @@ class ToolsPreferencesUI(QtWidgets.QWidget):
         self.tools_solderpaste_group = ToolsSolderpastePrefGroupUI()
         self.tools_solderpaste_group.setMinimumWidth(200)
 
+        self.tools_sub_group = ToolsSubPrefGroupUI()
+        self.tools_sub_group.setMinimumWidth(200)
+
         self.vlay = QtWidgets.QVBoxLayout()
         self.vlay.addWidget(self.tools_ncc_group)
         self.vlay.addWidget(self.tools_paint_group)
@@ -3296,6 +3299,7 @@ class ToolsPreferencesUI(QtWidgets.QWidget):
 
         self.vlay3 = QtWidgets.QVBoxLayout()
         self.vlay3.addWidget(self.tools_solderpaste_group)
+        self.vlay3.addWidget(self.tools_sub_group)
 
         self.layout.addLayout(self.vlay)
         self.layout.addLayout(self.vlay1)
@@ -6708,6 +6712,28 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
         self.layout.addStretch()
 
 
+class ToolsSubPrefGroupUI(OptionsGroupUI):
+    def __init__(self, parent=None):
+
+        super(ToolsSubPrefGroupUI, self).__init__(self)
+
+        self.setTitle(str(_("Substractor Tool Options")))
+
+        # ## Solder Paste Dispensing
+        self.sublabel = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.sublabel.setToolTip(
+            _("A tool to substract one Gerber or Geometry object\n"
+              "from another of the same type.")
+        )
+        self.layout.addWidget(self.sublabel)
+
+        self.close_paths_cb = FCCheckBox(_("Close paths"))
+        self.close_paths_cb.setToolTip(_("Checking this will close the paths cut by the Geometry substractor object."))
+        self.layout.addWidget(self.close_paths_cb)
+
+        self.layout.addStretch()
+
+
 class FlatCAMActivityView(QtWidgets.QWidget):
 
     def __init__(self, parent=None):

+ 64 - 8
flatcamTools/ToolSub.py

@@ -130,6 +130,10 @@ class ToolSub(FlatCAMTool):
 
         form_geo_layout.addRow(self.sub_geo_label, self.sub_geo_combo)
 
+        self.close_paths_cb = FCCheckBox(_("Close paths"))
+        self.close_paths_cb.setToolTip(_("Checking this will close the paths cut by the Geometry substractor object."))
+        self.tools_box.addWidget(self.close_paths_cb)
+
         self.intersect_geo_btn = FCButton(_('Substract Geometry'))
         self.intersect_geo_btn.setToolTip(
             _("Will remove the area occupied by the substractor\n"
@@ -217,6 +221,7 @@ class ToolSub(FlatCAMTool):
 
     def set_tool_ui(self):
         self.tools_frame.show()
+        self.close_paths_cb.setChecked(self.app.defaults["tools_sub_close_paths"])
 
     def on_grb_intersection_click(self):
         # reset previous values
@@ -231,7 +236,7 @@ class ToolSub(FlatCAMTool):
             self.app.inform.emit(_("[ERROR_NOTCL] No Target object loaded."))
             return
 
-        # Get source object.
+        # Get target object.
         try:
             self.target_grb_obj = self.app.collection.get_by_name(self.target_grb_obj_name)
         except Exception as e:
@@ -244,7 +249,7 @@ class ToolSub(FlatCAMTool):
             self.app.inform.emit(_("[ERROR_NOTCL] No Substractor object loaded."))
             return
 
-        # Get source object.
+        # Get substractor object.
         try:
             self.sub_grb_obj = self.app.collection.get_by_name(self.sub_grb_obj_name)
         except Exception as e:
@@ -424,7 +429,7 @@ class ToolSub(FlatCAMTool):
             self.app.inform.emit(_("[ERROR_NOTCL] No Target object loaded."))
             return
 
-        # Get source object.
+        # Get target object.
         try:
             self.target_geo_obj = self.app.collection.get_by_name(self.target_geo_obj_name)
         except Exception as e:
@@ -437,7 +442,7 @@ class ToolSub(FlatCAMTool):
             self.app.inform.emit(_("[ERROR_NOTCL] No Substractor object loaded."))
             return
 
-        # Get source object.
+        # Get substractor object.
         try:
             self.sub_geo_obj = self.app.collection.get_by_name(self.sub_geo_obj_name)
         except Exception as e:
@@ -496,10 +501,58 @@ class ToolSub(FlatCAMTool):
             text = _("Parsing tool %s geometry ...") % str(tool)
 
         with self.app.proc_container.new(text):
-            new_geo = (cascaded_union(geo)).difference(self.sub_union)
-            if new_geo:
-                if not new_geo.is_empty:
-                    new_geometry.append(new_geo)
+            # resulting paths are closed resulting into Polygons
+            if self.close_paths_cb.isChecked():
+                new_geo = (cascaded_union(geo)).difference(self.sub_union)
+                if new_geo:
+                    if not new_geo.is_empty:
+                        new_geometry.append(new_geo)
+            # resulting paths are unclosed resulting in a multitude of rings
+            else:
+                try:
+                    for geo_elem in geo:
+                        if isinstance(geo_elem, Polygon):
+                            for ring in self.poly2rings(geo_elem):
+                                new_geo = ring.difference(self.sub_union)
+                                if new_geo:
+                                    if not new_geo.is_empty:
+                                        new_geometry.append(new_geo)
+                        elif isinstance(geo_elem, MultiPolygon):
+                            for poly in geo_elem:
+                                for ring in self.poly2rings(poly):
+                                    new_geo = ring.difference(self.sub_union)
+                                    if new_geo:
+                                        if not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                        elif isinstance(geo_elem, LineString):
+                            new_geo = geo_elem.difference(self.sub_union)
+                            if new_geo:
+                                if not new_geo.is_empty:
+                                    new_geometry.append(new_geo)
+                        elif isinstance(geo_elem, MultiLineString):
+                            for line_elem in geo_elem:
+                                new_geo = line_elem.difference(self.sub_union)
+                                if new_geo:
+                                    if not new_geo.is_empty:
+                                        new_geometry.append(new_geo)
+                except TypeError:
+                    if isinstance(geo, Polygon):
+                        for ring in self.poly2rings(geo):
+                            new_geo = ring.difference(self.sub_union)
+                            if new_geo:
+                                if not new_geo.is_empty:
+                                    new_geometry.append(new_geo)
+                    elif isinstance(geo, LineString):
+                        new_geo = geo.difference(self.sub_union)
+                        if new_geo:
+                            if not new_geo.is_empty:
+                                new_geometry.append(new_geo)
+                    elif isinstance(geo, MultiLineString):
+                        for line_elem in geo:
+                            new_geo = line_elem.difference(self.sub_union)
+                            if new_geo:
+                                if not new_geo.is_empty:
+                                    new_geometry.append(new_geo)
 
         if new_geometry:
             if tool == "single":
@@ -620,4 +673,7 @@ class ToolSub(FlatCAMTool):
         self.target_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
         self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
 
+    @staticmethod
+    def poly2rings(poly):
+        return [poly.exterior] + [interior for interior in poly.interiors]
 # end of file