فهرست منبع

- 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

Marius Stanciu 6 سال پیش
والد
کامیت
198e055328
6فایلهای تغییر یافته به همراه108 افزوده شده و 19 حذف شده
  1. 18 5
      FlatCAMApp.py
  2. 5 0
      README.md
  3. 11 6
      camlib.py
  4. 15 1
      flatcamGUI/FlatCAMGUI.py
  5. 1 1
      flatcamGUI/VisPyVisuals.py
  6. 58 6
      flatcamTools/ToolNonCopperClear.py

+ 18 - 5
FlatCAMApp.py

@@ -423,6 +423,7 @@ class App(QtCore.QObject):
             "gerber_solid": self.ui.gerber_defaults_form.gerber_gen_group.solid_cb,
             "gerber_multicolored": self.ui.gerber_defaults_form.gerber_gen_group.multicolored_cb,
             "gerber_circle_steps": self.ui.gerber_defaults_form.gerber_gen_group.circle_steps_entry,
+            "gerber_buffering": self.ui.gerber_defaults_form.gerber_gen_group.buffering_radio,
 
             # Gerber Options
             "gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry,
@@ -824,19 +825,20 @@ class App(QtCore.QObject):
             "gerber_plot": True,
             "gerber_solid": True,
             "gerber_multicolored": False,
+            "gerber_circle_steps": 128,
+            "gerber_use_buffer_for_union": True,
+            "gerber_buffering": "full",
+
+            # Gerber Options
             "gerber_isotooldia": 0.00787402,
             "gerber_isopasses": 1,
             "gerber_isooverlap": 0.00393701,
-
-            # Gerber Options
-            "gerber_combine_passes": False,
             "gerber_milling_type": "cl",
+            "gerber_combine_passes": False,
             "gerber_noncoppermargin": 0.00393701,
             "gerber_noncopperrounded": False,
             "gerber_bboxmargin": 0.00393701,
             "gerber_bboxrounded": False,
-            "gerber_circle_steps": 128,
-            "gerber_use_buffer_for_union": True,
 
             # Gerber Advanced Options
             "gerber_aperture_display": False,
@@ -3724,6 +3726,17 @@ class App(QtCore.QObject):
                 # Icon and title
                 self.setWindowIcon(parent.app_icon)
                 self.setWindowTitle("FlatCAM")
+                # self.setStyleSheet("background-image: url(share/flatcam_icon256.png); background-attachment: fixed")
+                # self.setStyleSheet(
+                #     "border-image: url(share/flatcam_icon256.png) 0 0 0 0 stretch stretch; "
+                #     "background-attachment: fixed"
+                # )
+
+                # bgimage = QtGui.QImage('share/flatcam_icon256.png')
+                # s_bgimage = bgimage.scaled(QtCore.QSize(self.frameGeometry().width(), self.frameGeometry().height()))
+                # palette = QtGui.QPalette()
+                # palette.setBrush(10, QtGui.QBrush(bgimage))  # 10 = Windowrole
+                # self.setPalette(palette)
 
                 layout1 = QtWidgets.QVBoxLayout()
                 self.setLayout(layout1)

+ 5 - 0
README.md

@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+9.09.2019
+
+- 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
+
 8.09.2019
 
 - added some documentation strings for methods in FlatCAMApp.App class

+ 11 - 6
camlib.py

@@ -2368,6 +2368,8 @@ class Gerber (Geometry):
         # ### Parsing starts here ## ##
         line_num = 0
         gline = ""
+
+        self.app.inform.emit('%s %d %s.' % (_("Gerber processing. Parsing"), len(glines), _("lines")))
         try:
             for gline in glines:
                 if self.app.abort_flag:
@@ -3277,18 +3279,21 @@ class Gerber (Geometry):
             self.follow_geometry = follow_buffer
 
             # this treats the case when we are storing geometry as solids
