Просмотр исходного кода

- made Progressive plotting work in Isolation Tool
- fix an issue with progressive plotted shapes not being deleted on the end of the job

Marius Stanciu 5 лет назад
Родитель
Сommit
54407f6e50
3 измененных файлов с 81 добавлено и 31 удалено
  1. 57 22
      AppTools/ToolIsolation.py
  2. 2 0
      CHANGELOG.md
  3. 22 9
      camlib.py

+ 57 - 22
AppTools/ToolIsolation.py

@@ -805,6 +805,9 @@ class ToolIsolation(AppTool, Gerber):
             self.except_cb.set_value(False)
             self.except_cb.set_value(False)
             self.except_cb.hide()
             self.except_cb.hide()
 
 
+            self.type_excobj_radio.hide()
+            self.exc_obj_combo.hide()
+
             self.select_combo.setCurrentIndex(0)
             self.select_combo.setCurrentIndex(0)
             self.select_combo.hide()
             self.select_combo.hide()
             self.select_label.hide()
             self.select_label.hide()
@@ -1747,6 +1750,8 @@ class ToolIsolation(AppTool, Gerber):
                                      lim_area=limited_area, plot=plot)
                                      lim_area=limited_area, plot=plot)
 
 
         else:
         else:
+            prog_plot = self.app.defaults["tools_iso_plotting"]
+
             for tool in tools_storage:
             for tool in tools_storage:
                 tool_data = tools_storage[tool]['data']
                 tool_data = tools_storage[tool]['data']
                 to_follow = tool_data['tools_iso_follow']
                 to_follow = tool_data['tools_iso_follow']
