Explorar el Código

Merged marius_stanciu/flatcam_beta/Beta_8.993 into Beta

Marius Stanciu hace 5 años
padre
commit
bac0cddc12

+ 5 - 0
CHANGELOG.md

@@ -7,6 +7,11 @@ CHANGELOG for FlatCAM beta
 
 =================================================
 
+7.05.2020
+
+- added a fix so the app close is now clean, with exit code 0 as set
+- added the ability to add exclusion areas from the Excellon object too. Now there is a different in color to differentiate from which type of object the exclusion areas were added but they all serve the same purpose
+
 6.05.2020
 
 - wip in adding Exclusion areas in Geometry object; each Geometry object has now a storage for shapes (exclusion shapes, should I make them more general?)

+ 9 - 5
FlatCAMApp.py

@@ -3598,14 +3598,13 @@ class App(QtCore.QObject):
 
         # try to quit the Socket opened by ArgsThread class
         try:
-            self.new_launch.thread_exit = True
-            self.new_launch.listener.close()
+            self.new_launch.stop.emit()
         except Exception as err:
             log.debug("App.quit_application() --> %s" % str(err))
 
         # try to quit the QThread that run ArgsThread class
         try:
-            self.th.terminate()
+            self.th.quit()
         except Exception as e:
             log.debug("App.quit_application() --> %s" % str(e))
 
@@ -3615,7 +3614,6 @@ class App(QtCore.QObject):
         # quit app by signalling for self.kill_app() method
         # self.close_app_signal.emit()
         QtWidgets.qApp.quit()
-        # QtCore.QCoreApplication.exit()
 
         # When the main event loop is not started yet in which case the qApp.quit() will do nothing
         # we use the following command
@@ -3627,7 +3625,6 @@ class App(QtCore.QObject):
 
     @staticmethod
     def kill_app():
-        # QtCore.QCoreApplication.quit()
         QtWidgets.qApp.quit()
         # When the main event loop is not started yet in which case the qApp.quit() will do nothing
         # we use the following command
@@ -10888,6 +10885,7 @@ class App(QtCore.QObject):
 class ArgsThread(QtCore.QObject):
     open_signal = pyqtSignal(list)
     start = pyqtSignal()
+    stop = pyqtSignal()
 
     if sys.platform == 'win32':
         address = (r'\\.\pipe\NPtest', 'AF_PIPE')
@@ -10900,6 +10898,7 @@ class ArgsThread(QtCore.QObject):
         self.thread_exit = False
 
         self.start.connect(self.run)
+        self.stop.connect(self.close_listener)
 
     def my_loop(self, address):
         try:
@@ -10943,4 +10942,9 @@ class ArgsThread(QtCore.QObject):
     def run(self):
         self.my_loop(self.address)
 
+    @pyqtSlot()
+    def close_listener(self):
+        self.thread_exit = True
+        self.listener.close()
+
 # end of file

+ 31 - 32
FlatCAMCommon.py

@@ -275,11 +275,18 @@ class ExclusionAreas:
                     }
                     self.exclusion_areas_storage.append(new_el)
 
+                    if self.obj_type == 'excellon':
+                        color = "#FF7400"
+                        face_color = "#FF7400BF"
+                    else:
+                        color = "#098a8f"
+                        face_color = "#098a8fBF"
+
                     # add a temporary shape on canvas
                     FlatCAMTool.draw_tool_selection_shape(
                         self, old_coords=(x0, y0), coords=(x1, y1),
-                        color="#FF7400",
-                        face_color="#FF7400BF",
+                        color=color,
+                        face_color=face_color,
                         shapes_storage=self.exclusion_shapes)
 
                     self.first_click = False
@@ -328,10 +335,18 @@ class ExclusionAreas:
                                 "overz": self.over_z
                             }
                             self.exclusion_areas_storage.append(new_el)
+
+                            if self.obj_type == 'excellon':
+                                color = "#FF7400"
+                                face_color = "#FF7400BF"
+                            else:
+                                color = "#098a8f"
+                                face_color = "#098a8fBF"
+
                             FlatCAMTool.draw_selection_shape_polygon(
                                 self, points=self.points,
-                                color="#FF7400",
-                                face_color="#FF7400BF",
+                                color=color,
+                                face_color=face_color,
                                 shapes_storage=self.exclusion_shapes)
                             self.app.inform.emit(
                                 _("Zone added. Click to start adding next zone or right click to finish."))
