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

- code cleanup in Isolation Tool

Marius Stanciu 5 лет назад
Родитель
Сommit
f956373ad0
1 измененных файлов с 7 добавлено и 901 удалено
  1. 7 901
      AppTools/ToolIsolation.py

+ 7 - 901
AppTools/ToolIsolation.py

@@ -12,20 +12,17 @@ from AppGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, F
     FCComboBox, OptionalHideInputSection, FCSpinner
 from AppParsers.ParseGerber import Gerber
 
-from camlib import grace
-
 from copy import deepcopy
 
 import numpy as np
 import math
-from shapely.geometry import base
+
 from shapely.ops import cascaded_union
 from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing
 
 from matplotlib.backend_bases import KeyEvent as mpl_key_event
 
 import logging
-import traceback
 import gettext
 import AppTranslation as fcTranslate
 import builtins
@@ -1603,110 +1600,6 @@ class ToolIsolation(AppTool, Gerber):
 
         self.app.worker_task.emit({'fcn': buffer_task, 'params': []})
 
-    def on_isolate_click(self):
-        """
-        Slot for clicking signal of the self.generate_iso_button
-
-        :return: None
-        """
-
-        # init values for the next usage
-        self.reset_usage()
-
-        self.app.defaults.report_usage("on_paint_button_click")
-
-        self.grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
-        self.obj_name = self.object_combo.currentText()
-
-        # Get source object.
-        try:
-            self.grb_obj = self.app.collection.get_by_name(self.obj_name)
-        except Exception as e:
-            self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(self.obj_name)))
-            return "Could not retrieve object: %s with error: %s" % (self.obj_name, str(e))
-
-        if self.grb_obj is None:
-            self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(self.obj_name)))
-            return
-
-        # use the selected tools in the tool table; get diameters for isolation
-        self.iso_dia_list = []
-        # use the selected tools in the tool table; get diameters for non-copper clear
-        self.ncc_dia_list = []
-
-        if self.tools_table.selectedItems():
-            for x in self.tools_table.selectedItems():
-                try:
-                    self.tooldia = float(self.tools_table.item(x.row(), 1).text())
-                except ValueError:
-                    # try to convert comma to decimal point. if it's still not working error message and return
-                    try:
-                        self.tooldia = float(self.tools_table.item(x.row(), 1).text().replace(',', '.'))
-                    except ValueError:
-                        self.app.inform.emit('[ERROR_NOTCL] %s' % _("Wrong Tool Dia value format entered, "
-                                                                    "use a number."))
-                        continue
-
-                self.iso_dia_list.append(self.tooldia)
-        else:
-            self.app.inform.emit('[ERROR_NOTCL] %s' % _("No selected tools in Tool Table."))
-            return
-
-        self.o_name = '%s_ncc' % self.obj_name
-
-        self.select_method = self.select_combo.get_value()
-        if self.select_method == _('Itself'):
-            self.bound_obj_name = self.object_combo.currentText()
-            # Get source object.
-            try:
-                self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
-            except Exception as e:
-                self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), self.bound_obj_name))
-                return "Could not retrieve object: %s with error: %s" % (self.bound_obj_name, str(e))
-
-            self.clear_copper(ncc_obj=self.grb_obj,
-                              ncctooldia=self.ncc_dia_list,
-                              isotooldia=self.iso_dia_list,
-                              outname=self.o_name)
-        elif self.select_method == _("Area Selection"):
-            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
-
-            if self.app.is_legacy is False:
-                self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
-                self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
-                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
-            else:
-                self.app.plotcanvas.graph_event_disconnect(self.app.mp)
-                self.app.plotcanvas.graph_event_disconnect(self.app.mm)
-                self.app.plotcanvas.graph_event_disconnect(self.app.mr)
-
-            self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
-            self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
-            self.kp = self.app.plotcanvas.graph_event_connect('key_press', self.on_key_press)
-
-        elif self.select_method == _("Reference Object"):
-            self.bound_obj_name = self.reference_combo.currentText()
-            # Get source object.
-            try:
-                self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
-            except Exception as e:
-                self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), self.bound_obj_name))
-                return "Could not retrieve object: %s. Error: %s" % (self.bound_obj_name, str(e))
-
-            self.clear_copper(ncc_obj=self.grb_obj,
-                              sel_obj=self.bound_obj,
-                              ncctooldia=self.ncc_dia_list,
-                              isotooldia=self.iso_dia_list,
-                              outname=self.o_name)
-
-
-
-
-    # ###########################################
-    # ###########################################
-    # ###########################################
-    # ###########################################
-
     def on_iso_button_click(self, *args):
 
         self.obj_name = self.object_combo.currentText()
@@ -1799,7 +1692,7 @@ class ToolIsolation(AppTool, Gerber):
             else:
                 self.grid_status_memory = False
 
