Przeglądaj źródła

- added for NCC Tool and Paint Tool a setting in the Preferences -> Tools --> (NCC Tool/ Paint Tool) that can set a progressive plotting (plot shapes as they are processed)

Marius Stanciu 6 lat temu
rodzic
commit
f38dab80e3
6 zmienionych plików z 262 dodań i 79 usunięć
  1. 37 34
      FlatCAMApp.py
  2. 1 0
      README.md
  3. 73 9
      camlib.py
  4. 23 1
      flatcamGUI/FlatCAMGUI.py
  5. 36 12
      flatcamTools/ToolNonCopperClear.py
  6. 92 23
      flatcamTools/ToolPaint.py

+ 37 - 34
FlatCAMApp.py

@@ -614,6 +614,7 @@ class App(QtCore.QObject):
             "tools_ncc_offset_choice": self.ui.tools_defaults_form.tools_ncc_group.ncc_choice_offset_cb,
             "tools_ncc_offset_value": self.ui.tools_defaults_form.tools_ncc_group.ncc_offset_spinner,
             "tools_nccref": self.ui.tools_defaults_form.tools_ncc_group.reference_radio,
+            "tools_ncc_plotting": self.ui.tools_defaults_form.tools_ncc_group.ncc_plotting_radio,
             "tools_nccmilling_type": self.ui.tools_defaults_form.tools_ncc_group.milling_type_radio,
             "tools_ncctool_type": self.ui.tools_defaults_form.tools_ncc_group.tool_type_radio,
             "tools_ncccutz": self.ui.tools_defaults_form.tools_ncc_group.cutz_entry,
@@ -637,6 +638,7 @@ class App(QtCore.QObject):
             "tools_selectmethod": self.ui.tools_defaults_form.tools_paint_group.selectmethod_combo,
             "tools_pathconnect": self.ui.tools_defaults_form.tools_paint_group.pathconnect_cb,
             "tools_paintcontour": self.ui.tools_defaults_form.tools_paint_group.contour_cb,
+            "tools_paint_plotting": self.ui.tools_defaults_form.tools_paint_group.paint_plotting_radio,
 
             # 2-sided Tool
             "tools_2sided_mirror_axis": self.ui.tools_defaults_form.tools_2sided_group.mirror_axis_radio,
@@ -1004,6 +1006,7 @@ class App(QtCore.QObject):
             "tools_ncc_offset_choice": False,
             "tools_ncc_offset_value": 0.0000,
             "tools_nccref": 'itself',
+            "tools_ncc_plotting": 'normal',
             "tools_nccmilling_type": 'cl',
             "tools_ncctool_type": 'V',
             "tools_ncccutz": -0.001968504,
@@ -1025,6 +1028,7 @@ class App(QtCore.QObject):
             "tools_selectmethod": "single",
             "tools_pathconnect": True,
             "tools_paintcontour": True,
+            "tools_paint_plotting": 'normal',
 
             "tools_2sided_mirror_axis": "X",
             "tools_2sided_axis_loc": "point",
@@ -5733,44 +5737,12 @@ class App(QtCore.QObject):
                     for obj in self.collection.get_list():
                         obj.plot()
                     self.plotcanvas.fit_view()
+                self.plotcanvas.vis_disconnect('mouse_press', self.on_set_zero_click)
 
             self.worker_task.emit({'fcn': worker_task, 'params': []})
 
-        def on_set_zero_click(event):
-            # this function will be available only for mouse left click
-
-            pos_canvas = self.plotcanvas.translate_coords(event.pos)
-            if event.button == 1:
-                if self.grid_status() == True:
-                    pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
-                else:
-                    pos = pos_canvas
-
-                x = 0 - pos[0]
-                y = 0 - pos[1]
-
-                def worker_task():
-                    with self.proc_container.new(_("Setting Origin...")):
-                        for obj in self.collection.get_list():
-                            obj.offset((x, y))
-                            self.object_changed.emit(obj)
-
-                            # Update the object bounding box options
-                            a, b, c, d = obj.bounds()
-                            obj.options['xmin'] = a
-                            obj.options['ymin'] = b
-                            obj.options['xmax'] = c
-                            obj.options['ymax'] = d
-                        self.inform.emit(_('[success] Origin set ...'))
-                        self.replot_signal.emit([])
-
-                self.worker_task.emit({'fcn': worker_task, 'params': []})
-
-                self.plotcanvas.vis_disconnect('mouse_press', on_set_zero_click)
-                self.should_we_save = True
-
         self.inform.emit(_('Click to set the origin ...'))