@@ -456,20 +471,28 @@ class ExclusionAreas:
         self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f&nbsp;&nbsp;  <b>Dy</b>: "
                                                "%.4f&nbsp;&nbsp;&nbsp;&nbsp;" % (self.app.dx, self.app.dy))
 
+        if self.obj_type == 'excellon':
+            color = "#FF7400"
+            face_color = "#FF7400BF"
+        else:
+            color = "#098a8f"
+            face_color = "#098a8fBF"
+
         # draw the utility geometry
         if shape_type == "square":
             if self.first_click:
                 self.app.delete_selection_shape()
+
                 self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
-                                                     color="#FF7400",
-                                                     face_color="#FF7400BF",
+                                                     color=color,
+                                                     face_color=face_color,
                                                      coords=(curr_pos[0], curr_pos[1]))
         else:
             FlatCAMTool.delete_moving_selection_shape(self)
             FlatCAMTool.draw_moving_selection_shape_poly(
                 self, points=self.points,
-                color="#FF7400",
-                face_color="#FF7400BF",
+                color=color,
+                face_color=face_color,
                 data=(curr_pos[0], curr_pos[1]))
 
     def on_clear_area_click(self):
@@ -491,27 +514,3 @@ class ExclusionAreas:
         FlatCAMTool.delete_moving_selection_shape(self)
         self.app.delete_selection_shape()
         FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
-
-
-class InvertHexColor:
-    """
-    Will invert a hex color made out of 3 chars or 6 chars
-    From here: http://code.activestate.com/recipes/527747-invert-css-hex-colors/
-    """
-    def __init__(self):
-        self.p6 = re.compile("#[0-9a-f]{6};", re.IGNORECASE)
-        self.p3 = re.compile("#[0-9a-f]{3};", re.IGNORECASE)
-
-    def modify(self, original_color=3):
-        code = {}
-        l1 = "#;0123456789abcdef"
-        l2 = "#;fedcba9876543210"
-
-        for i in range(len(l1)):
-            code[l1[i]] = l2[i]
-        inverted = ""
-
-        content = p6.sub(modify, content)
-        content = p3.sub(modify, content)
-        return inverted
-

+ 1 - 2
FlatCAMTranslation.py

@@ -186,8 +186,7 @@ def restart_program(app, ask=None):
 
     # try to quit the Socket opened by ArgsThread class
     try:
-        app.new_launch.thread_exit = True
-        app.new_launch.listener.close()
+        app.new_launch.stop.emit()
     except Exception as err:
         log.debug("FlatCAMTranslation.restart_program() --> %s" % str(err))
 

+ 4 - 0
defaults.py

@@ -263,6 +263,10 @@ class FlatCAMDefaults:
         "excellon_tooldia": 0.8,
         "excellon_slot_tooldia": 1.8,
         "excellon_gcode_type": "drills",
+        "excellon_area_exclusion": False,
+        "excellon_area_shape": "polygon",
+        "excellon_area_strategy": "over",
+        "excellon_area_overz": 1.0,
 
         # Excellon Advanced Options
         "excellon_offset": 0.0,

+ 82 - 3
flatcamGUI/ObjectUI.py

@@ -1292,10 +1292,89 @@ class ExcellonObjectUI(ObjectUI):
         self.grid5.addWidget(pp_geo_label, 16, 0)
         self.grid5.addWidget(self.pp_geo_name_cb, 16, 1)
 
