Преглед на файлове

- in NCC and Isolation Tools, the Validity Checking of the tools is now multithreaded when the Check Validity UI control is checked
- translation strings updated

Marius Stanciu преди 5 години
родител
ревизия
13e4d7bad7

+ 2 - 0
CHANGELOG.md

@@ -17,6 +17,8 @@ CHANGELOG for FlatCAM beta
 - optimized some of the strings
 - fixed the project context save functionality to work in the new program configuration
 - updated Turkish translation (by Mehmet Kaya)
+- in NCC and Isolation Tools, the Validity Checking of the tools is now multithreaded when the Check Validity UI control is checked
+- translation strings updated
 
 2.11.2020
 

+ 125 - 36
appTools/ToolIsolation.py

@@ -908,9 +908,59 @@ class ToolIsolation(AppTool, Gerber):
             })
 
     def on_find_optimal_tooldia(self):
-        self.find_safe_tooldia_worker(is_displayed=True)
+        self.find_safe_tooldia_worker()
 
-    def find_safe_tooldia_worker(self, is_displayed):
+    @staticmethod
+    def find_optim_mp(aperture_storage, decimals):
+        msg = 'ok'
+        total_geo = []
+
+        for ap in list(aperture_storage.keys()):
+            if 'geometry' in aperture_storage[ap]:
+                for geo_el in aperture_storage[ap]['geometry']:
+                    if 'solid' in geo_el and geo_el['solid'] is not None and geo_el['solid'].is_valid:
+                        total_geo.append(geo_el['solid'])
+
+        total_geo = MultiPolygon(total_geo)
+        total_geo = total_geo.buffer(0)
+
+        try:
+            __ = iter(total_geo)
+            geo_len = len(total_geo)
+        except TypeError:
+            msg = ('[ERROR_NOTCL] %s' % _("The Gerber object has one Polygon as geometry.\n"
+                                          "There are no distances between geometry elements to be found."))
+
+        min_dict = {}
+        idx = 1
+        for geo in total_geo:
+            for s_geo in total_geo[idx:]:
+                # minimize the number of distances by not taking into considerations
+                # those that are too small
+                dist = geo.distance(s_geo)
+                dist = float('%.*f' % (decimals, dist))
+                loc_1, loc_2 = nearest_points(geo, s_geo)
+
+                proc_loc = (
+                    (float('%.*f' % (decimals, loc_1.x)), float('%.*f' % (decimals, loc_1.y))),
+                    (float('%.*f' % (decimals, loc_2.x)), float('%.*f' % (decimals, loc_2.y)))
+                )
+
+                if dist in min_dict:
+                    min_dict[dist].append(proc_loc)
+                else:
+                    min_dict[dist] = [proc_loc]
+
+            idx += 1
+
+        min_list = list(min_dict.keys())
+        min_dist = min(min_list)
+
+        return msg, min_dist
+
+    # multiprocessing variant
+    def find_safe_tooldia_multiprocessing(self):
+        self.app.inform.emit(_("Checking tools for validity."))
         self.units = self.app.defaults['units'].upper()
 
         obj_name = self.ui.object_combo.currentText()
@@ -926,8 +976,73 @@ class ToolIsolation(AppTool, Gerber):
             self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
             return
 