-            self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_click_release)
+            self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_poly_mouse_click_release)
             self.kp = self.app.plotcanvas.graph_event_connect('key_press', self.on_key_press)
 
             if self.app.is_legacy is False:
@@ -1941,8 +1834,8 @@ class ToolIsolation(AppTool, Gerber):
                 if len(self.iso_tools) > 1:
                     geo_obj.multigeo = True
                 else:
-                    passes = float(self.iso_tools[0]['data']['tools_iso_passes'])
-                    geo_obj.multigeo = True if passes > 1 else False
+                    passes_no = float(self.iso_tools[0]['data']['tools_iso_passes'])
+                    geo_obj.multigeo = True if passes_no > 1 else False
 
                 # detect if solid_geometry is empty and this require list flattening which is "heavy"
                 # or just looking in the lists (they are one level depth) and if any is not empty
@@ -2096,7 +1989,7 @@ class ToolIsolation(AppTool, Gerber):
                             return 'fail'
                         else:
                             fc_obj.inform.emit('[success] %s: %s' %
-                                                (_("Isolation geometry created"), geo_obj.options["name"]))
+                                               (_("Isolation geometry created"), geo_obj.options["name"]))
                         geo_obj.multigeo = False
 
                     # TODO: Do something if this is None. Offer changing name?
@@ -2215,7 +2108,7 @@ class ToolIsolation(AppTool, Gerber):
                         new_geometry.append(new_geo)
         return new_geometry
 
-    def on_mouse_click_release(self, event):
+    def on_poly_mouse_click_release(self, event):
         if self.app.is_legacy is False:
             event_pos = event.pos
             right_button = 2
@@ -2278,7 +2171,7 @@ class ToolIsolation(AppTool, Gerber):
                 self.app.ui.grid_snap_btn.trigger()
 
             if self.app.is_legacy is False:
-                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_click_release)
+                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_poly_mouse_click_release)
                 self.app.plotcanvas.graph_event_disconnect('key_press', self.on_key_pres)
             else:
                 self.app.plotcanvas.graph_event_disconnect(self.mr)
@@ -2365,14 +2258,6 @@ class ToolIsolation(AppTool, Gerber):
         else:
             self.app.inform.emit(_("No polygon in selection."))
 
-    # ###########################################
-    # ###########################################
-    # ###########################################
-    # ###########################################
-
-
-
-
     # To be called after clicking on the plot.
     def on_mouse_release(self, event):
         if self.app.is_legacy is False:
@@ -2605,785 +2490,6 @@ class ToolIsolation(AppTool, Gerber):
             self.delete_moving_selection_shape()
             self.delete_tool_selection_shape()
 