-            log.warning("Joining %d polygons." % len(poly_buffer))
 
             if len(poly_buffer) == 0:
                 log.error("Object is not Gerber file or empty. Aborting Object creation.")
                 return 'fail'
 
+            log.warning("Joining %d polygons." % len(poly_buffer))
+            self.app.inform.emit('%s %d %s.' % (_("Gerber processing. Joining"), len(poly_buffer), _("polygons")))
+
             if self.use_buffer_for_union:
                 log.debug("Union by buffer...")
 
                 new_poly = MultiPolygon(poly_buffer)
-                new_poly = new_poly.buffer(0.00000001)
-                new_poly = new_poly.buffer(-0.00000001)
+                if self.app.defaults["gerber_buffering"] == 'full':
+                    new_poly = new_poly.buffer(0.00000001)
+                    new_poly = new_poly.buffer(-0.00000001)
                 log.warning("Union(buffer) done.")
             else:
                 log.debug("Union by union()...")
@@ -3299,15 +3304,15 @@ class Gerber (Geometry):
                 self.solid_geometry = self.solid_geometry.union(new_poly)
             else:
                 self.solid_geometry = self.solid_geometry.difference(new_poly)
-
         except Exception as err:
             ex_type, ex, tb = sys.exc_info()
             traceback.print_tb(tb)
             # print traceback.format_exc()
 
             log.error("Gerber PARSING FAILED. Line %d: %s" % (line_num, gline))
-            loc = 'Gerber Line #%d Gerber Line Content: %s\n' % (line_num, gline) + repr(err)
-            self.app.inform.emit(_("[ERROR]Gerber Parser ERROR.\n%s:") % loc)
+
+            loc = '%s #%d %s: %s\n' % (_("Gerber Line"), line_num, _("Gerber Line Content"), gline) + repr(err)
+            self.app.inform.emit('[ERROR] %s\n%s:' % (_("Gerber Parser ERROR"), loc))
 
     @staticmethod
     def create_flash_geometry(location, aperture, steps_per_circle=None):

+ 15 - 1
flatcamGUI/FlatCAMGUI.py

@@ -4314,10 +4314,23 @@ class GerberGenPrefGroupUI(OptionsGroupUI):
             _("The number of circle steps for Gerber \n"
               "circular aperture linear approximation.")
         )
-        grid0.addWidget(self.circle_steps_label, 1, 0)
         self.circle_steps_entry = IntEntry()
+        grid0.addWidget(self.circle_steps_label, 1, 0)
         grid0.addWidget(self.circle_steps_entry, 1, 1)
 
+        # Milling Type
+        buffering_label = QtWidgets.QLabel('%s:' % _('Buffering'))
+        buffering_label.setToolTip(
+            _("Buffering type:\n"
+              "- None --> best performance, fast file loading but no so good display\n"
+              "- Full --> slow file loading but good visuals. This is the default.\n"
+              "<<WARNING>>: Don't change this unless you know what you are doing !!!")
+        )
+        self.buffering_radio = RadioSet([{'label': _('None'), 'value': 'no'},
+                                          {'label': _('Full'), 'value': 'full'}])
+        grid0.addWidget(buffering_label, 2, 0)
+        grid0.addWidget(self.buffering_radio, 2, 1)
+
         self.layout.addStretch()
 
 
@@ -4370,6 +4383,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
         self.iso_overlap_entry = FloatEntry()
         grid0.addWidget(self.iso_overlap_entry, 2, 1)
 