-        def job_thread(app_obj, is_display):
-            with self.app.proc_container.new(_("Working ...")):
+        def job_thread(app_obj):
+            with self.app.proc_container.new(_("Checking ...")):
+
+                ap_storage = fcobj.apertures
+
+                p = app_obj.pool.apply_async(self.find_optim_mp, args=(ap_storage, self.decimals))
+                res = p.get()
+
+                if res[0] != 'ok':
+                    app_obj.inform.emit(res[0])
+                    return 'fail'
+                else:
+                    min_dist = res[1]
+
+                try:
+                    min_dist_truncated = self.app.dec_format(float(min_dist), self.decimals)
+                    self.safe_tooldia = min_dist_truncated
+
+                    if self.safe_tooldia:
+                        # find the selected tool ID's
+                        sorted_tools = []
+                        table_items = self.ui.tools_table.selectedItems()
+                        sel_rows = {t.row() for t in table_items}
+                        for row in sel_rows:
+                            tid = int(self.ui.tools_table.item(row, 3).text())
+                            sorted_tools.append(tid)
+                        if not sorted_tools:
+                            msg = _("There are no tools selected in the Tool Table.")
+                            self.app.inform.emit('[ERROR_NOTCL] %s' % msg)
+                            return 'fail'
+
+                        # check if the tools diameters are less then the safe tool diameter
+                        for tool in sorted_tools:
+                            tool_dia = float(self.iso_tools[tool]['tooldia'])
+                            if tool_dia > self.safe_tooldia:
+                                msg = _("Incomplete isolation. "
+                                        "At least one tool could not do a complete isolation.")
+                                self.app.inform.emit('[WARNING] %s' % msg)
+                                break
+
+                        # reset the value to prepare for another isolation
+                        self.safe_tooldia = None
+                except Exception as ee:
+                    log.debug(str(ee))
+                    return
+
+        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+
+    def find_safe_tooldia_worker(self):
+        self.app.inform.emit(_("Checking tools for validity."))
+        self.units = self.app.defaults['units'].upper()
+
+        obj_name = self.ui.object_combo.currentText()
+
+        # Get source object.
+        try:
+            fcobj = self.app.collection.get_by_name(obj_name)
+        except Exception:
+            self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(obj_name)))
+            return
+
+        if fcobj is None:
+            self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
+            return
+
+        def job_thread(app_obj):
+            with self.app.proc_container.new(_("Checking ...")):
                 try:
                     old_disp_number = 0
                     pol_nr = 0
@@ -995,42 +1110,16 @@ class ToolIsolation(AppTool, Gerber):
                     min_dist_truncated = self.app.dec_format(float(min_dist), self.decimals)
                     self.safe_tooldia = min_dist_truncated
 
-                    if is_display:
-                        self.optimal_found_sig.emit(min_dist_truncated)
+                    self.optimal_found_sig.emit(min_dist_truncated)
 
-                        app_obj.inform.emit('[success] %s: %s %s' %
-                                            (_("Optimal tool diameter found"), str(min_dist_truncated),
-                                             self.units.lower()))
-                    else:
-                        if self.safe_tooldia:
-                            # find the selected tool ID's
-                            sorted_tools = []
-                            table_items = self.ui.tools_table.selectedItems()
-                            sel_rows = {t.row() for t in table_items}
-                            for row in sel_rows:
-                                tid = int(self.ui.tools_table.item(row, 3).text())
-                                sorted_tools.append(tid)
-                            if not sorted_tools:
-                                msg = _("There are no tools selected in the Tool Table.")
-                                self.app.inform.emit('[ERROR_NOTCL] %s' % msg)
-                                return 'fail'
-
-                            # check if the tools diameters are less then the safe tool diameter
-                            for tool in sorted_tools:
-                                tool_dia = float(self.iso_tools[tool]['tooldia'])
-                                if tool_dia > self.safe_tooldia:
-                                    msg = _("Incomplete isolation. "
-                                            "At least one tool could not do a complete isolation.")
-                                    self.app.inform.emit('[WARNING] %s' % msg)
-                                    break
-
-                            # reset the value to prepare for another isolation
-                            self.safe_tooldia = None
+                    app_obj.inform.emit('[success] %s: %s %s' %
+                                        (_("Optimal tool diameter found"), str(min_dist_truncated),
+                                         self.units.lower()))
                 except Exception as ee:
                     log.debug(str(ee))
                     return
 
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app, is_displayed]})
+        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
 
     def on_tool_add(self, custom_dia=None):
         self.blockSignals(True)
@@ -1384,7 +1473,7 @@ class ToolIsolation(AppTool, Gerber):
             return
 
         if self.ui.valid_cb.get_value() is True:
-            self.find_safe_tooldia_worker(is_displayed=False)
+            self.find_safe_tooldia_multiprocessing()
 
         def worker_task(iso_obj):
             with self.app.proc_container.new(_("Isolating ...")):

+ 130 - 41
appTools/ToolNCC.py

@@ -845,10 +845,128 @@ class NonCopperClear(AppTool, Gerber):
             })
 
     def on_find_optimal_tooldia(self):
-        self.find_safe_tooldia_worker(is_displayed=True)
+        self.find_safe_tooldia_worker()
 
