Przeglądaj źródła

- Gerber Editor: made geometry transfer (which is slow) to Editor to be multithreaded
- Gerber Editor: plotting process is showed in the status bar

Marius Stanciu 6 lat temu
rodzic
commit
cefb74d792
4 zmienionych plików z 88 dodań i 48 usunięć
  1. 8 2
      FlatCAMApp.py
  2. 13 0
      ObjectCollection.py
  3. 5 0
      README.md
  4. 62 46
      flatcamEditors/FlatCAMGrbEditor.py

+ 8 - 2
FlatCAMApp.py

@@ -7949,9 +7949,15 @@ The normal flow when working in FlatCAM is the following:</span></p>
                 t = threading.Thread(target=lambda: self.check_project_file_size(1, filename=filename))
                 t = threading.Thread(target=lambda: self.check_project_file_size(1, filename=filename))
                 t.start()
                 t.start()
 
 
-    # using Alfe's answer from here:
-    # https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds-in-python
     def check_project_file_size(self, delay, filename):
     def check_project_file_size(self, delay, filename):
+        """
+        Using Alfe's answer from here:
+        https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds-in-python
+
+        :param delay: period of checking if project file size is more than zero; in seconds
+        :param filename: the name of the project file to be checked for size more than zero
+        :return:
+        """
         next_time = time.time() + delay
         next_time = time.time() + delay
         while True:
         while True:
             time.sleep(max(0, next_time - time.time()))
             time.sleep(max(0, next_time - time.time()))

+ 13 - 0
ObjectCollection.py

@@ -240,6 +240,9 @@ class ObjectCollection(QtCore.QAbstractItemModel):
         # tasks know that they have to wait until available.
         # tasks know that they have to wait until available.
         self.promises = set()
         self.promises = set()
 
 
+        # same as above only for objects that are plotted
+        self.plot_promises = set()
+
         self.app = app
         self.app = app
 
 
         ### View
         ### View
@@ -275,6 +278,16 @@ class ObjectCollection(QtCore.QAbstractItemModel):
     def has_promises(self):
     def has_promises(self):
         return len(self.promises) > 0
         return len(self.promises) > 0
 
 
+    def plot_promise(self, plot_obj_name):
+        self.plot_promises.add(plot_obj_name)
+
+    def plot_remove_promise(self, plot_obj_name):
+        if plot_obj_name in self.plot_promises:
+            self.plot_promises.remove(plot_obj_name)
+
+    def has_plot_promises(self):
+        return len(self.plot_promises) > 0
+
     def on_mouse_down(self, event):
     def on_mouse_down(self, event):
         FlatCAMApp.App.log.debug("Mouse button pressed on list")
         FlatCAMApp.App.log.debug("Mouse button pressed on list")
 
 

+ 5 - 0
README.md

@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+5.04.2019
+
+- Gerber Editor: made geometry transfer (which is slow) to Editor to be multithreaded
+- Gerber Editor: plotting process is showed in the status bar
+
 4.04.2019
 4.04.2019
 
 
 - added support for Gerber format specification D (no zero suppression) - PCBWizard Gerber files support
 - added support for Gerber format specification D (no zero suppression) - PCBWizard Gerber files support

+ 62 - 46
flatcamEditors/FlatCAMGrbEditor.py

@@ -7,6 +7,7 @@ import shapely.affinity as affinity
 
 
 from numpy import arctan2, Inf, array, sqrt, sign, dot
 from numpy import arctan2, Inf, array, sqrt, sign, dot
 from rtree import index as rtindex
 from rtree import index as rtindex
+import threading, time
 
 
 from camlib import *
 from camlib import *
 from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
 from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
@@ -1262,18 +1263,23 @@ class FlatCAMGrbEditor(QtCore.QObject):
 
 
         # build the geometry for each tool-diameter, each drill will be represented by a '+' symbol
         # build the geometry for each tool-diameter, each drill will be represented by a '+' symbol
         # and then add it to the storage elements (each storage elements is a member of a list
         # and then add it to the storage elements (each storage elements is a member of a list
-        for apid in self.gerber_obj.apertures:
-            storage_elem = FlatCAMGeoEditor.make_storage()
-            for geo in self.gerber_obj.apertures[apid]['solid_geometry']:
-                if geo is not None:
-                    self.add_gerber_shape(DrawToolShape(geo), storage_elem)
-            self.storage_dict[apid] = storage_elem
 
 
-        self.replot()
+        def job_thread(apid):
+            with self.app.proc_container.new(_("Adding aperture: %s geo ...") % str(apid)):
+                storage_elem = FlatCAMGeoEditor.make_storage()
+                for geo in self.gerber_obj.apertures[apid]['solid_geometry']:
+                    if geo is not None:
+                        self.add_gerber_shape(DrawToolShape(geo), storage_elem)
+                self.storage_dict[apid] = storage_elem
+
+                # Check promises and clear if exists
+                self.app.collection.plot_remove_promise(apid)
+
+        for apid in self.gerber_obj.apertures:
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [apid]})
+            self.app.collection.plot_promise(apid)
 
 
-        # add a first tool in the Tool Table but only if the Excellon Object is empty
-        # if not self.tool2tooldia:
-        #     self.on_tool_add(tooldia=1.00)
+        self.start_delayed_plot(check_period=0.5)
 
 
     def update_fcgerber(self, exc_obj):
     def update_fcgerber(self, exc_obj):
         """
         """
