- 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

This commit is contained in:
Marius Stanciu 2019-09-09 02:41:14 +03:00 committed by Marius
parent c78404b737
commit 198e055328
6 changed files with 108 additions and 19 deletions

View File

@ -423,6 +423,7 @@ class App(QtCore.QObject):
"gerber_solid": self.ui.gerber_defaults_form.gerber_gen_group.solid_cb, "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_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_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 Options
"gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry, "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_plot": True,
"gerber_solid": True, "gerber_solid": True,
"gerber_multicolored": False, "gerber_multicolored": False,
"gerber_circle_steps": 128,
"gerber_use_buffer_for_union": True,
"gerber_buffering": "full",
# Gerber Options
"gerber_isotooldia": 0.00787402, "gerber_isotooldia": 0.00787402,
"gerber_isopasses": 1, "gerber_isopasses": 1,
"gerber_isooverlap": 0.00393701, "gerber_isooverlap": 0.00393701,
# Gerber Options
"gerber_combine_passes": False,
"gerber_milling_type": "cl", "gerber_milling_type": "cl",
"gerber_combine_passes": False,
"gerber_noncoppermargin": 0.00393701, "gerber_noncoppermargin": 0.00393701,
"gerber_noncopperrounded": False, "gerber_noncopperrounded": False,
"gerber_bboxmargin": 0.00393701, "gerber_bboxmargin": 0.00393701,
"gerber_bboxrounded": False, "gerber_bboxrounded": False,
"gerber_circle_steps": 128,
"gerber_use_buffer_for_union": True,
# Gerber Advanced Options # Gerber Advanced Options
"gerber_aperture_display": False, "gerber_aperture_display": False,
@ -3724,6 +3726,17 @@ class App(QtCore.QObject):
# Icon and title # Icon and title
self.setWindowIcon(parent.app_icon) self.setWindowIcon(parent.app_icon)
self.setWindowTitle("FlatCAM") 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() layout1 = QtWidgets.QVBoxLayout()
self.setLayout(layout1) self.setLayout(layout1)

View File

@ -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 8.09.2019
- added some documentation strings for methods in FlatCAMApp.App class - added some documentation strings for methods in FlatCAMApp.App class

View File

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

View File

@ -4314,10 +4314,23 @@ class GerberGenPrefGroupUI(OptionsGroupUI):
_("The number of circle steps for Gerber \n" _("The number of circle steps for Gerber \n"
"circular aperture linear approximation.") "circular aperture linear approximation.")
) )
grid0.addWidget(self.circle_steps_label, 1, 0)
self.circle_steps_entry = IntEntry() self.circle_steps_entry = IntEntry()
grid0.addWidget(self.circle_steps_label, 1, 0)
grid0.addWidget(self.circle_steps_entry, 1, 1) 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() self.layout.addStretch()
@ -4370,6 +4383,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
self.iso_overlap_entry = FloatEntry() self.iso_overlap_entry = FloatEntry()
grid0.addWidget(self.iso_overlap_entry, 2, 1) grid0.addWidget(self.iso_overlap_entry, 2, 1)
# Milling Type
milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type')) milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
milling_type_label.setToolTip( milling_type_label.setToolTip(
_("Milling type:\n" _("Milling type:\n"

View File

@ -187,7 +187,7 @@ class ShapeGroup(object):
class ShapeCollectionVisual(CompoundVisual): 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 Represents collection of shapes to draw on VisPy scene
:param line_width: float :param line_width: float

View File

@ -1515,7 +1515,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.inform.emit(_("NCC Tool. Calculate 'empty' area.")) self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
if isinstance(ncc_obj, FlatCAMGerber) and not isotooldia: 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: if has_offset is True:
app_obj.inform.emit('[WARNING_NOTCL] %s ...' % app_obj.inform.emit('[WARNING_NOTCL] %s ...' %
_("Buffering")) _("Buffering"))
@ -1523,9 +1529,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.inform.emit('[success] %s ...' % app_obj.inform.emit('[success] %s ...' %
_("Buffering finished")) _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia: elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia:
isolated_geo = [] 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 # if milling type is climb then the move is counter-clockwise around features
milling_type = self.milling_type_radio.get_value() milling_type = self.milling_type_radio.get_value()
@ -1609,6 +1623,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.inform.emit('[success] %s ...' % app_obj.inform.emit('[success] %s ...' %
_("Buffering finished")) _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
elif isinstance(ncc_obj, FlatCAMGeometry): elif isinstance(ncc_obj, FlatCAMGeometry):
sol_geo = cascaded_union(ncc_obj.solid_geometry) sol_geo = cascaded_union(ncc_obj.solid_geometry)
if has_offset is True: if has_offset is True:
@ -1618,6 +1635,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.inform.emit('[success] %s ...' % app_obj.inform.emit('[success] %s ...' %
_("Buffering finished")) _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
else: else:
app_obj.inform.emit('[ERROR_NOTCL] %s' % app_obj.inform.emit('[ERROR_NOTCL] %s' %
_('The selected object is not suitable for copper clearing.')) _('The selected object is not suitable for copper clearing.'))
@ -1832,6 +1852,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.inform.emit('[success] %s ...' % app_obj.inform.emit('[success] %s ...' %
_("Buffering finished")) _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia: elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia:
isolated_geo = [] isolated_geo = []
@ -1922,6 +1944,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.inform.emit('[success] %s ...' % app_obj.inform.emit('[success] %s ...' %
_("Buffering finished")) _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
elif isinstance(ncc_obj, FlatCAMGeometry): elif isinstance(ncc_obj, FlatCAMGeometry):
sol_geo = cascaded_union(ncc_obj.solid_geometry) sol_geo = cascaded_union(ncc_obj.solid_geometry)
@ -1932,7 +1956,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.inform.emit('[success] %s ...' % app_obj.inform.emit('[success] %s ...' %
_("Buffering finished")) _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
else: else:
app_obj.inform.emit('[ERROR_NOTCL] %s' % app_obj.inform.emit('[ERROR_NOTCL] %s' %
_('The selected object is not suitable for copper clearing.')) _('The selected object is not suitable for copper clearing.'))
@ -2509,16 +2534,43 @@ class NonCopperClear(FlatCAMTool, Gerber):
# # Background # # Background
# self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]}) # self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
@staticmethod def get_ncc_empty_area(self, target, boundary=None):
def get_ncc_empty_area(target, boundary=None):
""" """
Returns the complement of target geometry within Returns the complement of target geometry within
the given boundary polygon. If not specified, it defaults to the given boundary polygon. If not specified, it defaults to
the rectangular bounding box of target geometry. the rectangular bounding box of target geometry.
""" """
geo_len = len(target)
pol_nr = 0
old_disp_number = 0
if boundary is None: if boundary is None:
boundary = target.envelope 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): def reset_fields(self):
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex())) self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))