-    def find_safe_tooldia_worker(self, is_displayed):
-        self.app.inform.emit(_("NCC Tool. Checking tools for validity."))
+    @staticmethod
+    def find_optim_mp(aperture_storage, decimals):
+        msg = 'ok'
+        total_geo = []
+
+        for ap in list(aperture_storage.keys()):
+            if 'geometry' in aperture_storage[ap]:
+                for geo_el in aperture_storage[ap]['geometry']:
+                    if 'solid' in geo_el and geo_el['solid'] is not None and geo_el['solid'].is_valid:
+                        total_geo.append(geo_el['solid'])
+
+        total_geo = MultiPolygon(total_geo)
+        total_geo = total_geo.buffer(0)
+
+        try:
+            __ = iter(total_geo)
+            geo_len = len(total_geo)
+        except TypeError:
+            msg = ('[ERROR_NOTCL] %s' % _("The Gerber object has one Polygon as geometry.\n"
+                                          "There are no distances between geometry elements to be found."))
+
+        min_dict = {}
+        idx = 1
+        for geo in total_geo:
+            for s_geo in total_geo[idx:]:
+                # minimize the number of distances by not taking into considerations
+                # those that are too small
+                dist = geo.distance(s_geo)
+                dist = float('%.*f' % (decimals, dist))
+                loc_1, loc_2 = nearest_points(geo, s_geo)
+
+                proc_loc = (
+                    (float('%.*f' % (decimals, loc_1.x)), float('%.*f' % (decimals, loc_1.y))),
+                    (float('%.*f' % (decimals, loc_2.x)), float('%.*f' % (decimals, loc_2.y)))
+                )
+
+                if dist in min_dict:
+                    min_dict[dist].append(proc_loc)
+                else:
+                    min_dict[dist] = [proc_loc]
+
+            idx += 1
+
+        min_list = list(min_dict.keys())
+        min_dist = min(min_list)
+
+        return msg, min_dist
+
+    # multiprocessing variant
+    def find_safe_tooldia_multiprocessing(self):
+        self.app.inform.emit(_("Checking tools for validity."))
+        self.units = self.app.defaults['units'].upper()
+
+        obj_name = self.ui.object_combo.currentText()
+
+        # Get source object.
+        try:
+            fcobj = self.app.collection.get_by_name(obj_name)
+        except Exception:
+            self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(obj_name)))
+            return
+
+        if fcobj is None:
+            self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
+            return
+
+        def job_thread(app_obj):
+            with self.app.proc_container.new(_("Checking ...")):
+
+                ap_storage = fcobj.apertures
+
+                p = app_obj.pool.apply_async(self.find_optim_mp, args=(ap_storage, self.decimals))
+                res = p.get()
+
+                if res[0] != 'ok':
+                    app_obj.inform.emit(res[0])
+                    return 'fail'
+                else:
+                    min_dist = res[1]
+
+                try:
+                    min_dist_truncated = self.app.dec_format(float(min_dist), self.decimals)
+                    self.safe_tooldia = min_dist_truncated
+
+                    # find the selected tool ID's
+                    sorted_tools = []
+                    table_items = self.ui.tools_table.selectedItems()
+                    sel_rows = {t.row() for t in table_items}
+                    for row in sel_rows:
+                        tid = int(self.ui.tools_table.item(row, 3).text())
+                        sorted_tools.append(tid)
+                    if not sorted_tools:
+                        msg = _("There are no tools selected in the Tool Table.")
+                        self.app.inform.emit('[ERROR_NOTCL] %s' % msg)
+                        return 'fail'
+
+                    # check if the tools diameters are less then the safe tool diameter
+                    suitable_tools = []
+                    for tool in sorted_tools:
+                        tool_dia = float(self.ncc_tools[tool]['tooldia'])
+                        if tool_dia <= self.safe_tooldia:
+                            suitable_tools.append(tool_dia)
+
+                    if not suitable_tools:
+                        msg = _("Incomplete isolation. None of the selected tools could do a complete isolation.")
+                        self.app.inform.emit('[WARNING] %s' % msg)
+                    else:
+                        msg = _("At least one of the selected tools can do a complete isolation.")
+                        self.app.inform.emit('[success] %s' % msg)
+
+                    # reset the value to prepare for another isolation
+                    self.safe_tooldia = None
+                except Exception as ee:
+                    log.debug(str(ee))
+                    return
+
+        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+
+    def find_safe_tooldia_worker(self):
+        self.app.inform.emit(_("Checking tools for validity."))
         self.units = self.app.defaults['units'].upper()
 
         obj_name = self.ui.object_combo.currentText()