@@ -1845,25 +1851,56 @@ class FlatCAMGrbEditor(QtCore.QObject):
         :return: None
         :return: None
         :rtype: None
         :rtype: None
         """
         """
-        # self.app.log.debug("plot_all()")
-        self.shapes.clear(update=True)
+        with self.app.proc_container.new("Plotting"):
+            # self.app.log.debug("plot_all()")
+            self.shapes.clear(update=True)
 
 
-        for storage in self.storage_dict:
-            for shape_plus in self.storage_dict[storage].get_objects():
-                if shape_plus.geo is None:
-                    continue
+            for storage in self.storage_dict:
+                for shape in self.storage_dict[storage].get_objects():
+                    if shape.geo is None:
+                        continue
+
+                    if shape in self.selected:
+                        self.plot_shape(geometry=shape.geo, color=self.app.defaults['global_sel_draw_color'],
+                                        linewidth=2)
+                        continue
+                    self.plot_shape(geometry=shape.geo, color=self.app.defaults['global_draw_color'])
+
+            for shape in self.utility:
+                self.plot_shape(geometry=shape.geo, linewidth=1)
+                continue
 
 
-                if shape_plus in self.selected:
-                    self.plot_shape(geometry=shape_plus.geo, color=self.app.defaults['global_sel_draw_color'],
-                                    linewidth=2)
-                    continue
-                self.plot_shape(geometry=shape_plus.geo, color=self.app.defaults['global_draw_color'])
+            self.shapes.redraw()
 
 
-        for shape in self.utility:
-            self.plot_shape(geometry=shape.geo, linewidth=1)
-            continue
+    def start_delayed_plot(self, check_period):
+        self.plot_thread = threading.Thread(target=lambda: self.check_plot_finished(check_period))
+        self.plot_thread.start()
 
 
-        self.shapes.redraw()
+    def stop_delayed_plot(self):
+        self.plot_thread.exit()
+        # self.plot_thread.join()
+
+    def check_plot_finished(self, delay):
+        """
+        Using Alfe's answer from here:
+        https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds-in-python
+
+        :param delay: period of checking if project file size is more than zero; in seconds
+        :param filename: the name of the project file to be checked for size more than zero
+        :return:
+        """
+        next_time = time.time() + delay
+        while True:
+            time.sleep(max(0, next_time - time.time()))
+            try:
+                if self.app.collection.has_plot_promises() is False:
+                    self.plot_all()
+                    break
+            except Exception:
+                traceback.print_exc()
+
+            # skip tasks if we are behind schedule:
+            next_time += (time.time() - next_time) // delay * delay + delay
 
 
     def plot_shape(self, geometry=None, color='black', linewidth=1):
     def plot_shape(self, geometry=None, color='black', linewidth=1):
         """
         """
@@ -1887,27 +1924,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
                 return
                 return
             self.shapes.add(shape=geometry, color=color, face_color=color+'AF', layer=0)
             self.shapes.add(shape=geometry, color=color, face_color=color+'AF', layer=0)
 
 
-        # try:
-        #     for geo in geometry:
-        #         plot_elements += self.plot_shape(geometry=geo.geo, color=color, linewidth=linewidth)
-        #
-        # ## Non-iterable
-        # except TypeError:
-        #
-        #     # ## DrawToolShape
-        #     # if isinstance(geometry, DrawToolShape):
-        #     #     plot_elements += self.plot_shape(geometry=geometry.geo, color=color, linewidth=linewidth)
-        #     #
-        #     # ## Polygon: Descend into exterior and each interior.
-        #     # if type(geometry) == Polygon:
-        #     #     plot_elements += self.plot_shape(geometry=geometry.exterior, color=color, linewidth=linewidth)
-        #     #     plot_elements += self.plot_shape(geometry=geometry.interiors, color=color, linewidth=linewidth)
-        #     if type(geometry) == Point:
-        #         pass
-        #     else:
-        #         plot_elements.append(self.shapes.add(shape=geometry, color=color, face_color=color, layer=0))
-        # return plot_elements
-
     def on_shape_complete(self):
     def on_shape_complete(self):
         self.app.log.debug("on_shape_complete()")
         self.app.log.debug("on_shape_complete()")