+        # Exclusion Areas
+        self.exclusion_cb = FCCheckBox('%s' % _("Exclusion areas"))
+        self.exclusion_cb.setToolTip(
+            _(
+                "Include exclusion areas.\n"
+                "In those areas the travel of the tools\n"
+                "is forbidden."
+            )
+        )
+        self.grid5.addWidget(self.exclusion_cb, 17, 0, 1, 2)
+
+        # ------------------------------------------------------------------------------------------------------------
+        # ------------------------- EXCLUSION AREAS ------------------------------------------------------------------
+        # ------------------------------------------------------------------------------------------------------------
+        self.exclusion_frame = QtWidgets.QFrame()
+        self.exclusion_frame.setContentsMargins(0, 0, 0, 0)
+        self.grid5.addWidget(self.exclusion_frame, 18, 0, 1, 2)
+
+        self.exclusion_box = QtWidgets.QVBoxLayout()
+        self.exclusion_box.setContentsMargins(0, 0, 0, 0)
+        self.exclusion_frame.setLayout(self.exclusion_box)
+
+        h_lay = QtWidgets.QHBoxLayout()
+        self.exclusion_box.addLayout(h_lay)
+
+        # Button Add Area
+        self.add_area_button = QtWidgets.QPushButton(_('Add area'))
+        self.add_area_button.setToolTip(_("Add an Exclusion Area."))
+        h_lay.addWidget(self.add_area_button)
+
+        # Button Delete Area
+        self.delete_area_button = QtWidgets.QPushButton(_('Clear areas'))
+        self.delete_area_button.setToolTip(_("Delete all exclusion areas."))
+        h_lay.addWidget(self.delete_area_button)
+
+        grid_l = QtWidgets.QGridLayout()
+        grid_l.setColumnStretch(0, 0)
+        grid_l.setColumnStretch(1, 1)
+        self.exclusion_box.addLayout(grid_l)
+
+        # Area Selection shape
+        self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
+        self.area_shape_label.setToolTip(
+            _("The kind of selection shape used for area selection.")
+        )
+
+        self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
+                                          {'label': _("Polygon"), 'value': 'polygon'}])
+
+        grid_l.addWidget(self.area_shape_label, 0, 0)
+        grid_l.addWidget(self.area_shape_radio, 0, 1)
+
+        # Chose Strategy
+        self.strategy_label = FCLabel('%s:' % _("Strategy"))
+        self.strategy_label.setToolTip(_("The strategy followed when encountering an exclusion area.\n"
+                                         "Can be:\n"
+                                         "- Over -> when encountering the area, the tool will go to a set height\n"
+                                         "- Around -> will avoid the exclusion area by going around the area"))
+        self.strategy_radio = RadioSet([{'label': _('Over'), 'value': 'over'},
+                                        {'label': _('Around'), 'value': 'around'}])
+
+        grid_l.addWidget(self.strategy_label, 1, 0)
+        grid_l.addWidget(self.strategy_radio, 1, 1)
+
+        # Over Z
+        self.over_z_label = FCLabel('%s:' % _("Over Z"))
+        self.over_z_label.setToolTip(_("The height Z to which the tool will rise in order to avoid\n"
+                                       "an interdiction area."))
+        self.over_z_entry = FCDoubleSpinner()
+        self.over_z_entry.set_range(0.000, 9999.9999)
+        self.over_z_entry.set_precision(self.decimals)
+
+        grid_l.addWidget(self.over_z_label, 2, 0)
+        grid_l.addWidget(self.over_z_entry, 2, 1)
+
+        # -------------------------- EXCLUSION AREAS END -------------------------------------------------------------
+        # ------------------------------------------------------------------------------------------------------------
+        self.ois_exclusion_geo = OptionalHideInputSection(self.exclusion_cb, [self.exclusion_frame])
+
         separator_line = QtWidgets.QFrame()
         separator_line.setFrameShape(QtWidgets.QFrame.HLine)
         separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        self.grid5.addWidget(separator_line, 17, 0, 1, 2)
+        self.grid5.addWidget(separator_line, 19, 0, 1, 2)
 
         # #################################################################
         # ################# GRID LAYOUT 6   ###############################
@@ -2025,7 +2104,7 @@ class GeometryObjectUI(ObjectUI):
         # grid4.addWidget(QtWidgets.QLabel(''), 12, 0, 1, 2)
 
         # Exclusion Areas