@@ -864,8 +982,8 @@ class NonCopperClear(AppTool, Gerber):
             self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
             return
 
-        def job_thread(app_obj, is_display):
-            with self.app.proc_container.new(_("Working...")):
+        def job_thread(app_obj):
+            with self.app.proc_container.new(_("Checking ...")):
                 try:
                     old_disp_number = 0
                     pol_nr = 0
@@ -933,46 +1051,16 @@ class NonCopperClear(AppTool, Gerber):
                     min_dist_truncated = self.app.dec_format(float(min_dist), self.decimals)
                     self.safe_tooldia = min_dist_truncated
 
-                    if is_display:
-                        self.optimal_found_sig.emit(min_dist_truncated)
-
-                        app_obj.inform.emit('[success] %s: %s %s' %
-                                            (_("Optimal tool diameter found"), str(min_dist_truncated),
-                                             self.units.lower()))
-                    else:
-                        # find the selected tool ID's
-                        sorted_tools = []
-                        table_items = self.ui.tools_table.selectedItems()
-                        sel_rows = {t.row() for t in table_items}
-                        for row in sel_rows:
-                            tid = int(self.ui.tools_table.item(row, 3).text())
-                            sorted_tools.append(tid)
-                        if not sorted_tools:
-                            msg = _("There are no tools selected in the Tool Table.")
-                            self.app.inform.emit('[ERROR_NOTCL] %s' % msg)
-                            return 'fail'
-
-                        # check if the tools diameters are less then the safe tool diameter
-                        suitable_tools = []
-                        for tool in sorted_tools:
-                            tool_dia = float(self.ncc_tools[tool]['tooldia'])
-                            if tool_dia <= self.safe_tooldia:
-                                suitable_tools.append(tool_dia)
-
-                        if not suitable_tools:
-                            msg = _("Incomplete isolation. None of the selected tools could do a complete isolation.")
-                            self.app.inform.emit('[WARNING] %s' % msg)
-                        else:
-                            msg = _("At least one of the selected tools can do a complete isolation.")
-                            self.app.inform.emit('[success] %s' % msg)
+                    self.optimal_found_sig.emit(min_dist_truncated)
 
-                        # reset the value to prepare for another isolation
-                        self.safe_tooldia = None
+                    app_obj.inform.emit('[success] %s: %s %s' %
+                                        (_("Optimal tool diameter found"), str(min_dist_truncated),
+                                         self.units.lower()))
                 except Exception as ee:
                     log.debug(str(ee))
                     return
 
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app, is_displayed]})
+        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
 
     def on_tool_add(self, custom_dia=None):
         self.blockSignals(True)
@@ -1327,7 +1415,8 @@ class NonCopperClear(AppTool, Gerber):
             return
 
         if self.ui.valid_cb.get_value() is True:
-            self.find_safe_tooldia_worker(is_displayed=False)
+            # this is done in another Process
+            self.find_safe_tooldia_multiprocessing()
 
         # use the selected tools in the tool table; get diameters for isolation
         self.iso_dia_list = []

BIN
locale/de/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 158
locale/de/LC_MESSAGES/strings.po


BIN
locale/en/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 158
locale/en/LC_MESSAGES/strings.po


BIN
locale/es/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 158
locale/es/LC_MESSAGES/strings.po


BIN
locale/fr/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 158
locale/fr/LC_MESSAGES/strings.po


BIN
locale/it/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 158
locale/it/LC_MESSAGES/strings.po


BIN
locale/pt_BR/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 158
locale/pt_BR/LC_MESSAGES/strings.po


BIN
locale/ro/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 160
locale/ro/LC_MESSAGES/strings.po


BIN
locale/ru/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 157 - 159
locale/ru/LC_MESSAGES/strings.po


BIN
locale/tr/LC_MESSAGES/strings.mo


Файловите разлики са ограничени, защото са твърде много
+ 158 - 158
locale/tr/LC_MESSAGES/strings.po


Файловите разлики са ограничени, защото са твърде много
+ 160 - 160
locale_template/strings.pot


Някои файлове не бяха показани, защото твърде много файлове са промени