+        # Milling Type
         milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
         milling_type_label.setToolTip(
             _("Milling type:\n"

+ 1 - 1
flatcamGUI/VisPyVisuals.py

@@ -187,7 +187,7 @@ class ShapeGroup(object):
 
 class ShapeCollectionVisual(CompoundVisual):
 
-    def __init__(self, line_width=1, triangulation='gpc', layers=3, pool=None, **kwargs):
+    def __init__(self, line_width=1, triangulation='vispy', layers=3, pool=None, **kwargs):
         """
         Represents collection of shapes to draw on VisPy scene
         :param line_width: float

+ 58 - 6
flatcamTools/ToolNonCopperClear.py

@@ -1515,7 +1515,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
             self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
 
             if isinstance(ncc_obj, FlatCAMGerber) and not isotooldia:
-                sol_geo = ncc_obj.solid_geometry
+                # unfortunately for this function to work time efficient,
+                # if the Gerber was loaded without buffering then it require the buffering now.
+                if self.app.defaults['gerber_buffering'] == 'no':
+                    sol_geo = ncc_obj.solid_geometry.buffer(0)
+                else:
+                    sol_geo = ncc_obj.solid_geometry
+
                 if has_offset is True:
                     app_obj.inform.emit('[WARNING_NOTCL] %s ...' %
                                         _("Buffering"))
@@ -1523,9 +1529,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[success] %s ...' %
                                         _("Buffering finished"))
                 empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
             elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia:
                 isolated_geo = []
-                self.solid_geometry = ncc_obj.solid_geometry
+
+                # unfortunately for this function to work time efficient,
+                # if the Gerber was loaded without buffering then it require the buffering now.
+                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()
@@ -1609,6 +1623,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[success] %s ...' %
                                         _("Buffering finished"))
                 empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
             elif isinstance(ncc_obj, FlatCAMGeometry):
                 sol_geo = cascaded_union(ncc_obj.solid_geometry)
                 if has_offset is True:
@@ -1618,6 +1635,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[success] %s ...' %
                                         _("Buffering finished"))
                 empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
             else:
                 app_obj.inform.emit('[ERROR_NOTCL] %s' %
                                     _('The selected object is not suitable for copper clearing.'))
@@ -1832,6 +1852,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[success] %s ...' %
                                         _("Buffering finished"))
                 empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
 
             elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia:
                 isolated_geo = []
@@ -1922,6 +1944,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[success] %s ...' %
                                         _("Buffering finished"))
                 empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
 
             elif isinstance(ncc_obj, FlatCAMGeometry):
                 sol_geo = cascaded_union(ncc_obj.solid_geometry)
@@ -1932,7 +1956,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[success] %s ...' %
                                         _("Buffering finished"))
                 empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
-
+                if empty == 'fail':
+                    return 'fail'
             else:
                 app_obj.inform.emit('[ERROR_NOTCL] %s' %
                                     _('The selected object is not suitable for copper clearing.'))
@@ -2509,16 +2534,43 @@ class NonCopperClear(FlatCAMTool, Gerber):
     #     # Background
     #     self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
 
-    @staticmethod
-    def get_ncc_empty_area(target, boundary=None):
+    def get_ncc_empty_area(self, target, boundary=None):
         """
         Returns the complement of target geometry within
         the given boundary polygon. If not specified, it defaults to
         the rectangular bounding box of target geometry.
         """
+        geo_len = len(target)
+        pol_nr = 0
+        old_disp_number = 0
+
         if boundary is None:
             boundary = target.envelope
-        return boundary.difference(target)
+        else:
+            boundary = boundary
+        try:
+            ret_val = boundary.difference(target)
+        except Exception as e:
+            try:
+                for el in target:
+                    if self.app.abort_flag:
+                        # graceful abort requested by the user
+                        raise FlatCAMApp.GracefulException
+                    boundary = boundary.difference(el)
+                    pol_nr += 1
+                    disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 99]))
+
+                    if disp_number > old_disp_number and disp_number <= 100:
+                        self.app.proc_container.update_view_text(' %d%%' % disp_number)
+                        old_disp_number = disp_number
+                return boundary
+            except Exception as e:
+                self.app.inform.emit('[ERROR_NOTCL] %s' %
+                                     _("Try to use the Buffering Type = Full in Preferences -> Gerber General. "
+                                       "Reload the Gerber file after this change."))
+                return 'fail'
+
+        return ret_val
 
     def reset_fields(self):
         self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))