-    def get_tool_empty_area(self, name, ncc_obj, geo_obj, isotooldia, has_offset, ncc_offset, ncc_margin,
-                            bounding_box, tools_storage):
-        """
-        Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry.
-
-        :param name:
-        :param ncc_obj:
-        :param geo_obj:
-        :param isotooldia:
-        :param has_offset:
-        :param ncc_offset:
-        :param ncc_margin:
-        :param bounding_box:
-        :param tools_storage:
-        :return:
-        """
-
-        log.debug("NCC Tool. Calculate 'empty' area.")
-        self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
-
-        # a flag to signal that the isolation is broken by the bounding box in 'area' and 'box' cases
-        # will store the number of tools for which the isolation is broken
-        warning_flag = 0
-
-        if ncc_obj.kind == 'gerber' and isotooldia:
-            isolated_geo = []
-
-            # unfortunately for this function to work time efficient,
-            # if the Gerber was loaded without buffering then it require the buffering now.
-            # TODO 'buffering status' should be a property of the object not the project property
-            if self.app.defaults['gerber_buffering'] == 'no':
-                self.solid_geometry = ncc_obj.solid_geometry.buffer(0)
-            else:
-                self.solid_geometry = ncc_obj.solid_geometry
-
-            # if milling type is climb then the move is counter-clockwise around features
-            milling_type = self.milling_type_radio.get_value()
-
-            for tool_iso in isotooldia:
-                new_geometry = []
-
-                if milling_type == 'cl':
-                    isolated_geo = self.generate_envelope(tool_iso / 2, 1)
-                else:
-                    isolated_geo = self.generate_envelope(tool_iso / 2, 0)
-
-                if isolated_geo == 'fail':
-                    self.app.inform.emit('[ERROR_NOTCL] %s %s' %
-                                         (_("Isolation geometry could not be generated."), str(tool_iso)))
-                    continue
-
-                if ncc_margin < tool_iso:
-                    self.app.inform.emit('[WARNING_NOTCL] %s' % _("Isolation geometry is broken. Margin is less "
-                                                                  "than isolation tool diameter."))
-                try:
-                    for geo_elem in isolated_geo:
-                        # provide the app with a way to process the GUI events when in a blocking loop
-                        QtWidgets.QApplication.processEvents()
-
-                        if self.app.abort_flag:
-                            # graceful abort requested by the user
-                            raise grace
-
-                        if isinstance(geo_elem, Polygon):
-                            for ring in self.poly2rings(geo_elem):
-                                new_geo = ring.intersection(bounding_box)
-                                if new_geo and 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.intersection(bounding_box)
-                                    if new_geo and not new_geo.is_empty:
-                                        new_geometry.append(new_geo)
-                        elif isinstance(geo_elem, LineString):
-                            new_geo = geo_elem.intersection(bounding_box)
-                            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.intersection(bounding_box)
-                                if new_geo and not new_geo.is_empty:
-                                    new_geometry.append(new_geo)
-                except TypeError:
-                    if isinstance(isolated_geo, Polygon):
-                        for ring in self.poly2rings(isolated_geo):
-                            new_geo = ring.intersection(bounding_box)
-                            if new_geo:
-                                if not new_geo.is_empty:
-                                    new_geometry.append(new_geo)
-                    elif isinstance(isolated_geo, LineString):
-                        new_geo = isolated_geo.intersection(bounding_box)
-                        if new_geo and not new_geo.is_empty:
-                            new_geometry.append(new_geo)
-                    elif isinstance(isolated_geo, MultiLineString):
-                        for line_elem in isolated_geo:
-                            new_geo = line_elem.intersection(bounding_box)
-                            if new_geo and not new_geo.is_empty:
-                                new_geometry.append(new_geo)
-
-                # a MultiLineString geometry element will show that the isolation is broken for this tool
-                for geo_e in new_geometry:
-                    if type(geo_e) == MultiLineString:
-                        warning_flag += 1
-                        break
-
-                current_uid = 0
-                for k, v in tools_storage.items():
-                    if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
-                                                                                        tool_iso)):
-                        current_uid = int(k)
-                        # add the solid_geometry to the current too in self.paint_tools dictionary
-                        # and then reset the temporary list that stored that solid_geometry
-                        v['solid_geometry'] = deepcopy(new_geometry)
-                        v['data']['name'] = name
-                        break
-                geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
-
-            sol_geo = cascaded_union(isolated_geo)
-            if has_offset is True:
-                self.app.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
-                sol_geo = sol_geo.buffer(distance=ncc_offset)
-                self.app.inform.emit('[success] %s ...' % _("Buffering finished"))
-
-            empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
-            if empty == 'fail':
-                return 'fail'
-
-            if empty.is_empty:
-                self.app.inform.emit('[ERROR_NOTCL] %s' %
-                                     _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
-                return 'fail'
-        else:
-            self.app.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
-            return 'fail'
-
-        if type(empty) is Polygon:
-            empty = MultiPolygon([empty])
-
-        log.debug("NCC Tool. Finished calculation of 'empty' area.")
-        self.app.inform.emit(_("NCC Tool. Finished calculation of 'empty' area."))
-
-        return empty, warning_flag
-
-    def clear_copper(self, ncc_obj, sel_obj=None, ncctooldia=None, isotooldia=None, outname=None, order=None,
-                     tools_storage=None, run_threaded=True):
-        """
-        Clear the excess copper from the entire object.
-
-        :param ncc_obj:         ncc cleared object
-        :param sel_obj:
-        :param ncctooldia:      a tuple or single element made out of diameters of the tools to be used to ncc clear
-        :param isotooldia:      a tuple or single element made out of diameters of the tools to be used for isolation
-        :param outname:         name of the resulting object
-        :param order:           Tools order
-        :param tools_storage:   whether to use the current tools_storage self.iso_tools or a different one.
-                                Usage of the different one is related to when this function is called
-                                from a TcL command.
-
-        :param run_threaded:    If True the method will be run in a threaded way suitable for GUI usage; if False
-                                it will run non-threaded for TclShell usage
-        :return:
-        """
-        log.debug("Executing the handler ...")
-
-        if run_threaded:
-            proc = self.app.proc_container.new(_("Non-Copper clearing ..."))
-        else:
-            self.app.proc_container.view.set_busy(_("Non-Copper clearing ..."))
-            QtWidgets.QApplication.processEvents()
-
-        # ######################################################################################################
-        # ######################### Read the parameters ########################################################
-        # ######################################################################################################
-
-        units = self.app.defaults['units']
-        order = order if order else self.order_radio.get_value()
-        ncc_select = self.select_combo.get_value()
-        rest_machining_choice = self.rest_cb.get_value()
-
-        # determine if to use the progressive plotting
-        prog_plot = True if self.app.defaults["tools_iso_plotting"] == 'progressive' else False
-        tools_storage = tools_storage if tools_storage is not None else self.iso_tools
-
-        # ######################################################################################################
-        # # Read the tooldia parameter and create a sorted list out them - they may be more than one diameter ##
-        # ######################################################################################################
-        sorted_clear_tools = []
-        if ncctooldia is not None:
-            try:
-                sorted_clear_tools = [float(eval(dia)) for dia in ncctooldia.split(",") if dia != '']
-            except AttributeError:
-                if not isinstance(ncctooldia, list):
-                    sorted_clear_tools = [float(ncctooldia)]
-                else:
-                    sorted_clear_tools = ncctooldia
-        else:
-            # for row in range(self.tools_table.rowCount()):
-            #     if self.tools_table.cellWidget(row, 1).currentText() == 'clear_op':
-            #         sorted_clear_tools.append(float(self.tools_table.item(row, 1).text()))
-            for tooluid in self.iso_tools:
-                if self.iso_tools[tooluid]['data']['tools_nccoperation'] == 'clear':
-                    sorted_clear_tools.append(self.iso_tools[tooluid]['tooldia'])
-
-        # ########################################################################################################
-        # set the name for the future Geometry object
-        # I do it here because it is also stored inside the gen_clear_area() and gen_clear_area_rest() methods
-        # ########################################################################################################
-        name = outname if outname is not None else self.obj_name + "_ncc"
-
-        # ########################################################################################################
-        # ######### #####Initializes the new geometry object #####################################################
-        # ########################################################################################################
-        def gen_clear_area(geo_obj, app_obj):
-            log.debug("NCC Tool. Normal copper clearing task started.")
-            self.app.inform.emit(_("NCC Tool. Finished non-copper polygons. Normal copper clearing task started."))
-
-            # provide the app with a way to process the GUI events when in a blocking loop
-            if not run_threaded:
-                QtWidgets.QApplication.processEvents()
-
-            # a flag to signal that the isolation is broken by the bounding box in 'area' and 'box' cases
-            # will store the number of tools for which the isolation is broken
-            warning_flag = 0
-
-            if order == 'fwd':
-                sorted_clear_tools.sort(reverse=False)
-            elif order == 'rev':
-                sorted_clear_tools.sort(reverse=True)
-            else:
-                pass
-
-            cleared_geo = []
-            cleared = MultiPolygon()  # Already cleared area
-            app_obj.poly_not_cleared = False  # flag for polygons not cleared
-
-            # Generate area for each tool
-            offset = sum(sorted_clear_tools)
-            current_uid = int(1)
-            # try:
-            #     tool = eval(self.app.defaults["tools_ncctools"])[0]
-            # except TypeError:
-            #     tool = eval(self.app.defaults["tools_ncctools"])
-
-            if ncc_select == _("Reference Object"):
-                bbox_geo, bbox_kind = self.calculate_bounding_box(
-                    ncc_obj=ncc_obj, box_obj=sel_obj, ncc_select=ncc_select)
-            else:
-                bbox_geo, bbox_kind = self.calculate_bounding_box(ncc_obj=ncc_obj, ncc_select=ncc_select)
-
-            if bbox_geo is None and bbox_kind is None:
-                self.app.inform.emit("[ERROR_NOTCL] %s" % _("NCC Tool failed creating bounding box."))
-                return "fail"
-
-            # COPPER CLEARING with tools marked for CLEAR#
-            for tool in sorted_clear_tools:
-                log.debug("Starting geometry processing for tool: %s" % str(tool))
-                if self.app.abort_flag:
-                    # graceful abort requested by the user
-                    raise grace
-
-                # provide the app with a way to process the GUI events when in a blocking loop
-                if not run_threaded:
-                    QtWidgets.QApplication.processEvents()
-
-                app_obj.inform.emit('[success] %s = %s%s %s' % (
-                    _('NCC Tool clearing with tool diameter'), str(tool), units.lower(), _('started.'))
-                                    )
-                app_obj.proc_container.update_view_text(' %d%%' % 0)
-
-                tool_uid = 0  # find the current tool_uid
-                for k, v in self.iso_tools.items():
-                    if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool)):
-                        tool_uid = int(k)
-                        break
-
-                # parameters that are particular to the current tool
-                ncc_overlap = float(self.iso_tools[tool_uid]["data"]["tools_nccoverlap"]) / 100.0
-                ncc_margin = float(self.iso_tools[tool_uid]["data"]["tools_nccmargin"])
-                ncc_method = self.iso_tools[tool_uid]["data"]["tools_nccmethod"]
-                ncc_connect = self.iso_tools[tool_uid]["data"]["tools_nccconnect"]
-                ncc_contour = self.iso_tools[tool_uid]["data"]["tools_ncccontour"]
-                has_offset = self.iso_tools[tool_uid]["data"]["tools_ncc_offset_choice"]
-                ncc_offset = float(self.iso_tools[tool_uid]["data"]["tools_ncc_offset_value"])
-
-                # Get remaining tools offset
-                offset -= (tool - 1e-12)
-
-                # Bounding box for current tool
-                bbox = self.apply_margin_to_bounding_box(bbox=bbox_geo, box_kind=bbox_kind,
-                                                         ncc_select=ncc_select, ncc_margin=ncc_margin)
-
-                # Area to clear
-                empty, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj,
-                                                               isotooldia=isotooldia, ncc_margin=ncc_margin,
-                                                               has_offset=has_offset, ncc_offset=ncc_offset,
-                                                               tools_storage=tools_storage, bounding_box=bbox)
-
-                area = empty.buffer(-offset)
-                try:
-                    area = area.difference(cleared)
-                except Exception:
-                    continue
-
-                # Transform area to MultiPolygon
-                if isinstance(area, Polygon):
-                    area = MultiPolygon([area])
-
-                # variables to display the percentage of work done
-                geo_len = len(area.geoms)
-
-                old_disp_number = 0
-                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
-
-                cleared_geo[:] = []
-                if area.geoms:
-                    if len(area.geoms) > 0:
-                        pol_nr = 0
-                        for p in area.geoms:
-                            # provide the app with a way to process the GUI events when in a blocking loop
-                            if not run_threaded:
-                                QtWidgets.QApplication.processEvents()
-
-                            if self.app.abort_flag:
-                                # graceful abort requested by the user
-                                raise grace
-
-                            # clean the polygon
-                            p = p.buffer(0)
-
-                            if p is not None and p.is_valid:
-                                poly_failed = 0
-                                try:
-                                    for pol in p:
-                                        if pol is not None and isinstance(pol, Polygon):
-                                            res = self.clear_polygon_worker(pol=pol, tooldia=tool,
-                                                                            ncc_method=ncc_method,
-                                                                            ncc_overlap=ncc_overlap,
-                                                                            ncc_connect=ncc_connect,
-                                                                            ncc_contour=ncc_contour,
-                                                                            prog_plot=prog_plot)
-                                            if res is not None:
-                                                cleared_geo += res
-                                            else:
-                                                poly_failed += 1
-                                        else:
-                                            log.warning("Expected geo is a Polygon. Instead got a %s" % str(type(pol)))
-                                except TypeError:
-                                    if isinstance(p, Polygon):
-                                        res = self.clear_polygon_worker(pol=p, tooldia=tool,
-                                                                        ncc_method=ncc_method,
-                                                                        ncc_overlap=ncc_overlap,
-                                                                        ncc_connect=ncc_connect,
-                                                                        ncc_contour=ncc_contour,
-                                                                        prog_plot=prog_plot)
-                                        if res is not None:
-                                            cleared_geo += res
-                                        else:
-                                            poly_failed += 1
-                                    else:
-                                        log.warning("Expected geo is a Polygon. Instead got a %s" % str(type(p)))
-
-                                if poly_failed > 0:
-                                    app_obj.poly_not_cleared = True
-
-                                pol_nr += 1
-                                disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
-                                # log.debug("Polygons cleared: %d" % pol_nr)
-
-                                if old_disp_number < disp_number <= 100:
-                                    self.app.proc_container.update_view_text(' %d%%' % disp_number)
-                                    old_disp_number = disp_number
-                                    # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
-
-                        # check if there is a geometry at all in the cleared geometry
-                        if cleared_geo:
-                            cleared = empty.buffer(-offset * (1 + ncc_overlap))  # Overall cleared area
-                            cleared = cleared.buffer(-tool / 1.999999).buffer(tool / 1.999999)
-
-                            # clean-up cleared geo
-                            cleared = cleared.buffer(0)
-
-                            # find the tooluid associated with the current tool_dia so we know where to add the tool
-                            # solid_geometry
-                            for k, v in tools_storage.items():
-                                if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
-                                                                                                    tool)):
-                                    current_uid = int(k)
-
-                                    # add the solid_geometry to the current too in self.paint_tools dictionary
-                                    # and then reset the temporary list that stored that solid_geometry
-                                    v['solid_geometry'] = deepcopy(cleared_geo)
-                                    v['data']['name'] = name
-                                    break
-                            geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
-                        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_iso_plotting"] == 'progressive':
-                self.temp_shapes.clear(update=True)
-
-            # delete tools with empty geometry
-            # look for keys in the tools_storage dict that have 'solid_geometry' values empty
-            for uid, uid_val in list(tools_storage.items()):
-                try:
-                    # if the solid_geometry (type=list) is empty
-                    if not uid_val['solid_geometry']:
-                        tools_storage.pop(uid, None)
-                except KeyError:
-                    tools_storage.pop(uid, None)
-
-            geo_obj.options["cnctooldia"] = str(tool)
-
-            geo_obj.multigeo = True
-            geo_obj.tools.clear()
-            geo_obj.tools = dict(tools_storage)
-
-            # test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
-            has_solid_geo = 0
-            for tid in geo_obj.tools:
-                if geo_obj.tools[tid]['solid_geometry']:
-                    has_solid_geo += 1
-            if has_solid_geo == 0:
-                app_obj.inform.emit('[ERROR] %s' %
-                                    _("There is no NCC Geometry in the file.\n"
-                                      "Usually it means that the tool diameter is too big for the painted geometry.\n"
-                                      "Change the painting parameters and try again."))
-                return 'fail'
-
-            # 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:
-                if warning_flag == 0:
-                    self.app.inform.emit('[success] %s' % _("NCC Tool clear all done."))
-                else:
-                    self.app.inform.emit('[WARNING] %s: %s %s.' % (
-                        _("NCC Tool clear all done but the copper features isolation is broken for"),
-                        str(warning_flag),
-                        _("tools")))
-                    return
-
-                # create the solid_geometry
-                geo_obj.solid_geometry = []
-                for tool_id in geo_obj.tools:
-                    if geo_obj.tools[tool_id]['solid_geometry']:
-                        try:
-                            for geo in geo_obj.tools[tool_id]['solid_geometry']:
-                                geo_obj.solid_geometry.append(geo)
-                        except TypeError:
-                            geo_obj.solid_geometry.append(geo_obj.tools[tool_id]['solid_geometry'])
-            else:
-                # I will use this variable for this purpose although it was meant for something else
-                # signal that we have no geo in the object therefore don't create it
-                app_obj.poly_not_cleared = False
-                return "fail"
-
-            # # Experimental...
-            # # print("Indexing...", end=' ')
-            # # geo_obj.make_index()
-
-        # ###########################################################################################
-        # Initializes the new geometry object for the case of the rest-machining ####################
-        # ###########################################################################################
-        def gen_clear_area_rest(geo_obj, app_obj):
-            assert geo_obj.kind == 'geometry', \
-                "Initializer expected a GeometryObject, got %s" % type(geo_obj)
-
-            log.debug("NCC Tool. Rest machining copper clearing task started.")
-            app_obj.inform.emit('_(NCC Tool. Rest machining copper clearing task started.')
-
-            # provide the app with a way to process the GUI events when in a blocking loop
-            if not run_threaded:
-                QtWidgets.QApplication.processEvents()
-
-            # a flag to signal that the isolation is broken by the bounding box in 'area' and 'box' cases
-            # will store the number of tools for which the isolation is broken
-            warning_flag = 0
-
-            sorted_clear_tools.sort(reverse=True)
-
-            cleared_geo = []
-            cleared_by_last_tool = []
-            rest_geo = []
-            current_uid = 1
-            try:
-                tool = eval(self.app.defaults["tools_ncctools"])[0]
-            except TypeError:
-                tool = eval(self.app.defaults["tools_ncctools"])
-
-            # repurposed flag for final object, geo_obj. True if it has any solid_geometry, False if not.
-            app_obj.poly_not_cleared = True
-
-            if ncc_select == _("Reference Object"):
-                env_obj, box_obj_kind = self.calculate_bounding_box(
-                    ncc_obj=ncc_obj, box_obj=sel_obj, ncc_select=ncc_select)
-            else:
-                env_obj, box_obj_kind = self.calculate_bounding_box(ncc_obj=ncc_obj, ncc_select=ncc_select)
-
-            if env_obj is None and box_obj_kind is None:
-                self.app.inform.emit("[ERROR_NOTCL] %s" % _("NCC Tool failed creating bounding box."))
-                return "fail"
-
-            log.debug("NCC Tool. Calculate 'empty' area.")
-            app_obj.inform.emit("NCC Tool. Calculate 'empty' area.")
-
-            # Generate area for each tool
-            while sorted_clear_tools:
-                log.debug("Starting geometry processing for tool: %s" % str(tool))
-                if self.app.abort_flag:
-                    # graceful abort requested by the user
-                    raise grace
-
-                # provide the app with a way to process the GUI events when in a blocking loop
-                QtWidgets.QApplication.processEvents()
-
-                app_obj.inform.emit('[success] %s = %s%s %s' % (
-                    _('NCC Tool clearing with tool diameter'), str(tool), units.lower(), _('started.'))
-                                    )
-                app_obj.proc_container.update_view_text(' %d%%' % 0)
-
-                tool = sorted_clear_tools.pop(0)
-
-                tool_uid = 0
-                for k, v in self.iso_tools.items():
-                    if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool)):
-                        tool_uid = int(k)
-                        break
-
-                ncc_overlap = float(self.iso_tools[tool_uid]["data"]["tools_nccoverlap"]) / 100.0
-                ncc_margin = float(self.iso_tools[tool_uid]["data"]["tools_nccmargin"])
-                ncc_method = self.iso_tools[tool_uid]["data"]["tools_nccmethod"]
-                ncc_connect = self.iso_tools[tool_uid]["data"]["tools_nccconnect"]
-                ncc_contour = self.iso_tools[tool_uid]["data"]["tools_ncccontour"]
-                has_offset = self.iso_tools[tool_uid]["data"]["tools_ncc_offset_choice"]
-                ncc_offset = float(self.iso_tools[tool_uid]["data"]["tools_ncc_offset_value"])
-
-                tool_used = tool - 1e-12
-                cleared_geo[:] = []
-
-                # Bounding box for current tool
-                bbox = self.apply_margin_to_bounding_box(bbox=env_obj, box_kind=box_obj_kind,
-                                                         ncc_select=ncc_select, ncc_margin=ncc_margin)
-
-                # Area to clear
-                empty, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj,
-                                                               isotooldia=isotooldia,
-                                                               has_offset=has_offset, ncc_offset=ncc_offset,
-                                                               ncc_margin=ncc_margin, tools_storage=tools_storage,
-                                                               bounding_box=bbox)
-
-                area = empty.buffer(0)
-
-                # Area to clear
-                for poly in cleared_by_last_tool:
-                    # provide the app with a way to process the GUI events when in a blocking loop
-                    QtWidgets.QApplication.processEvents()
-
-                    if self.app.abort_flag:
-                        # graceful abort requested by the user
-                        raise grace
-                    try:
-                        area = area.difference(poly)
-                    except Exception:
-                        pass
-                cleared_by_last_tool[:] = []
-
-                # Transform area to MultiPolygon
-                if type(area) is Polygon:
-                    area = MultiPolygon([area])
-
-                # add the rest that was not able to be cleared previously; area is a MultyPolygon
-                # and rest_geo it's a list
-                allparts = [p.buffer(0) for p in area.geoms]
-                allparts += deepcopy(rest_geo)
-                rest_geo[:] = []
-                area = MultiPolygon(deepcopy(allparts))
-                allparts[:] = []
-
-                # variables to display the percentage of work done
-                geo_len = len(area.geoms)
-                old_disp_number = 0
-                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
-
-                if area.geoms:
-                    if len(area.geoms) > 0:
-                        pol_nr = 0
-                        for p in area.geoms:
-                            if self.app.abort_flag:
-                                # graceful abort requested by the user
-                                raise grace
-
-                            # clean the polygon
-                            p = p.buffer(0)
-
-                            if p is not None and p.is_valid:
-                                # provide the app with a way to process the GUI events when in a blocking loop
-                                QtWidgets.QApplication.processEvents()
-
-                                if isinstance(p, Polygon):
-                                    try:
-                                        if ncc_method == _("Standard"):
-                                            cp = self.clear_polygon(p, tool_used,
-                                                                    self.grb_circle_steps,
-                                                                    overlap=ncc_overlap, contour=ncc_contour,
-                                                                    connect=ncc_connect,
-                                                                    prog_plot=prog_plot)
-                                        elif ncc_method == _("Seed"):
-                                            cp = self.clear_polygon2(p, tool_used,
-                                                                     self.grb_circle_steps,
-                                                                     overlap=ncc_overlap, contour=ncc_contour,
-                                                                     connect=ncc_connect,
-                                                                     prog_plot=prog_plot)
-                                        else:
-                                            cp = self.clear_polygon3(p, tool_used,
-                                                                     self.grb_circle_steps,
-                                                                     overlap=ncc_overlap, contour=ncc_contour,
-                                                                     connect=ncc_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))
-                                        # this polygon should be added to a list and then try clear it with
-                                        # a smaller tool
-                                        rest_geo.append(p)
-                                elif isinstance(p, MultiPolygon):
-                                    for poly in p:
-                                        if poly is not None:
-                                            # provide the app with a way to process the GUI events when
-                                            # in a blocking loop
-                                            QtWidgets.QApplication.processEvents()
-
-                                            try:
-                                                if ncc_method == _("Standard"):
-                                                    cp = self.clear_polygon(poly, tool_used,
-                                                                            self.grb_circle_steps,
-                                                                            overlap=ncc_overlap, contour=ncc_contour,
-                                                                            connect=ncc_connect,
-                                                                            prog_plot=prog_plot)
-                                                elif ncc_method == _("Seed"):
-                                                    cp = self.clear_polygon2(poly, tool_used,
-                                                                             self.grb_circle_steps,
-                                                                             overlap=ncc_overlap, contour=ncc_contour,
-                                                                             connect=ncc_connect,
-                                                                             prog_plot=prog_plot)
-                                                else:
-                                                    cp = self.clear_polygon3(poly, tool_used,
-                                                                             self.grb_circle_steps,
-                                                                             overlap=ncc_overlap, contour=ncc_contour,
-                                                                             connect=ncc_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))
-                                                # this polygon should be added to a list and then try clear it with
-                                                # a smaller tool
-                                                rest_geo.append(poly)
-
-                                pol_nr += 1
-                                disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
-                                # log.debug("Polygons cleared: %d" % pol_nr)
-
-                                if old_disp_number < disp_number <= 100:
-                                    self.app.proc_container.update_view_text(' %d%%' % disp_number)
-                                    old_disp_number = disp_number
-                                    # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
-
-                        if self.app.abort_flag:
-                            # graceful abort requested by the user
-                            raise grace
-
-                        # check if there is a geometry at all in the cleared geometry
-                        if cleared_geo:
-                            # Overall cleared area
-                            cleared_area = list(self.flatten_list(cleared_geo))
-
-                            # cleared = MultiPolygon([p.buffer(tool_used / 2).buffer(-tool_used / 2)
-                            #                         for p in cleared_area])
-
-                            # here we store the poly's already processed in the original geometry by the current tool
-                            # into cleared_by_last_tool list
-                            # this will be sutracted from the original geometry_to_be_cleared and make data for
-                            # the next tool
-                            buffer_value = tool_used / 2
-                            for p in cleared_area:
-                                if self.app.abort_flag:
-                                    # graceful abort requested by the user
-                                    raise grace
-
-                                poly = p.buffer(buffer_value)
-                                cleared_by_last_tool.append(poly)
-
-                            # find the tool uid associated with the current tool_dia so we know
-                            # where to add the tool solid_geometry
-                            for k, v in tools_storage.items():
-                                if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
-                                                                                                    tool)):
-                                    current_uid = int(k)
-
-                                    # add the solid_geometry to the current too in self.paint_tools dictionary
-                                    # and then reset the temporary list that stored that solid_geometry
-                                    v['solid_geometry'] = deepcopy(cleared_area)
-                                    v['data']['name'] = name
-                                    cleared_area[:] = []
-                                    break
-
-                            geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
-                        else:
-                            log.debug("There are no geometries in the cleared polygon.")
-
-            geo_obj.multigeo = True
-            geo_obj.options["cnctooldia"] = str(tool)
-
-            # clean the progressive plotted shapes if it was used
-            if self.app.defaults["tools_iso_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:
-                if warning_flag == 0:
-                    self.app.inform.emit('[success] %s' % _("NCC Tool Rest Machining clear all done."))
-                else:
-                    self.app.inform.emit(
-                        '[WARNING] %s: %s %s.' % (_("NCC Tool Rest Machining clear all done but the copper features "
-                                                    "isolation is broken for"), str(warning_flag), _("tools")))
-                    return
-
-                # create the solid_geometry
-                geo_obj.solid_geometry = []
-                for tool_uid in geo_obj.tools:
-                    if geo_obj.tools[tool_uid]['solid_geometry']:
-                        try:
-                            for geo in geo_obj.tools[tool_uid]['solid_geometry']:
-                                geo_obj.solid_geometry.append(geo)
-                        except TypeError:
-                            geo_obj.solid_geometry.append(geo_obj.tools[tool_uid]['solid_geometry'])
-            else:
-                # I will use this variable for this purpose although it was meant for something else
-                # signal that we have no geo in the object therefore don't create it
-                app_obj.poly_not_cleared = False
-                return "fail"
-
-        # ###########################################################################################
-        # Create the Job function and send it to the worker to be processed in another thread #######
-        # ###########################################################################################
-        def job_thread(a_obj):
-            try:
-                if rest_machining_choice is True:
-                    a_obj.app_obj.new_object("geometry", name, gen_clear_area_rest)
-                else:
-                    a_obj.app_obj.new_object("geometry", name, gen_clear_area)
-            except grace:
-                if run_threaded:
-                    proc.done()
-                return
-            except Exception:
-                if run_threaded:
-                    proc.done()
-                traceback.print_stack()
-                return
-
-            if run_threaded:
-                proc.done()
-            else:
-                a_obj.proc_container.view.set_idle()
-
-            # focus on Selected Tab
-            self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
-
-        if run_threaded:
-            # Promise object with the new name
-            self.app.collection.promise(name)
-
-            # Background
-            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
-        else:
-            job_thread(app_obj=self.app)
-
     @staticmethod
     def poly2rings(poly):
         return [poly.exterior] + [interior for interior in poly.interiors]