-        self.plotcanvas.vis_connect('mouse_press', on_set_zero_click)
+        self.plotcanvas.vis_connect('mouse_press', self.on_set_zero_click)
 
         # first disconnect it as it may have been used by something else
         try:
@@ -5779,6 +5751,37 @@ class App(QtCore.QObject):
             pass
         self.replot_signal[list].connect(origin_replot)
 
+    def on_set_zero_click(self, event):
+        # this function will be available only for mouse left click
+
+        pos_canvas = self.plotcanvas.translate_coords(event.pos)
+        if event.button == 1:
+            if self.grid_status() == True:
+                pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
+            else:
+                pos = pos_canvas
+
+            x = 0 - pos[0]
+            y = 0 - pos[1]
+
+            def worker_task():
+                with self.proc_container.new(_("Setting Origin...")):
+                    for obj in self.collection.get_list():
+                        obj.offset((x, y))
+                        self.object_changed.emit(obj)
+
+                        # Update the object bounding box options
+                        a, b, c, d = obj.bounds()
+                        obj.options['xmin'] = a
+                        obj.options['ymin'] = b
+                        obj.options['xmax'] = c
+                        obj.options['ymax'] = d
+                    self.inform.emit(_('[success] Origin set ...'))
+                    self.replot_signal.emit([])
+
+            self.worker_task.emit({'fcn': worker_task, 'params': []})
+            self.should_we_save = True
+
     def on_jump_to(self, custom_location=None, fit_center=True):
         """
         Jump to a location by setting the mouse cursor location

+ 1 - 0
README.md

@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
 
 - changed the triangulation type in VisPyVisuals for ShapeCollectionVisual class
 - added a setting in Preferences -> Gerber -> Gerber General named Buffering. If set to 'no' the Gerber objects load a lot more faster (perhaps 10 times faster than when set to 'full') but the visual look is not so great as all the aperture polygons can be seen
+- added for NCC Tool and Paint Tool a setting in the Preferences -> Tools --> (NCC Tool/ Paint Tool) that can set a progressive plotting (plot shapes as they are processed)
 
 8.09.2019
 

+ 73 - 9
camlib.py

@@ -117,10 +117,22 @@ class Geometry(object):
         self.old_disp_number = 0
         self.el_count = 0
 
+        self.temp_shapes = self.app.plotcanvas.new_shape_group()
+
         # if geo_steps_per_circle is None:
         #     geo_steps_per_circle = int(Geometry.defaults["geo_steps_per_circle"])
         # self.geo_steps_per_circle = geo_steps_per_circle
 
+    def plot_temp_shapes(self, element, color='red'):
+
+        try:
+            for sub_el in element:
+                self.plot_temp_shapes(sub_el)
+        except TypeError:  # Element is not iterable...
+            # self.add_shape(shape=element, color=color, visible=visible, layer=0)
+            self.temp_shapes.add(tolerance=float(self.app.defaults["global_tolerance"]),
+                                 shape=element, color=color, visible=True, layer=0)
+
     def make_index(self):
         self.flatten()
         self.index = FlatCAMRTree()
@@ -802,7 +814,8 @@ class Geometry(object):
         return boundary.difference(self.solid_geometry)
         
 
-    def clear_polygon(self, polygon, tooldia, steps_per_circle, overlap=0.15, connect=True, contour=True):
+    def clear_polygon(self, polygon, tooldia, steps_per_circle, overlap=0.15, connect=True, contour=True,
+                      prog_plot=False):
         """
         Creates geometry inside a polygon for a tool to cover
         the whole area.
@@ -818,6 +831,7 @@ class Geometry(object):
                         minimize tool lifts.
         :param contour: Paint around the edges. Inconsequential in
                         this painting method.