@@ -1793,7 +1798,7 @@ class ToolIsolation(AppTool, Gerber):
                     mill_dir = 1 if milling_type == 'cl' else 0
                     mill_dir = 1 if milling_type == 'cl' else 0
 
 
                     iso_geo = self.generate_envelope(iso_offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
                     iso_geo = self.generate_envelope(iso_offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
-                                                     follow=to_follow, nr_passes=i)
+                                                     follow=to_follow, nr_passes=i, prog_plot=prog_plot)
                     if iso_geo == 'fail':
                     if iso_geo == 'fail':
                         self.app.inform.emit(
                         self.app.inform.emit(
                             '[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
                             '[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
@@ -1865,11 +1870,17 @@ class ToolIsolation(AppTool, Gerber):
 
 
                     self.app.app_obj.new_object("geometry", iso_name, iso_init, plot=plot)
                     self.app.app_obj.new_object("geometry", iso_name, iso_init, plot=plot)
 
 
+            # clean the progressive plotted shapes if it was used
+
+            if prog_plot == 'progressive':
+                self.temp_shapes.clear(update=True)
+
         # Switch notebook to Selected page
         # Switch notebook to Selected page
         self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
         self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
 
 
     def combined_rest(self, iso_obj, iso2geo, tools_storage, lim_area, plot=True):
     def combined_rest(self, iso_obj, iso2geo, tools_storage, lim_area, plot=True):
         """
         """
+        Isolate the provided Gerber object using "rest machining" strategy
 
 
         :param iso_obj:         the isolated Gerber object
         :param iso_obj:         the isolated Gerber object
         :type iso_obj:          AppObjects.FlatCAMGerber.GerberObject
         :type iso_obj:          AppObjects.FlatCAMGerber.GerberObject
@@ -1904,6 +1915,9 @@ class ToolIsolation(AppTool, Gerber):
         else:
         else:
             pass
             pass
 
 
+        # decide to use "progressive" or "normal" plotting
+        prog_plot = self.app.defaults["tools_iso_plotting"]
+
         for sorted_tool in sorted_tools:
         for sorted_tool in sorted_tools:
             for tool in tools_storage:
             for tool in tools_storage:
                 if float('%.*f' % (self.decimals, tools_storage[tool]['tooldia'])) == sorted_tool:
                 if float('%.*f' % (self.decimals, tools_storage[tool]['tooldia'])) == sorted_tool:
@@ -1942,7 +1956,8 @@ class ToolIsolation(AppTool, Gerber):
 
 
                     solid_geo, work_geo = self.generate_rest_geometry(geometry=work_geo, tooldia=tool_dia,
                     solid_geo, work_geo = self.generate_rest_geometry(geometry=work_geo, tooldia=tool_dia,
                                                                       passes=passes, overlap=overlap, invert=mill_dir,
                                                                       passes=passes, overlap=overlap, invert=mill_dir,
-                                                                      env_iso_type=iso_t)
+                                                                      env_iso_type=iso_t, prog_plot=prog_plot,
+                                                                      prog_plot_handler=self.plot_temp_shapes)
 
 
                     # ############################################################
                     # ############################################################
                     # ########## AREA SUBTRACTION ################################
                     # ########## AREA SUBTRACTION ################################
@@ -1973,6 +1988,10 @@ class ToolIsolation(AppTool, Gerber):
                     if not work_geo:
                     if not work_geo:
                         break
                         break
 
 
+        # clean the progressive plotted shapes if it was used
+        if self.app.defaults["tools_iso_plotting"] == 'progressive':
+            self.temp_shapes.clear(update=True)
+
         def iso_init(geo_obj, app_obj):
         def iso_init(geo_obj, app_obj):
             geo_obj.options["cnctooldia"] = str(tool_dia)
             geo_obj.options["cnctooldia"] = str(tool_dia)
 
 
@@ -2052,6 +2071,7 @@ class ToolIsolation(AppTool, Gerber):
 
 
         iso_name = iso_obj.options["name"] + '_iso_combined'
         iso_name = iso_obj.options["name"] + '_iso_combined'
         geometry = iso2geo
         geometry = iso2geo
+        prog_plot = self.app.defaults["tools_iso_plotting"]
 
 
         for tool in tools_storage:
         for tool in tools_storage:
             tool_dia = tools_storage[tool]['tooldia']
             tool_dia = tools_storage[tool]['tooldia']
@@ -2100,7 +2120,7 @@ class ToolIsolation(AppTool, Gerber):
                 mill_dir = 1 if milling_type == 'cl' else 0
                 mill_dir = 1 if milling_type == 'cl' else 0
 
 
                 iso_geo = self.generate_envelope(iso_offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
                 iso_geo = self.generate_envelope(iso_offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
-                                                 follow=to_follow, nr_passes=nr_pass)
+                                                 follow=to_follow, nr_passes=nr_pass, prog_plot=prog_plot)
                 if iso_geo == 'fail':
                 if iso_geo == 'fail':
                     self.app.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
                     self.app.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
                     continue
                     continue
@@ -2135,6 +2155,10 @@ class ToolIsolation(AppTool, Gerber):
 
 
             total_solid_geometry += solid_geo
             total_solid_geometry += solid_geo
 
 
+        # clean the progressive plotted shapes if it was used
+        if prog_plot == 'progressive':
+            self.temp_shapes.clear(update=True)
+
         def iso_init(geo_obj, app_obj):
         def iso_init(geo_obj, app_obj):
             geo_obj.options["cnctooldia"] = str(tool_dia)
             geo_obj.options["cnctooldia"] = str(tool_dia)
 
 
@@ -2709,7 +2733,8 @@ class ToolIsolation(AppTool, Gerber):
     def poly2ints(poly):
     def poly2ints(poly):
         return [interior for interior in poly.interiors]
         return [interior for interior in poly.interiors]
 
 
-    def generate_envelope(self, offset, invert, geometry=None, env_iso_type=2, follow=None, nr_passes=0):
+    def generate_envelope(self, offset, invert, geometry=None, env_iso_type=2, follow=None, nr_passes=0,
+                          prog_plot=False):
         """
         """
         Isolation_geometry produces an envelope that is going on the left of the geometry
         Isolation_geometry produces an envelope that is going on the left of the geometry
         (the copper features). To leave the least amount of burrs on the features
         (the copper features). To leave the least amount of burrs on the features
@@ -2730,17 +2755,19 @@ class ToolIsolation(AppTool, Gerber):
         :type follow:           bool
         :type follow:           bool
         :param nr_passes:       Number of passes
         :param nr_passes:       Number of passes
         :type nr_passes:        int
         :type nr_passes:        int
+        :param prog_plot:       Type of plotting: "normal" or "progressive"
+        :type prog_plot:        str
         :return:                The buffered geometry
         :return:                The buffered geometry
         :rtype:                 MultiPolygon or Polygon
         :rtype:                 MultiPolygon or Polygon
         """
         """
 
 
         if follow:
         if follow:
-            geom = self.grb_obj.isolation_geometry(offset, geometry=geometry, follow=follow)
+            geom = self.grb_obj.isolation_geometry(offset, geometry=geometry, follow=follow, prog_plot=prog_plot)
             return geom
             return geom
         else:
         else:
             try:
             try:
                 geom = self.grb_obj.isolation_geometry(offset, geometry=geometry, iso_type=env_iso_type,
                 geom = self.grb_obj.isolation_geometry(offset, geometry=geometry, iso_type=env_iso_type,
-                                                       passes=nr_passes)
+                                                       passes=nr_passes, prog_plot=prog_plot)
             except Exception as e:
             except Exception as e:
                 log.debug('ToolIsolation.generate_envelope() --> %s' % str(e))
                 log.debug('ToolIsolation.generate_envelope() --> %s' % str(e))
                 return 'fail'
                 return 'fail'
@@ -2769,25 +2796,30 @@ class ToolIsolation(AppTool, Gerber):
         return geom
         return geom
 
 
     @staticmethod
     @staticmethod
-    def generate_rest_geometry(geometry, tooldia, passes, overlap, invert, env_iso_type=2):
+    def generate_rest_geometry(geometry, tooldia, passes, overlap, invert, env_iso_type=2,
+                               prog_plot="normal", prog_plot_handler=None):
         """
         """
         Will try to isolate the geometry and return a tuple made of list of paths made through isolation
         Will try to isolate the geometry and return a tuple made of list of paths made through isolation
         and a list of Shapely Polygons that could not be isolated
         and a list of Shapely Polygons that could not be isolated
 
 
-        :param geometry:        A list of Shapely Polygons to be isolated
-        :type geometry:         list
-        :param tooldia:         The tool diameter used to do the isolation
-        :type tooldia:          float
-        :param passes:          Number of passes that will made the isolation
-        :type passes:           int
-        :param overlap:         How much to overlap the previous pass; in percentage [0.00, 99.99]%
-        :type overlap:          float
-        :param invert:          If to invert the direction of the resulting isolated geometries
-        :type invert:           bool
-        :param env_iso_type:    can be either 0 = keep exteriors or 1 = keep interiors or 2 = keep all paths
-        :type env_iso_type:     int
-        :return:                Tuple made from list of isolating paths and list of not isolated Polygons
-        :rtype:                 tuple
+        :param geometry:            A list of Shapely Polygons to be isolated
+        :type geometry:             list
+        :param tooldia:             The tool diameter used to do the isolation
+        :type tooldia:              float
+        :param passes:              Number of passes that will made the isolation
+        :type passes:               int
+        :param overlap:             How much to overlap the previous pass; in percentage [0.00, 99.99]%
+        :type overlap:              float
+        :param invert:              If to invert the direction of the resulting isolated geometries
+        :type invert:               bool
+        :param env_iso_type:        can be either 0 = keep exteriors or 1 = keep interiors or 2 = keep all paths
+        :type env_iso_type:         int
+        :param prog_plot:           kind of plotting: "progressive" or "normal"
+        :type prog_plot:            str
+        :param prog_plot_handler:   method used to plot shapes if plot_prog is "proggressive"
+        :type prog_plot_handler:
+        :return:                    Tuple made from list of isolating paths and list of not isolated Polygons
+        :rtype:                     tuple
         """
         """
 
 
         isolated_geo = []
         isolated_geo = []
@@ -2819,7 +2851,10 @@ class ToolIsolation(AppTool, Gerber):
 
 
                 # if we had an intersection do nothing, else add the geo to the good pass isolations
                 # if we had an intersection do nothing, else add the geo to the good pass isolations
                 if intersect_flag is False:
                 if intersect_flag is False:
-                    good_pass_iso.append(geo.buffer(iso_offset))
+                    temp_geo = geo.buffer(iso_offset)
+                    good_pass_iso.append(temp_geo)
+                    if prog_plot == 'progressive':
+                        prog_plot_handler(temp_geo)
 
 
             if good_pass_iso:
             if good_pass_iso:
                 work_geo += good_pass_iso
                 work_geo += good_pass_iso

+ 2 - 0
CHANGELOG.md

@@ -23,6 +23,8 @@ CHANGELOG for FlatCAM beta
 - after using Isolation Tool it will switch automatically to the Geometry UI
 - after using Isolation Tool it will switch automatically to the Geometry UI
 - in Preferences replaced some widgets with a new one that combine a Slider with a Spinner (from David Robertson)
 - in Preferences replaced some widgets with a new one that combine a Slider with a Spinner (from David Robertson)
 - in Preferences replaced the widgets that sets colors with a compound one (from David Robertson)
 - in Preferences replaced the widgets that sets colors with a compound one (from David Robertson)
+- made Progressive plotting work in Isolation Tool
+- fix an issue with progressive plotted shapes not being deleted on the end of the job
 
 
 31.05.2020
 31.05.2020
 
 

+ 22 - 9
camlib.py

@@ -499,7 +499,7 @@ class Geometry(object):
         self.el_count = 0
         self.el_count = 0
 
 
         if self.app.is_legacy is False:
         if self.app.is_legacy is False:
-            self.temp_shapes = self.app.plotcanvas.new_shape_group()
+            self.temp_shapes = self.app.plotcanvas.new_shape_collection(layers=1)
         else:
         else:
             from AppGUI.PlotCanvasLegacy import ShapeCollectionLegacy
             from AppGUI.PlotCanvasLegacy import ShapeCollectionLegacy
             self.temp_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='camlib.geometry')
             self.temp_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='camlib.geometry')