-        self.exclusion_cb = FCCheckBox('%s:' % _("Exclusion areas"))
+        self.exclusion_cb = FCCheckBox('%s' % _("Exclusion areas"))
         self.exclusion_cb.setToolTip(
             _(
                 "Include exclusion areas.\n"
@@ -2101,7 +2180,7 @@ class GeometryObjectUI(ObjectUI):
 
         # -------------------------- EXCLUSION AREAS END -------------------------------------------------------------
         # ------------------------------------------------------------------------------------------------------------
-        self.ois_exclusion_geo = OptionalInputSection(self.exclusion_cb, [self.exclusion_frame])
+        self.ois_exclusion_geo = OptionalHideInputSection(self.exclusion_cb, [self.exclusion_frame])
 
         warning_lbl = QtWidgets.QLabel(
             _(

+ 23 - 1
flatcamObjects/FlatCAMExcellon.py

@@ -567,7 +567,11 @@ class ExcellonObject(FlatCAMObj, Excellon):
             "ppname_g": self.ui.pp_geo_name_cb,
             "z_pdepth": self.ui.pdepth_entry,
             "feedrate_probe": self.ui.feedrate_probe_entry,
-            # "gcode_type": self.ui.excellon_gcode_type_radio
+            # "gcode_type": self.ui.excellon_gcode_type_radio,
+            "area_exclusion": self.ui.exclusion_cb,
+            "area_shape": self.ui.area_shape_radio,
+            "area_strategy": self.ui.strategy_radio,
+            "area_overz": self.ui.over_z_entry,
         })
 
         self.name2option = {
@@ -634,6 +638,9 @@ class ExcellonObject(FlatCAMObj, Excellon):
         self.ui.generate_milling_button.clicked.connect(self.on_generate_milling_button_click)
         self.ui.generate_milling_slots_button.clicked.connect(self.on_generate_milling_slots_button_click)
 
+        self.ui.add_area_button.clicked.connect(self.on_add_area_click)
+        self.ui.delete_area_button.clicked.connect(self.on_clear_area_click)
+
         self.on_operation_type(val='drill')
         self.ui.operation_radio.activated_custom.connect(self.on_operation_type)
 
@@ -1467,6 +1474,21 @@ class ExcellonObject(FlatCAMObj, Excellon):
         #     self.options['startz'] = float(self.options['startz']) * factor
         # self.options['endz'] = float(self.options['endz']) * factor
 
+    def on_add_area_click(self):
+        shape_button = self.ui.area_shape_radio
+        overz_button = self.ui.over_z_entry
+        strategy_radio = self.ui.strategy_radio
+        cnc_button = self.ui.generate_cnc_button
+        solid_geo = self.solid_geometry
+        obj_type = self.kind
+
+        self.app.exc_areas.on_add_area_click(
+            shape_button=shape_button, overz_button=overz_button, cnc_button=cnc_button, strategy_radio=strategy_radio,
+            solid_geo=solid_geo, obj_type=obj_type)
+
+    def on_clear_area_click(self):
+        self.app.exc_areas.on_clear_area_click()
+
     def on_solid_cb_click(self, *args):
         if self.muted_ui:
             return

+ 7 - 11
flatcamObjects/FlatCAMGeometry.py

@@ -1674,15 +1674,11 @@ class GeometryObject(FlatCAMObj, Geometry):
         The actual work is done by the target CNCJobObject object's
         `generate_from_geometry_2()` method.
 
-        :param tools_dict: a dictionary that holds the whole data needed to create the Gcode
-        (including the solid_geometry)
-
-        :param tools_in_use: the tools that are used, needed by some preprocessors
-        :type list of lists, each list in the list is made out of row elements of tools table from GUI
-
         :param outname:
-        :param tools_dict:
-        :param tools_in_use:
+        :param tools_dict:      a dictionary that holds the whole data needed to create the Gcode
+                                (including the solid_geometry)
+        :param tools_in_use:    the tools that are used, needed by some preprocessors
+        :type  tools_in_use     list of lists, each list in the list is made out of row elements of tools table from GUI
         :param segx:            number of segments on the X axis, for auto-levelling
         :param segy:            number of segments on the Y axis, for auto-levelling
         :param plot:            if True the generated object will be plotted; if False will not be plotted
@@ -1726,7 +1722,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             # count the tools
             tool_cnt = 0
 
-            dia_cnc_dict = {}
+            # dia_cnc_dict = {}
 
             # this turn on the FlatCAMCNCJob plot for multiple tools
             job_obj.multitool = True
@@ -1866,7 +1862,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             # count the tools
             tool_cnt = 0
 
-            dia_cnc_dict = {}
+            # dia_cnc_dict = {}
 
             # this turn on the FlatCAMCNCJob plot for multiple tools
             job_obj.multitool = True
@@ -2040,7 +2036,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             use_thread=True,
             plot=True):
         """
-        Only used for TCL Command.
+        Only used by the TCL Command Cncjob.
         Creates a CNCJob out of this Geometry object. The actual
         work is done by the target camlib.CNCjob
         `generate_from_geometry_2()` method.