diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 2bfdcf2d..08d39abb 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -843,6 +843,7 @@ class App(QtCore.QObject): "tools_transform_mirror_reference": False, "tools_transform_mirror_point": (0, 0), "tools_transform_buffer_dis": 0.0, + "tools_transform_buffer_factor": 100.0, "tools_transform_buffer_corner": True, # SolderPaste Tool @@ -1465,6 +1466,7 @@ class App(QtCore.QObject): "tools_transform_mirror_reference": self.ui.tools_defaults_form.tools_transform_group.mirror_reference_cb, "tools_transform_mirror_point": self.ui.tools_defaults_form.tools_transform_group.flip_ref_entry, "tools_transform_buffer_dis": self.ui.tools_defaults_form.tools_transform_group.buffer_entry, + "tools_transform_buffer_factor": self.ui.tools_defaults_form.tools_transform_group.buffer_factor_entry, "tools_transform_buffer_corner": self.ui.tools_defaults_form.tools_transform_group.buffer_rounded_cb, # SolderPaste Dispensing Tool diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 7d22fe6a..d28e40ab 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -2215,8 +2215,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber): Gerber.skew(self, angle_x=angle_x, angle_y=angle_y, point=point) self.replotApertures.emit() - def buffer(self, distance, join): - Gerber.buffer(self, distance=distance, join=join) + def buffer(self, distance, join, factor=None): + Gerber.buffer(self, distance=distance, join=join, factor=factor) self.replotApertures.emit() def serialize(self): diff --git a/README.md b/README.md index fb38722a..d3419233 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing. ================================================= +30.12.2019 + +- Buffer sub-tool in Transform Tool: added the possibility to apply a factor effectively scaling the aperture size thus the copper features sizes +- in Transform Tool adjusted the GUI + 29.12.2019 - the Apply button text in Preferences is now made red when changes were made and require to be applied diff --git a/camlib.py b/camlib.py index 75a440db..7f87351a 100644 --- a/camlib.py +++ b/camlib.py @@ -2118,11 +2118,11 @@ class Geometry(object): # self.solid_geometry = affinity.skew(self.solid_geometry, angle_x, angle_y, # origin=(px, py)) - def buffer(self, distance, join): + def buffer(self, distance, join, factor): """ - :param distance: - :param join: + :param distance: if 'factor' is True then distance is the factor + :param factor: True or False (None) :return: """ @@ -2145,7 +2145,10 @@ class Geometry(object): self.app.proc_container.update_view_text(' %d%%' % disp_number) self.old_disp_number = disp_number - return obj.buffer(distance, resolution=self.geo_steps_per_circle, join_style=join) + if factor is None: + return obj.buffer(distance, resolution=self.geo_steps_per_circle, join_style=join) + else: + return affinity.scale(obj, xfact=distance, yfact=distance, origin='center') except AttributeError: return obj @@ -2155,20 +2158,23 @@ class Geometry(object): # variables to display the percentage of work done self.geo_len = 0 try: - for __ in self.tools[tool]['solid_geometry']: - self.geo_len += 1 + self.geo_len += len(self.tools[tool]['solid_geometry']) except TypeError: - self.geo_len = 1 + self.geo_len += 1 self.old_disp_number = 0 self.el_count = 0 - self.tools[tool]['solid_geometry'] = buffer_geom(self.tools[tool]['solid_geometry']) + res = buffer_geom(self.tools[tool]['solid_geometry']) + try: + __ = iter(res) + self.tools[tool]['solid_geometry'] = res + except TypeError: + self.tools[tool]['solid_geometry'] = [res] # variables to display the percentage of work done self.geo_len = 0 try: - for __ in self.solid_geometry: - self.geo_len += 1 + self.geo_len = len(self.solid_geometry) except TypeError: self.geo_len = 1 self.old_disp_number = 0 @@ -2182,6 +2188,7 @@ class Geometry(object): self.app.proc_container.new_text = '' + class AttrDict(dict): def __init__(self, *args, **kwargs): super(AttrDict, self).__init__(*args, **kwargs) diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py index d322232b..2ec568bd 100644 --- a/flatcamGUI/PreferencesUI.py +++ b/flatcamGUI/PreferencesUI.py @@ -6416,6 +6416,23 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.buffer_label, 17, 0) grid0.addWidget(self.buffer_entry, 17, 1) + self.buffer_factor_label = QtWidgets.QLabel('%s:' % _("Factor")) + self.buffer_factor_label.setToolTip( + _("A positive value will create the effect of dilation,\n" + "while a negative value will create the effect of erosion.\n" + "Each geometry element of the object will be increased\n" + "or decreased by the 'factor'.") + ) + + self.buffer_factor_entry = FCDoubleSpinner(suffix='%') + self.buffer_factor_entry.set_range(-100.0000, 1000.0000) + self.buffer_factor_entry.set_precision(self.decimals) + self.buffer_factor_entry.setWrapping(True) + self.buffer_factor_entry.setSingleStep(1) + + grid0.addWidget(self.buffer_factor_label, 18, 0) + grid0.addWidget(self.buffer_factor_entry, 18, 1) + self.buffer_rounded_cb = FCCheckBox() self.buffer_rounded_cb.setText('%s' % _("Rounded")) self.buffer_rounded_cb.setToolTip( @@ -6425,9 +6442,8 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI): "of the buffered shape.") ) - grid0.addWidget(self.buffer_rounded_cb, 18, 0, 1, 2) + grid0.addWidget(self.buffer_rounded_cb, 19, 0, 1, 2) - grid0.addWidget(QtWidgets.QLabel(''), 19, 0, 1, 2) self.layout.addStretch() diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py index 894851c6..adba5941 100644 --- a/flatcamParsers/ParseExcellon.py +++ b/flatcamParsers/ParseExcellon.py @@ -1459,11 +1459,11 @@ class Excellon(Geometry): self.create_geometry() self.app.proc_container.new_text = '' - def buffer(self, distance, join): + def buffer(self, distance, join, factor): """ - :param distance: - :param join: + :param distance: if 'factor' is True then distance is the factor + :param factor: True or False (None) :return: """ log.debug("flatcamParsers.ParseExcellon.Excellon.buffer()") @@ -1479,13 +1479,24 @@ class Excellon(Geometry): return new_obj else: try: - return obj.buffer(distance, resolution=self.geo_steps_per_circle) + if factor is None: + return obj.buffer(distance, resolution=self.geo_steps_per_circle) + else: + return affinity.scale(obj, xfact=distance, yfact=distance, origin='center') except AttributeError: return obj # buffer solid_geometry for tool, tool_dict in list(self.tools.items()): - self.tools[tool]['solid_geometry'] = buffer_geom(tool_dict['solid_geometry']) - self.tools[tool]['C'] += distance + res = buffer_geom(tool_dict['solid_geometry']) + try: + __ = iter(res) + self.tools[tool]['solid_geometry'] = res + except TypeError: + self.tools[tool]['solid_geometry'] = [res] + if factor is None: + self.tools[tool]['C'] += distance + else: + self.tools[tool]['C'] *= distance self.create_geometry() diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py index 876947a0..6f79c31a 100644 --- a/flatcamParsers/ParseGerber.py +++ b/flatcamParsers/ParseGerber.py @@ -2188,14 +2188,14 @@ class Gerber(Geometry): except Exception as e: log.debug('camlib.Gerber.rotate() Exception --> %s' % str(e)) return 'fail' - self.app.inform.emit('[success] %s' % - _("Gerber Rotate done.")) + self.app.inform.emit('[success] %s' % _("Gerber Rotate done.")) self.app.proc_container.new_text = '' - def buffer(self, distance, join): + def buffer(self, distance, join, factor=None): """ - :param distance: + :param distance: if 'factor' is True then distance is the factor + :param factor: True or False (None) :return: """ log.debug("parseGerber.Gerber.buffer()") @@ -2206,69 +2206,143 @@ class Gerber(Geometry): # variables to display the percentage of work done self.geo_len = 0 try: - for __ in self.solid_geometry: - self.geo_len += 1 - except TypeError: + self.geo_len = len(self.solid_geometry) + except (TypeError, ValueError): self.geo_len = 1 self.old_disp_number = 0 self.el_count = 0 - def buffer_geom(obj): - if type(obj) is list: - new_obj = [] - for g in obj: - new_obj.append(buffer_geom(g)) - return new_obj - else: - try: - self.el_count += 1 - disp_number = int(np.interp(self.el_count, [0, self.geo_len], [0, 100])) - if self.old_disp_number < disp_number <= 100: - self.app.proc_container.update_view_text(' %d%%' % disp_number) - self.old_disp_number = disp_number + if factor is None: + def buffer_geom(obj): + if type(obj) is list: + new_obj = [] + for g in obj: + new_obj.append(buffer_geom(g)) + return new_obj + else: + try: + self.el_count += 1 + disp_number = int(np.interp(self.el_count, [0, self.geo_len], [0, 100])) + if self.old_disp_number < disp_number <= 100: + self.app.proc_container.update_view_text(' %d%%' % disp_number) + self.old_disp_number = disp_number - return obj.buffer(distance, resolution=self.steps_per_circle, join_style=join) - except AttributeError: - return obj + return obj.buffer(distance, resolution=int(self.steps_per_circle), join_style=join) - self.solid_geometry = buffer_geom(self.solid_geometry) + except AttributeError: + return obj - # we need to buffer the geometry stored in the Gerber apertures, too - try: + res = buffer_geom(self.solid_geometry) + try: + __ = iter(res) + self.solid_geometry = res + except TypeError: + self.solid_geometry = [res] + + # we need to buffer the geometry stored in the Gerber apertures, too + try: + for apid in self.apertures: + new_geometry = list() + if 'geometry' in self.apertures[apid]: + for geo_el in self.apertures[apid]['geometry']: + new_geo_el = dict() + if 'solid' in geo_el: + new_geo_el['solid'] = buffer_geom(geo_el['solid']) + if 'follow' in geo_el: + new_geo_el['follow'] = geo_el['follow'] + if 'clear' in geo_el: + new_geo_el['clear'] = buffer_geom(geo_el['clear']) + new_geometry.append(new_geo_el) + + self.apertures[apid]['geometry'] = deepcopy(new_geometry) + + try: + if str(self.apertures[apid]['type']) == 'R' or str(self.apertures[apid]['type']) == 'O': + self.apertures[apid]['width'] += (distance * 2) + self.apertures[apid]['height'] += (distance * 2) + elif str(self.apertures[apid]['type']) == 'P': + self.apertures[apid]['diam'] += (distance * 2) + self.apertures[apid]['nVertices'] += (distance * 2) + except KeyError: + pass + + try: + if self.apertures[apid]['size'] is not None: + self.apertures[apid]['size'] = float(self.apertures[apid]['size'] + (distance * 2)) + except KeyError: + pass + except Exception as e: + log.debug('camlib.Gerber.buffer() Exception --> %s' % str(e)) + return 'fail' + else: + try: + for apid in self.apertures: + try: + if str(self.apertures[apid]['type']) == 'R' or str(self.apertures[apid]['type']) == 'O': + self.apertures[apid]['width'] *= distance + self.apertures[apid]['height'] *= distance + elif str(self.apertures[apid]['type']) == 'P': + self.apertures[apid]['diam'] *= distance + self.apertures[apid]['nVertices'] *= distance + except KeyError: + pass + + try: + if self.apertures[apid]['size'] is not None: + self.apertures[apid]['size'] = float(self.apertures[apid]['size']) * distance + except KeyError: + pass + + new_geometry = list() + if 'geometry' in self.apertures[apid]: + for geo_el in self.apertures[apid]['geometry']: + new_geo_el = dict() + if 'follow' in geo_el: + new_geo_el['follow'] = geo_el['follow'] + size = float(self.apertures[apid]['size']) + if isinstance(new_geo_el['follow'], Point): + if str(self.apertures[apid]['type']) == 'C': + new_geo_el['solid'] = geo_el['follow'].buffer( + size / 1.9999, + resolution=int(self.steps_per_circle) + ) + elif str(self.apertures[apid]['type']) == 'R': + width = self.apertures[apid]['width'] + height = self.apertures[apid]['height'] + minx = new_geo_el['follow'].x - width / 2 + maxx = new_geo_el['follow'].x + width / 2 + miny = new_geo_el['follow'].y - height / 2 + maxy = new_geo_el['follow'].y + height / 2 + + geo_p = shply_box(minx, miny, maxx, maxy) + new_geo_el['solid'] = geo_p + else: + log.debug("flatcamParsers.ParseGerber.Gerber.buffer() --> " + "ap type not supported") + else: + new_geo_el['solid'] = geo_el['follow'].buffer( + size/1.9999, + resolution=int(self.steps_per_circle) + ) + if 'clear' in geo_el: + new_geo_el['clear'] = geo_el['clear'] + new_geometry.append(new_geo_el) + + self.apertures[apid]['geometry'] = deepcopy(new_geometry) + except Exception as e: + log.debug('camlib.Gerber.buffer() Exception --> %s' % str(e)) + return 'fail' + + # make the new solid_geometry + new_solid_geo = list() for apid in self.apertures: - new_geometry = list() if 'geometry' in self.apertures[apid]: - for geo_el in self.apertures[apid]['geometry']: - new_geo_el = dict() - if 'solid' in geo_el: - new_geo_el['solid'] = buffer_geom(geo_el['solid']) - if 'follow' in geo_el: - new_geo_el['follow'] = buffer_geom(geo_el['follow']) - if 'clear' in geo_el: - new_geo_el['clear'] = buffer_geom(geo_el['clear']) - new_geometry.append(new_geo_el) + new_solid_geo += [geo_el['solid'] for geo_el in self.apertures[apid]['geometry']] - self.apertures[apid]['geometry'] = deepcopy(new_geometry) - - try: - if str(self.apertures[apid]['type']) == 'R' or str(self.apertures[apid]['type']) == 'O': - self.apertures[apid]['width'] += (distance * 2) - self.apertures[apid]['height'] += (distance * 2) - elif str(self.apertures[apid]['type']) == 'P': - self.apertures[apid]['diam'] += (distance * 2) - self.apertures[apid]['nVertices'] += (distance * 2) - except KeyError: - pass - - try: - if self.apertures[apid]['size'] is not None: - self.apertures[apid]['size'] = float(self.apertures[apid]['size'] + (distance * 2)) - except KeyError: - pass - except Exception as e: - log.debug('camlib.Gerber.buffer() Exception --> %s' % str(e)) - return 'fail' + self.solid_geometry = MultiPolygon(new_solid_geo) + self.solid_geometry = self.solid_geometry.buffer(0.000001) + self.solid_geometry = self.solid_geometry.buffer(-0.000001) self.app.inform.emit('[success] %s' % _("Gerber Buffer done.")) self.app.proc_container.new_text = '' diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py index 566372c2..cbfe6f34 100644 --- a/flatcamTools/ToolTransform.py +++ b/flatcamTools/ToolTransform.py @@ -89,7 +89,10 @@ class ToolTransform(FlatCAMTool): grid0.addWidget(self.rotate_entry, 1, 1) grid0.addWidget(self.rotate_button, 1, 2) - grid0.addWidget(QtWidgets.QLabel(''), 2, 0) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 2, 0, 1, 3) # ## Skew Title skew_title_label = QtWidgets.QLabel("%s" % self.skewName) @@ -139,7 +142,10 @@ class ToolTransform(FlatCAMTool): grid0.addWidget(self.skewy_entry, 5, 1) grid0.addWidget(self.skewy_button, 5, 2) - grid0.addWidget(QtWidgets.QLabel(''), 6, 0) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 6, 0, 1, 3) # ## Scale Title scale_title_label = QtWidgets.QLabel("%s" % self.scaleName) @@ -208,7 +214,11 @@ class ToolTransform(FlatCAMTool): grid0.addWidget(self.scale_link_cb, 10, 0) grid0.addWidget(self.scale_zero_ref_cb, 10, 1) - grid0.addWidget(QtWidgets.QLabel(''), 11, 0) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 11, 0, 1, 3) # ## Offset Title offset_title_label = QtWidgets.QLabel("%s" % self.offsetName) @@ -256,7 +266,10 @@ class ToolTransform(FlatCAMTool): grid0.addWidget(self.offy_entry, 14, 1) grid0.addWidget(self.offy_button, 14, 2) - grid0.addWidget(QtWidgets.QLabel(''), 15, 0, 1, 3) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 15, 0, 1, 3) # ## Flip Title flip_title_label = QtWidgets.QLabel("%s" % self.flipName) @@ -323,7 +336,10 @@ class ToolTransform(FlatCAMTool): grid0.addWidget(self.flip_ref_button, 20, 0, 1, 3) - grid0.addWidget(QtWidgets.QLabel(''), 21, 0, 1, 3) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 21, 0, 1, 3) # ## Buffer Title buffer_title_label = QtWidgets.QLabel("%s" % self.bufferName) @@ -343,13 +359,11 @@ class ToolTransform(FlatCAMTool): self.buffer_entry.setWrapping(True) self.buffer_entry.set_range(-9999.9999, 9999.9999) - # self.rotate_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) - self.buffer_button = FCButton() - self.buffer_button.set_value(_("Buffer")) + self.buffer_button.set_value(_("Buffer D")) self.buffer_button.setToolTip( _("Create the buffer effect on each geometry,\n" - "element from the selected object.") + "element from the selected object, using the distance.") ) self.buffer_button.setMinimumWidth(90) @@ -357,8 +371,33 @@ class ToolTransform(FlatCAMTool): grid0.addWidget(self.buffer_entry, 23, 1) grid0.addWidget(self.buffer_button, 23, 2) - self.buffer_rounded_cb = FCCheckBox() - self.buffer_rounded_cb.setText('%s' % _("Rounded")) + self.buffer_factor_label = QtWidgets.QLabel('%s:' % _("Factor")) + self.buffer_factor_label.setToolTip( + _("A positive value will create the effect of dilation,\n" + "while a negative value will create the effect of erosion.\n" + "Each geometry element of the object will be increased\n" + "or decreased by the 'factor'.") + ) + + self.buffer_factor_entry = FCDoubleSpinner(suffix='%') + self.buffer_factor_entry.set_range(-100.0000, 1000.0000) + self.buffer_factor_entry.set_precision(self.decimals) + self.buffer_factor_entry.setWrapping(True) + self.buffer_factor_entry.setSingleStep(1) + + self.buffer_factor_button = FCButton() + self.buffer_factor_button.set_value(_("Buffer F")) + self.buffer_factor_button.setToolTip( + _("Create the buffer effect on each geometry,\n" + "element from the selected object, using the factor.") + ) + self.buffer_factor_button.setMinimumWidth(90) + + grid0.addWidget(self.buffer_factor_label, 24, 0) + grid0.addWidget(self.buffer_factor_entry, 24, 1) + grid0.addWidget(self.buffer_factor_button, 24, 2) + + self.buffer_rounded_cb = FCCheckBox('%s' % _("Rounded")) self.buffer_rounded_cb.setToolTip( _("If checked then the buffer will surround the buffered shape,\n" "every corner will be rounded.\n" @@ -366,9 +405,9 @@ class ToolTransform(FlatCAMTool): "of the buffered shape.") ) - grid0.addWidget(self.buffer_rounded_cb, 24, 0, 1, 3) + grid0.addWidget(self.buffer_rounded_cb, 25, 0, 1, 3) - grid0.addWidget(QtWidgets.QLabel(''), 25, 0, 1, 3) + grid0.addWidget(QtWidgets.QLabel(''), 26, 0, 1, 3) self.transform_lay.addStretch() @@ -383,7 +422,8 @@ class ToolTransform(FlatCAMTool): self.flipx_button.clicked.connect(self.on_flipx) self.flipy_button.clicked.connect(self.on_flipy) self.flip_ref_button.clicked.connect(self.on_flip_add_coords) - self.buffer_button.clicked.connect(self.on_buffer) + self.buffer_button.clicked.connect(self.on_buffer_by_distance) + self.buffer_factor_button.clicked.connect(self.on_buffer_by_factor) # self.rotate_entry.returnPressed.connect(self.on_rotate) # self.skewx_entry.returnPressed.connect(self.on_skewx) @@ -392,7 +432,7 @@ class ToolTransform(FlatCAMTool): # self.scaley_entry.returnPressed.connect(self.on_scaley) # self.offx_entry.returnPressed.connect(self.on_offx) # self.offy_entry.returnPressed.connect(self.on_offy) - # self.buffer_entry.returnPressed.connect(self.on_buffer) + # self.buffer_entry.returnPressed.connect(self.on_buffer_by_distance) def run(self, toggle=True): self.app.report_usage("ToolTransform()") @@ -486,6 +526,11 @@ class ToolTransform(FlatCAMTool): else: self.buffer_entry.set_value(0.0) + if self.app.defaults["tools_transform_buffer_factor"]: + self.buffer_factor_entry.set_value(self.app.defaults["tools_transform_buffer_factor"]) + else: + self.buffer_factor_entry.set_value(100.0) + if self.app.defaults["tools_transform_buffer_corner"]: self.buffer_rounded_cb.set_value(self.app.defaults["tools_transform_buffer_corner"]) else: @@ -589,13 +634,23 @@ class ToolTransform(FlatCAMTool): self.app.worker_task.emit({'fcn': self.on_offset, 'params': [axis, value]}) return - def on_buffer(self): + def on_buffer_by_distance(self): value = self.buffer_entry.get_value() join = 1 if self.buffer_rounded_cb.get_value() else 2 self.app.worker_task.emit({'fcn': self.on_buffer_action, 'params': [value, join]}) return + def on_buffer_by_factor(self): + value = self.buffer_factor_entry.get_value() / 100.0 + join = 1 if self.buffer_rounded_cb.get_value() else 2 + + # tell the buffer method to use the factor + factor = True + + self.app.worker_task.emit({'fcn': self.on_buffer_action, 'params': [value, join, factor]}) + return + def on_rotate_action(self, num): obj_list = self.app.collection.get_selected() xminlist = [] @@ -604,8 +659,7 @@ class ToolTransform(FlatCAMTool): ymaxlist = [] if not obj_list: - self.app.inform.emit('[WARNING_NOTCL] %s' % - _("No object selected. Please Select an object to rotate!")) + self.app.inform.emit('[WARNING_NOTCL] %s' % _("No object selected. Please Select an object to rotate!")) return else: with self.app.proc_container.new(_("Appying Rotate")): @@ -874,7 +928,7 @@ class ToolTransform(FlatCAMTool): (_("Due of"), str(e), _("action was not executed."))) return - def on_buffer_action(self, value, join): + def on_buffer_action(self, value, join, factor=None): obj_list = self.app.collection.get_selected() if not obj_list: @@ -887,17 +941,17 @@ class ToolTransform(FlatCAMTool): if isinstance(sel_obj, FlatCAMCNCjob): self.app.inform.emit(_("CNCJob objects can't be buffered.")) elif sel_obj.kind.lower() == 'gerber': - sel_obj.buffer(value, join) + sel_obj.buffer(value, join, factor) sel_obj.source_file = self.app.export_gerber(obj_name=sel_obj.options['name'], filename=None, local_use=sel_obj, use_thread=False) elif sel_obj.kind.lower() == 'excellon': - sel_obj.buffer(value, join) + sel_obj.buffer(value, join, factor) sel_obj.source_file = self.app.export_excellon(obj_name=sel_obj.options['name'], filename=None, local_use=sel_obj, use_thread=False) elif sel_obj.kind.lower() == 'geometry': - sel_obj.buffer(value, join) + sel_obj.buffer(value, join, factor) self.app.object_changed.emit(sel_obj) sel_obj.plot()