+        :param prog_plot: boolean; if Ture use the progressive plotting
         :return:
         """
 
@@ -870,16 +884,25 @@ class Geometry(object):
                         geoms.insert(p.exterior)
                         for i in p.interiors:
                             geoms.insert(i)
+                            if prog_plot:
+                                self.plot_temp_shapes(p)
 
                 # Not a Multipolygon. Must be a Polygon
                 except TypeError:
                     geoms.insert(current.exterior)
+                    if prog_plot:
+                        self.plot_temp_shapes(current.exterior)
                     for i in current.interiors:
                         geoms.insert(i)
+                        if prog_plot:
+                            self.plot_temp_shapes(i)
             else:
                 log.debug("camlib.Geometry.clear_polygon() --> Current Area is zero")
                 break
 
+        if prog_plot:
+            self.temp_shapes.redraw()
+
         # Optimization: Reduce lifts
         if connect:
             # log.debug("Reducing tool lifts...")
@@ -888,7 +911,7 @@ class Geometry(object):
         return geoms
 
     def clear_polygon2(self, polygon_to_clear, tooldia, steps_per_circle, seedpoint=None, overlap=0.15,
-                       connect=True, contour=True):
+                       connect=True, contour=True, prog_plot=False):
         """
         Creates geometry inside a polygon for a tool to cover
         the whole area.
@@ -907,6 +930,7 @@ class Geometry(object):
         :param contour: Cut countour inside the polygon.
         :return: List of toolpaths covering polygon.
         :rtype: FlatCAMRTreeStorage | None
+        :param prog_plot: boolean; if True use the progressive plotting
         """
 
         # log.debug("camlib.clear_polygon2()")
@@ -952,8 +976,15 @@ class Geometry(object):
                 try:
                     for p in path:
                         geoms.insert(p)
+                        if prog_plot:
+                            self.plot_temp_shapes(p)
                 except TypeError:
                     geoms.insert(path)
+                    if prog_plot:
+                        self.plot_temp_shapes(path)
+
+                if prog_plot:
+                    self.temp_shapes.redraw()
 
             radius += tooldia * (1 - overlap)
 
@@ -969,6 +1000,11 @@ class Geometry(object):
             # geoms += outer_edges + inner_edges
             for g in outer_edges + inner_edges:
                 geoms.insert(g)
+                if prog_plot:
+                    self.plot_temp_shapes(g)
+
+        if prog_plot:
+            self.temp_shapes.redraw()
 
         # Optimization connect touching paths
         # log.debug("Connecting paths...")
@@ -981,7 +1017,8 @@ class Geometry(object):
 
         return geoms
 
-    def clear_polygon3(self, polygon, tooldia, steps_per_circle, overlap=0.15, connect=True, contour=True):
+    def clear_polygon3(self, polygon, tooldia, steps_per_circle, overlap=0.15, connect=True, contour=True,
+                       prog_plot=False):
         """
         Creates geometry inside a polygon for a tool to cover
         the whole area.
@@ -995,6 +1032,7 @@ class Geometry(object):
         :param overlap: Tool path overlap percentage.
         :param connect: Connect lines to avoid tool lifts.
         :param contour: Paint around the edges.