@@ -915,7 +915,8 @@ class Geometry(object):
     #
     #
     #     return self.flat_geometry, self.flat_geometry_rtree
     #     return self.flat_geometry, self.flat_geometry_rtree
 
 
-    def isolation_geometry(self, offset, geometry=None, iso_type=2, corner=None, follow=None, passes=0):
+    def isolation_geometry(self, offset, geometry=None, iso_type=2, corner=None, follow=None, passes=0,
+                           prog_plot=False):
         """
         """
         Creates contours around geometry at a given
         Creates contours around geometry at a given
         offset distance.
         offset distance.
@@ -928,6 +929,7 @@ class Geometry(object):
                             0 = round; 1 = square; 2= beveled (line that connects the ends)
                             0 = round; 1 = square; 2= beveled (line that connects the ends)
         :param follow:      whether the geometry to be isolated is a follow_geometry
         :param follow:      whether the geometry to be isolated is a follow_geometry
         :param passes:      current pass out of possible multiple passes for which the isolation is done
         :param passes:      current pass out of possible multiple passes for which the isolation is done
+        :param prog_plot:   type of plotting: "normal" or "progressive"
         :return:            The buffered geometry.
         :return:            The buffered geometry.
         :rtype:             Shapely.MultiPolygon or Shapely.Polygon
         :rtype:             Shapely.MultiPolygon or Shapely.Polygon
         """
         """
@@ -960,10 +962,13 @@ class Geometry(object):
                     # graceful abort requested by the user
                     # graceful abort requested by the user
                     raise grace
                     raise grace
                 if offset == 0:
                 if offset == 0:
-                    geo_iso.append(pol)
+                    temp_geo = pol
                 else:
                 else:
                     corner_type = 1 if corner is None else corner
                     corner_type = 1 if corner is None else corner
-                    geo_iso.append(pol.buffer(offset, int(self.geo_steps_per_circle), join_style=corner_type))
+                    temp_geo = pol.buffer(offset, int(self.geo_steps_per_circle), join_style=corner_type)
+
+                geo_iso.append(temp_geo)
+
                 pol_nr += 1
                 pol_nr += 1
 
 
                 # activity view update
                 # activity view update
@@ -977,10 +982,12 @@ class Geometry(object):
             # taking care of the case when the self.solid_geometry is just a single Polygon, not a list or a
             # taking care of the case when the self.solid_geometry is just a single Polygon, not a list or a
             # MultiPolygon (not an iterable)
             # MultiPolygon (not an iterable)
             if offset == 0:
             if offset == 0:
-                geo_iso.append(working_geo)
+                temp_geo = working_geo
             else:
             else:
                 corner_type = 1 if corner is None else corner
                 corner_type = 1 if corner is None else corner
-                geo_iso.append(working_geo.buffer(offset, int(self.geo_steps_per_circle), join_style=corner_type))
+                temp_geo = working_geo.buffer(offset, int(self.geo_steps_per_circle), join_style=corner_type)
+
+            geo_iso.append(temp_geo)
 
 
         self.app.proc_container.update_view_text(' %s' % _("Buffering"))
         self.app.proc_container.update_view_text(' %s' % _("Buffering"))
         geo_iso = unary_union(geo_iso)
         geo_iso = unary_union(geo_iso)
@@ -989,17 +996,23 @@ class Geometry(object):
         # end of replaced block
         # end of replaced block
 
 
         if iso_type == 2:
         if iso_type == 2:
-            return geo_iso
+            ret_geo = geo_iso
         elif iso_type == 0:
         elif iso_type == 0:
             self.app.proc_container.update_view_text(' %s' % _("Get Exteriors"))
             self.app.proc_container.update_view_text(' %s' % _("Get Exteriors"))
-            return self.get_exteriors(geo_iso)
+            ret_geo = self.get_exteriors(geo_iso)
         elif iso_type == 1:
         elif iso_type == 1:
             self.app.proc_container.update_view_text(' %s' % _("Get Interiors"))
             self.app.proc_container.update_view_text(' %s' % _("Get Interiors"))
-            return self.get_interiors(geo_iso)
+            ret_geo =  self.get_interiors(geo_iso)
         else:
         else:
             log.debug("Geometry.isolation_geometry() --> Type of isolation not supported")
             log.debug("Geometry.isolation_geometry() --> Type of isolation not supported")
             return "fail"
             return "fail"
 
 
+        if prog_plot == 'progressive':
+            for elem in ret_geo:
+                self.plot_temp_shapes(elem)
+
+        return ret_geo
+
     def flatten_list(self, obj_list):
     def flatten_list(self, obj_list):
         for item in obj_list:
         for item in obj_list:
             if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):
             if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):