+        :param prog_plot: boolean; if to use the progressive plotting
         :return:
         """
 
@@ -1008,11 +1046,13 @@ class Geometry(object):
         geoms = FlatCAMRTreeStorage()
         geoms.get_points = get_pts
 
-        lines = []
+        lines_trimmed = []
 
         # Bounding box
         left, bot, right, top = polygon.bounds
 
+        margin_poly = polygon.buffer(-tooldia / 1.99999999, (int(steps_per_circle)))
+
         # First line
         y = top - tooldia / 1.99999999
         while y > bot + tooldia / 1.999999999:
@@ -1021,20 +1061,33 @@ class Geometry(object):
                 raise FlatCAMApp.GracefulException
 
             line = LineString([(left, y), (right, y)])
-            lines.append(line)
+            line = line.intersection(margin_poly)
+            lines_trimmed.append(line)
             y -= tooldia * (1 - overlap)
+            if prog_plot:
+                self.plot_temp_shapes(line)
+                self.temp_shapes.redraw()
 
         # Last line
         y = bot + tooldia / 2
         line = LineString([(left, y), (right, y)])
-        lines.append(line)
+        line = line.intersection(margin_poly)
+        for ll in line:
+            lines_trimmed.append(ll)
+            if prog_plot:
+                self.plot_temp_shapes(line)
 
         # Combine
-        linesgeo = unary_union(lines)
+        # linesgeo = unary_union(lines)
 
         # Trim to the polygon
-        margin_poly = polygon.buffer(-tooldia / 1.99999999, (int(steps_per_circle)))
-        lines_trimmed = linesgeo.intersection(margin_poly)
+        # margin_poly = polygon.buffer(-tooldia / 1.99999999, (int(steps_per_circle)))
+        # lines_trimmed = linesgeo.intersection(margin_poly)
+
+        if prog_plot:
+            self.temp_shapes.redraw()
+
+        lines_trimmed = unary_union(lines_trimmed)
 
         # Add lines to storage
         try:
@@ -1048,13 +1101,24 @@ class Geometry(object):
         if contour:
             if isinstance(margin_poly, Polygon):
                 geoms.insert(margin_poly.exterior)
+                if prog_plot:
+                    self.plot_temp_shapes(margin_poly.exterior)
                 for ints in margin_poly.interiors:
                     geoms.insert(ints)
+                    if prog_plot:
+                        self.plot_temp_shapes(ints)
             elif isinstance(margin_poly, MultiPolygon):
                 for poly in margin_poly:
                     geoms.insert(poly.exterior)
+                    if prog_plot:
+                        self.plot_temp_shapes(poly.exterior)
                     for ints in poly.interiors:
                         geoms.insert(ints)
+                        if prog_plot:
+                            self.plot_temp_shapes(ints)
+
+        if prog_plot:
+            self.temp_shapes.redraw()
 
         # Optimization: Reduce lifts
         if connect:

+ 23 - 1
flatcamGUI/FlatCAMGUI.py

@@ -6663,6 +6663,17 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(reference_label, 15, 0)
         grid0.addWidget(self.reference_radio, 15, 1)
 
+        # ## Plotting type
+        self.ncc_plotting_radio = RadioSet([{'label': _('Normal'), 'value': 'normal'},
+                                            {"label": _("progressive"), "value": "progressive"}])
+        plotting_label = QtWidgets.QLabel('%s:' % _("NCC Plotting"))
+        plotting_label.setToolTip(
+            _("- 'Normal' -  normal plotting, done at the end of the NCC job\n"
+              "- 'Progressive' - after each shape is generated it will be plotted.")
+        )
+        grid0.addWidget(plotting_label, 16, 0)
+        grid0.addWidget(self.ncc_plotting_radio, 16, 1)
+
         self.layout.addStretch()
 
 
@@ -6949,15 +6960,26 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
               "- 'Reference Object' -  will do non copper clearing within the area\n"
               "specified by another object.")
         )
-        grid0.addWidget(selectlabel, 7, 0)
         self.selectmethod_combo = RadioSet([
             {"label": _("Single"), "value": "single"},
             {"label": _("Area"), "value": "area"},
             {"label": _("All"), "value": "all"},
             {"label": _("Ref."), "value": "ref"}
         ])
+        grid0.addWidget(selectlabel, 7, 0)
         grid0.addWidget(self.selectmethod_combo, 7, 1)
 
+        # ## Plotting type
+        self.paint_plotting_radio = RadioSet([{'label': _('Normal'), 'value': 'normal'},
+                                              {"label": _("progressive"), "value": "progressive"}])
+        plotting_label = QtWidgets.QLabel('%s:' % _("Paint Plotting"))
+        plotting_label.setToolTip(
+            _("- 'Normal' -  normal plotting, done at the end of the Paint job\n"
+              "- 'Progressive' - after each shape is generated it will be plotted.")
+        )
+        grid0.addWidget(plotting_label, 8, 0)
+        grid0.addWidget(self.paint_plotting_radio, 8, 1)
+
         self.layout.addStretch()
 
 

+ 36 - 12
flatcamTools/ToolNonCopperClear.py

@@ -1351,6 +1351,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
         contour = contour if contour else self.app.defaults["tools_ncccontour"]
         order = order if order else self.ncc_order_radio.get_value()
 
+        # determine if to use the progressive plotting
+        if self.app.defaults["tools_ncc_plotting"] == 'progressive':
+            prog_plot = True
+
         if tools_storage is not None:
             tools_storage = tools_storage
         else:
@@ -1703,13 +1707,16 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                     if isinstance(p, Polygon):
                                         if ncc_method == 'standard':
                                             cp = self.clear_polygon(p, tool, self.app.defaults["gerber_circle_steps"],
-                                                                    overlap=overlap, contour=contour, connect=connect)
+                                                                    overlap=overlap, contour=contour, connect=connect,
+                                                                    prog_plot=prog_plot)
                                         elif ncc_method == 'seed':
                                             cp = self.clear_polygon2(p, tool, self.app.defaults["gerber_circle_steps"],
-                                                                     overlap=overlap, contour=contour, connect=connect)
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=prog_plot)
                                         else:
                                             cp = self.clear_polygon3(p, tool, self.app.defaults["gerber_circle_steps"],
-                                                                     overlap=overlap, contour=contour, connect=connect)
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=prog_plot)
                                         if cp:
                                             cleared_geo += list(cp.get_objects())
                                     elif isinstance(p, MultiPolygon):
@@ -1719,17 +1726,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                                     cp = self.clear_polygon(pol, tool,
                                                                             self.app.defaults["gerber_circle_steps"],
                                                                             overlap=overlap, contour=contour,
-                                                                            connect=connect)
+                                                                            connect=connect,
+                                                                            prog_plot=prog_plot)
                                                 elif ncc_method == 'seed':
                                                     cp = self.clear_polygon2(pol, tool,
                                                                              self.app.defaults["gerber_circle_steps"],
                                                                              overlap=overlap, contour=contour,
-                                                                             connect=connect)
+                                                                             connect=connect,
+                                                                             prog_plot=prog_plot)
                                                 else:
                                                     cp = self.clear_polygon3(pol, tool,
                                                                              self.app.defaults["gerber_circle_steps"],
                                                                              overlap=overlap, contour=contour,
-                                                                             connect=connect)
+                                                                             connect=connect,
+                                                                             prog_plot=prog_plot)
                                                 if cp:
                                                     cleared_geo += list(cp.get_objects())
                                 except Exception as e:
@@ -1770,6 +1780,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
                         else:
                             log.debug("There are no geometries in the cleared polygon.")
 
+            # clean the progressive plotted shapes if it was used
+            if self.app.defaults["tools_ncc_plotting"] == 'progressive':
+                self.temp_shapes.clear(update=True)
+
             # delete tools with empty geometry
             keys_to_delete = []
             # look for keys in the tools_storage dict that have 'solid_geometry' values empty
@@ -2043,15 +2057,18 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                         if ncc_method == 'standard':
                                             cp = self.clear_polygon(p, tool_used,
                                                                     self.app.defaults["gerber_circle_steps"],
-                                                                    overlap=overlap, contour=contour, connect=connect)
+                                                                    overlap=overlap, contour=contour, connect=connect,
+                                                                    prog_plot=prog_plot)
                                         elif ncc_method == 'seed':
                                             cp = self.clear_polygon2(p, tool_used,
                                                                      self.app.defaults["gerber_circle_steps"],
-                                                                     overlap=overlap, contour=contour, connect=connect)
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=prog_plot)
                                         else:
                                             cp = self.clear_polygon3(p, tool_used,
                                                                      self.app.defaults["gerber_circle_steps"],
-                                                                     overlap=overlap, contour=contour, connect=connect)
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=prog_plot)
                                         cleared_geo.append(list(cp.get_objects()))
                                     except Exception as e:
                                         log.warning("Polygon can't be cleared. %s" % str(e))
@@ -2066,17 +2083,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                                     cp = self.clear_polygon(poly, tool_used,
                                                                             self.app.defaults["gerber_circle_steps"],
                                                                             overlap=overlap, contour=contour,
-                                                                            connect=connect)
+                                                                            connect=connect,
+                                                                            prog_plot=prog_plot)
                                                 elif ncc_method == 'seed':
                                                     cp = self.clear_polygon2(poly, tool_used,
                                                                              self.app.defaults["gerber_circle_steps"],
                                                                              overlap=overlap, contour=contour,
-                                                                             connect=connect)
+                                                                             connect=connect,
+                                                                             prog_plot=prog_plot)
                                                 else:
                                                     cp = self.clear_polygon3(poly, tool_used,
                                                                              self.app.defaults["gerber_circle_steps"],
                                                                              overlap=overlap, contour=contour,
-                                                                             connect=connect)
+                                                                             connect=connect,
+                                                                             prog_plot=prog_plot)
                                                 cleared_geo.append(list(cp.get_objects()))
                                             except Exception as e:
                                                 log.warning("Polygon can't be cleared. %s" % str(e))
@@ -2138,6 +2158,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
             geo_obj.multigeo = True
             geo_obj.options["cnctooldia"] = str(tool)
 
+            # clean the progressive plotted shapes if it was used
+            if self.app.defaults["tools_ncc_plotting"] == 'progressive':
+                self.temp_shapes.clear(update=True)
+
             # check to see if geo_obj.tools is empty
             # it will be updated only if there is a solid_geometry for tools
             if geo_obj.tools:

+ 92 - 23
flatcamTools/ToolPaint.py

@@ -518,6 +518,8 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.paintcontour_cb.set_value(self.default_data["paintcontour"])
         self.paintoverlap_entry.set_value(self.default_data["paintoverlap"])
 
+        # make the default object type, "Geometry"
+        self.type_obj_combo.setCurrentIndex(2)
         # updated units
         self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
 
@@ -1204,6 +1206,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                     self.app.inform.emit('[ERROR_NOTCL] %s' %
                                          _("Wrong value format entered, use a number."))
                     return
+        # determine if to use the progressive plotting
+        if self.app.defaults["tools_paint_plotting"] == 'progressive':
+            prog_plot = True
 
         # No polygon?
         if poly is None:
@@ -1263,7 +1268,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                     overlap=over,
                                                     contour=cont,
-                                                    connect=conn)
+                                                    connect=conn,
+                                                    prog_plot=prog_plot)
 
                     elif paint_method == "lines":
                         # Type(cp) == FlatCAMRTreeStorage | None
@@ -1272,7 +1278,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                     overlap=over,
                                                     contour=cont,
-                                                    connect=conn)
+                                                    connect=conn,
+                                                    prog_plot=prog_plot)
 
                     else:
                         # Type(cp) == FlatCAMRTreeStorage | None
@@ -1281,7 +1288,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                    steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                    overlap=over,
                                                    contour=cont,
-                                                   connect=conn)
+                                                   connect=conn,
+                                                    prog_plot=prog_plot)
                 except FlatCAMApp.GracefulException:
                     return "fail"
                 except Exception as e:
@@ -1349,6 +1357,10 @@ class ToolPaint(FlatCAMTool, Gerber):
                 tools_storage[current_uid]['data']['name'] = name
                 total_geometry[:] = []
 
+            # clean the progressive plotted shapes if it was used
+            if self.app.defaults["tools_paint_plotting"] == 'progressive':
+                self.temp_shapes.clear(update=True)
+
             # delete tools with empty geometry
             keys_to_delete = []
             # look for keys in the tools_storage dict that have 'solid_geometry' values empty
@@ -1462,6 +1474,10 @@ class ToolPaint(FlatCAMTool, Gerber):
                                          _("Wrong value format entered, use a number."))
                     return
 
+        # determine if to use the progressive plotting
+        if self.app.defaults["tools_paint_plotting"] == 'progressive':
+            prog_plot = True
+
         proc = self.app.proc_container.new(_("Painting polygons..."))
         name = outname if outname is not None else self.obj_name + "_paint"
 
@@ -1603,7 +1619,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over,
                                                      contour=cont,
-                                                     connect=conn)
+                                                     connect=conn,
+                                                     prog_plot=prog_plot)
 
                         elif paint_method == "lines":
                             # Type(cp) == FlatCAMRTreeStorage | None
@@ -1612,7 +1629,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over,
                                                      contour=cont,
-                                                     connect=conn)
+                                                     connect=conn,
+                                                     prog_plot=prog_plot)
 
                         else:
                             # Type(cp) == FlatCAMRTreeStorage | None
@@ -1621,7 +1639,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                     overlap=over,
                                                     contour=cont,
-                                                    connect=conn)
+                                                    connect=conn,
+                                                    prog_plot=prog_plot)
 
                         if cp is not None:
                             total_geometry += list(cp.get_objects())
@@ -1651,6 +1670,10 @@ class ToolPaint(FlatCAMTool, Gerber):
                 tools_storage[current_uid]['data']['name'] = name
                 total_geometry[:] = []
 
+            # clean the progressive plotted shapes if it was used
+            if self.app.defaults["tools_paint_plotting"] == 'progressive':
+                self.temp_shapes.clear(update=True)
+
             # delete tools with empty geometry
             keys_to_delete = []
             # look for keys in the tools_storage dict that have 'solid_geometry' values empty
@@ -1741,19 +1764,22 @@ class ToolPaint(FlatCAMTool, Gerber):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
-                                                    overlap=over, contour=cont, connect=conn)
+                                                    overlap=over, contour=cont, connect=conn,
+                                                    prog_plot=prog_plot)
 
                         elif paint_method == "seed":
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
-                                                     overlap=over, contour=cont, connect=conn)
+                                                     overlap=over, contour=cont, connect=conn,
+                                                     prog_plot=prog_plot)
 
                         elif paint_method == "lines":
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
-                                                     overlap=over, contour=cont, connect=conn)
+                                                     overlap=over, contour=cont, connect=conn,
+                                                     prog_plot=prog_plot)
 
                         if cp is not None:
                             cleared_geo += list(cp.get_objects())
@@ -1796,6 +1822,10 @@ class ToolPaint(FlatCAMTool, Gerber):
             geo_obj.tools.clear()
             geo_obj.tools = dict(tools_storage)
 
+            # clean the progressive plotted shapes if it was used
+            if self.app.defaults["tools_paint_plotting"] == 'progressive':
+                self.temp_shapes.clear(update=True)
+
             # test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
             has_solid_geo = 0
             for tooluid in geo_obj.tools:
@@ -1882,6 +1912,10 @@ class ToolPaint(FlatCAMTool, Gerber):
                                          _("Wrong value format entered, use a number."))
                     return
 
+        # determine if to use the progressive plotting
+        if self.app.defaults["tools_paint_plotting"] == 'progressive':
+            prog_plot = True
+
         proc = self.app.proc_container.new(_("Painting polygons..."))
         name = outname if outname is not None else self.obj_name + "_paint"
 
@@ -1960,15 +1994,21 @@ class ToolPaint(FlatCAMTool, Gerber):
 
             # this is were heavy lifting is done and creating the geometry to be painted
             geo_to_paint = []
-            if not isinstance(obj.solid_geometry, list):
-                target_geo = [obj.solid_geometry]
-            else:
-                target_geo = obj.solid_geometry
+            target_geo = obj.solid_geometry
 
-            for poly in target_geo:
-                new_pol = poly.intersection(sel_obj)
+            if self.app.defaults["tools_paint_plotting"] == 'progressive':
+                target_geo = MultiPolygon(target_geo).buffer(0)
+
+            try:
+                for poly in target_geo:
+                    new_pol = poly.intersection(sel_obj)
+                    geo_to_paint.append(new_pol)
+            except TypeError:
+                new_pol = target_geo.intersection(sel_obj)
                 geo_to_paint.append(new_pol)
 
+            painted_area = recurse(geo_to_paint)
+
             try:
                 a, b, c, d = self.paint_bounds(geo_to_paint)
                 geo_obj.options['xmin'] = a
@@ -1999,7 +2039,6 @@ class ToolPaint(FlatCAMTool, Gerber):
                         current_uid = int(k)
                         break
 
-                painted_area = recurse(geo_to_paint)
                 # variables to display the percentage of work done
                 geo_len = len(painted_area)
                 disp_number = 0
@@ -2022,7 +2061,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over,
                                                      contour=cont,
-                                                     connect=conn)
+                                                     connect=conn,
+                                                     prog_plot=prog_plot)
 
                         elif paint_method == "lines":
                             # Type(cp) == FlatCAMRTreeStorage | None
@@ -2031,7 +2071,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over,
                                                      contour=cont,
-                                                     connect=conn)
+                                                     connect=conn,
+                                                     prog_plot=prog_plot)
 
                         else:
                             # Type(cp) == FlatCAMRTreeStorage | None
@@ -2040,7 +2081,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                     overlap=over,
                                                     contour=cont,
-                                                    connect=conn)
+                                                    connect=conn,
+                                                     prog_plot=prog_plot)
 
                         if cp is not None:
                             total_geometry += list(cp.get_objects())
@@ -2069,6 +2111,10 @@ class ToolPaint(FlatCAMTool, Gerber):
                 tools_storage[current_uid]['data']['name'] = name
                 total_geometry[:] = []
 
+            # clean the progressive plotted shapes if it was used
+            if self.app.defaults["tools_paint_plotting"] == 'progressive':
+                self.temp_shapes.clear(update=True)
+
             # delete tools with empty geometry
             keys_to_delete = []
             # look for keys in the tools_storage dict that have 'solid_geometry' values empty
@@ -2121,6 +2167,23 @@ class ToolPaint(FlatCAMTool, Gerber):
             current_uid = int(1)
             geo_obj.solid_geometry = []
 
+            # this is were heavy lifting is done and creating the geometry to be painted
+            geo_to_paint = []
+            target_geo = obj.solid_geometry
+
+            if self.app.defaults["tools_paint_plotting"] == 'progressive':
+                target_geo = MultiPolygon(target_geo).buffer(0)
+
+            try:
+                for poly in target_geo:
+                    new_pol = poly.intersection(sel_obj)
+                    geo_to_paint.append(new_pol)
+            except TypeError:
+                new_pol = target_geo.intersection(sel_obj)
+                geo_to_paint.append(new_pol)
+
+            painted_area = recurse(geo_to_paint)
+
             try:
                 a, b, c, d = obj.bounds()
                 geo_obj.options['xmin'] = a
@@ -2141,7 +2204,6 @@ class ToolPaint(FlatCAMTool, Gerber):
                 )
                 app_obj.proc_container.update_view_text(' %d%%' % 0)
 
-                painted_area = recurse(obj.solid_geometry)
                 # variables to display the percentage of work done
                 geo_len = len(painted_area)
                 disp_number = 0
@@ -2159,19 +2221,22 @@ class ToolPaint(FlatCAMTool, Gerber):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
-                                                    overlap=over, contour=cont, connect=conn)
+                                                    overlap=over, contour=cont, connect=conn,
+                                                    prog_plot=prog_plot)
 
                         elif paint_method == "seed":
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
-                                                     overlap=over, contour=cont, connect=conn)
+                                                     overlap=over, contour=cont, connect=conn,
+                                                     prog_plot=prog_plot)
 
                         elif paint_method == "lines":
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
-                                                     overlap=over, contour=cont, connect=conn)
+                                                     overlap=over, contour=cont, connect=conn,
+                                                     prog_plot=prog_plot)
 
                         if cp is not None:
                             cleared_geo += list(cp.get_objects())
@@ -2213,6 +2278,10 @@ class ToolPaint(FlatCAMTool, Gerber):
             geo_obj.tools.clear()
             geo_obj.tools = dict(self.paint_tools)
 
+            # clean the progressive plotted shapes if it was used
+            if self.app.defaults["tools_paint_plotting"] == 'progressive':
+                self.temp_shapes.clear(update=True)
+
             # test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
             has_solid_geo = 0
             for tooluid in geo_obj.tools: