From b1b140634b85fe277fddeacda72a8030cb2e56c4 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Mon, 23 Dec 2019 22:59:01 +0200 Subject: [PATCH] - in Tool Transform added a new feature named 'Buffer'. For Geometry and Gerber objects will create (and replace) a geometry at a distance from the original geometry and for Excellon will adjust the Tool diameters --- FlatCAMApp.py | 4 + FlatCAMObj.py | 17 +++- ObjectCollection.py | 5 -- README.md | 3 +- camlib.py | 63 +++++++++++++++ flatcamGUI/PreferencesUI.py | 50 ++++++++++-- flatcamParsers/ParseExcellon.py | 33 +++++++- flatcamParsers/ParseGerber.py | 81 +++++++++++++++++++ flatcamTools/ToolTransform.py | 136 ++++++++++++++++++++++++++++---- 9 files changed, 359 insertions(+), 33 deletions(-) diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 0df5f314..2ba31254 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -830,6 +830,8 @@ class App(QtCore.QObject): "tools_transform_offset_y": 0.0, "tools_transform_mirror_reference": False, "tools_transform_mirror_point": (0, 0), + "tools_transform_buffer_dis": 0.0, + "tools_transform_buffer_corner": True, # SolderPaste Tool "tools_solderpaste_tools": "1.0, 0.3", @@ -1432,6 +1434,8 @@ class App(QtCore.QObject): "tools_transform_offset_y": self.ui.tools_defaults_form.tools_transform_group.offy_entry, "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_corner": self.ui.tools_defaults_form.tools_transform_group.buffer_rounded_cb, # SolderPaste Dispensing Tool "tools_solderpaste_tools": self.ui.tools_defaults_form.tools_solderpaste_group.nozzle_tool_dia_entry, diff --git a/FlatCAMObj.py b/FlatCAMObj.py index dbd5eb48..4ac69b82 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -599,7 +599,9 @@ class FlatCAMGerber(FlatCAMObj, Gerber): def __init__(self, name): self.decimals = self.app.decimals - Gerber.__init__(self, steps_per_circle=int(self.app.defaults["gerber_circle_steps"])) + self.circle_steps = int(self.app.defaults["gerber_circle_steps"]) + + Gerber.__init__(self, steps_per_circle=self.circle_steps) FlatCAMObj.__init__(self, name) self.kind = "gerber" @@ -2199,6 +2201,10 @@ 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) + self.replotApertures.emit() + def serialize(self): return { "options": self.options, @@ -2217,7 +2223,9 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): def __init__(self, name): self.decimals = self.app.decimals - Excellon.__init__(self, geo_steps_per_circle=int(self.app.defaults["geometry_circle_steps"])) + self.circle_steps = int(self.app.defaults["geometry_circle_steps"]) + + Excellon.__init__(self, geo_steps_per_circle=self.circle_steps) FlatCAMObj.__init__(self, name) self.kind = "excellon" @@ -3545,8 +3553,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): def __init__(self, name): self.decimals = self.app.decimals + + self.circle_steps = int(self.app.defaults["geometry_circle_steps"]) + FlatCAMObj.__init__(self, name) - Geometry.__init__(self, geo_steps_per_circle=int(self.app.defaults["geometry_circle_steps"])) + Geometry.__init__(self, geo_steps_per_circle=self.circle_steps) self.kind = "geometry" diff --git a/ObjectCollection.py b/ObjectCollection.py index d2c37096..f134fc32 100644 --- a/ObjectCollection.py +++ b/ObjectCollection.py @@ -787,11 +787,6 @@ class ObjectCollection(QtCore.QAbstractItemModel): # FlatCAMApp.App.log.debug("Current: %s, Previous %s" % (str(current), str(previous))) try: - # delete selection shape - self.app.delete_selection_shape() - for o in self.get_list(): - o.selection_shape_drawn = False - obj = current.indexes()[0].internalPointer().obj self.item_selected.emit(obj.options['name']) diff --git a/README.md b/README.md index eef59695..b4160bec 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,9 @@ CAD program, and create G-Code for Isolation routing. - speed up the plotting in OpenGL(3D) graphic mode - spped up the color setting for Gerber object when using the OpenGL(3D) graphic mode - setting color for Gerber objects work on a selection of Gerber objects -- when the selection is changed in the Project Tree the selection shape on canvas is deleted +- ~~when the selection is changed in the Project Tree the selection shape on canvas is deleted~~ - if an object is selected on Project Tree and it does not have the selection shape drawn, first click on canvas over it will draw the selection shape +- in Tool Transform added a new feature named 'Buffer'. For Geometry and Gerber objects will create (and replace) a geometry at a distance from the original geometry and for Excellon will adjust the Tool diameters 22.12.2019 diff --git a/camlib.py b/camlib.py index f699ee36..c1751bcb 100644 --- a/camlib.py +++ b/camlib.py @@ -2118,6 +2118,69 @@ class Geometry(object): # self.solid_geometry = affinity.skew(self.solid_geometry, angle_x, angle_y, # origin=(px, py)) + def buffer(self, distance, join): + """ + + :param distance: + :param join: + :return: + """ + + log.debug("camlib.Geometry.buffer()") + + if distance == 0: + return + + 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.geo_steps_per_circle, join_style=join) + except AttributeError: + return obj + + try: + if self.multigeo is True: + for tool in self.tools: + # variables to display the percentage of work done + self.geo_len = 0 + try: + for __ in self.tools[tool]['solid_geometry']: + self.geo_len += 1 + except TypeError: + 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']) + + # 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 = 1 + self.old_disp_number = 0 + self.el_count = 0 + + self.solid_geometry = buffer_geom(self.solid_geometry) + + self.app.inform.emit('[success] %s...' % _('Object was buffered')) + except AttributeError: + self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed to buffer. No object selected")) + + self.app.proc_container.new_text = '' class AttrDict(dict): def __init__(self, *args, **kwargs): diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py index 6b34a72c..f06e983f 100644 --- a/flatcamGUI/PreferencesUI.py +++ b/flatcamGUI/PreferencesUI.py @@ -5378,7 +5378,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.skewy_label, 4, 0) grid0.addWidget(self.skewy_entry, 4, 1) - # ## Scale factor on X axis + # ## Scale scale_title_lbl = QtWidgets.QLabel('%s' % _("Scale")) grid0.addWidget(scale_title_lbl, 5, 0, 1, 2) @@ -5425,7 +5425,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI): ) grid0.addWidget(self.reference_cb, 8, 1) - # ## Offset distance on X axis + # ## Offset offset_title_lbl = QtWidgets.QLabel('%s' % _("Offset")) grid0.addWidget(offset_title_lbl, 9, 0, 1, 2) @@ -5454,6 +5454,10 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.offy_label, 11, 0) grid0.addWidget(self.offy_entry, 11, 1) + # ## Mirror + mirror_title_lbl = QtWidgets.QLabel('%s' % _("Mirror")) + grid0.addWidget(mirror_title_lbl, 12, 0, 1, 2) + # ## Mirror (Flip) Reference Point self.mirror_reference_cb = FCCheckBox('%s' % _("Mirror Reference")) self.mirror_reference_cb.setToolTip( @@ -5466,9 +5470,9 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI): "Then click Add button to insert coordinates.\n" "Or enter the coords in format (x, y) in the\n" "Point Entry field and click Flip on X(Y)")) - grid0.addWidget(self.mirror_reference_cb, 12, 0, 1, 2) + grid0.addWidget(self.mirror_reference_cb, 13, 0, 1, 2) - self.flip_ref_label = QtWidgets.QLabel('%s' % _("Mirror Reference point")) + self.flip_ref_label = QtWidgets.QLabel('%s' % _("Mirror Reference point")) self.flip_ref_label.setToolTip( _("Coordinates in format (x, y) used as reference for mirroring.\n" "The 'x' in (x, y) will be used when using Flip on X and\n" @@ -5476,8 +5480,42 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI): ) self.flip_ref_entry = EvalEntry2("(0, 0)") - grid0.addWidget(self.flip_ref_label, 13, 0, 1, 2) - grid0.addWidget(self.flip_ref_entry, 14, 0, 1, 2) + grid0.addWidget(self.flip_ref_label, 14, 0, 1, 2) + grid0.addWidget(self.flip_ref_entry, 15, 0, 1, 2) + + # ## Buffer + buffer_title_lbl = QtWidgets.QLabel('%s' % _("Buffer")) + grid0.addWidget(buffer_title_lbl, 16, 0, 1, 2) + + self.buffer_label = QtWidgets.QLabel('%s:' % _("Distance")) + self.buffer_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 with the 'distance'.") + ) + + self.buffer_entry = FCDoubleSpinner() + self.buffer_entry.set_precision(self.decimals) + self.buffer_entry.setSingleStep(0.1) + self.buffer_entry.setWrapping(True) + self.buffer_entry.set_range(-9999.9999, 9999.9999) + + grid0.addWidget(self.buffer_label, 17, 0) + grid0.addWidget(self.buffer_entry, 17, 1) + + self.buffer_rounded_cb = FCCheckBox() + self.buffer_rounded_cb.setText('%s' % _("Rounded")) + self.buffer_rounded_cb.setToolTip( + _("If checked then the buffer will surround the buffered shape,\n" + "every corner will be rounded.\n" + "If not checked then the buffer will follow the exact geometry\n" + "of the buffered shape.") + ) + + grid0.addWidget(self.buffer_rounded_cb, 18, 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 0b5677dc..894851c6 100644 --- a/flatcamParsers/ParseExcellon.py +++ b/flatcamParsers/ParseExcellon.py @@ -1457,4 +1457,35 @@ class Excellon(Geometry): slot['start'] = affinity.rotate(slot['start'], angle, origin=(px, py)) self.create_geometry() - self.app.proc_container.new_text = '' \ No newline at end of file + self.app.proc_container.new_text = '' + + def buffer(self, distance, join): + """ + + :param distance: + :param join: + :return: + """ + log.debug("flatcamParsers.ParseExcellon.Excellon.buffer()") + + if distance == 0: + return + + 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: + return obj.buffer(distance, resolution=self.geo_steps_per_circle) + 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 + + self.create_geometry() diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py index b9bc504d..881b49b6 100644 --- a/flatcamParsers/ParseGerber.py +++ b/flatcamParsers/ParseGerber.py @@ -2169,6 +2169,87 @@ class Gerber(Geometry): _("Gerber Rotate done.")) self.app.proc_container.new_text = '' + def buffer(self, distance, join): + """ + + :param distance: + :return: + """ + log.debug("parseGerber.Gerber.buffer()") + + if distance == 0: + return + + # 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 = 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 + + return obj.buffer(distance, resolution=self.steps_per_circle, join_style=join) + except AttributeError: + return obj + + self.solid_geometry = buffer_geom(self.solid_geometry) + + # 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'] = 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) + + 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.app.inform.emit('[success] %s' % _("Gerber Buffer done.")) + self.app.proc_container.new_text = '' + def parse_gerber_number(strnumber, int_digits, frac_digits, zeros): """ diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py index 0b83c5c6..566372c2 100644 --- a/flatcamTools/ToolTransform.py +++ b/flatcamTools/ToolTransform.py @@ -27,6 +27,7 @@ class ToolTransform(FlatCAMTool): scaleName = _("Scale") flipName = _("Mirror (Flip)") offsetName = _("Offset") + bufferName = _("Buffer") def __init__(self, app): FlatCAMTool.__init__(self, app) @@ -255,11 +256,11 @@ class ToolTransform(FlatCAMTool): grid0.addWidget(self.offy_entry, 14, 1) grid0.addWidget(self.offy_button, 14, 2) - grid0.addWidget(QtWidgets.QLabel('')) + grid0.addWidget(QtWidgets.QLabel(''), 15, 0, 1, 3) # ## Flip Title flip_title_label = QtWidgets.QLabel("%s" % self.flipName) - self.transform_lay.addWidget(flip_title_label) + grid0.addWidget(flip_title_label, 16, 0, 1, 3) self.flipx_button = FCButton() self.flipx_button.set_value(_("Flip on X")) @@ -274,7 +275,7 @@ class ToolTransform(FlatCAMTool): ) hlay0 = QtWidgets.QHBoxLayout() - self.transform_lay.addLayout(hlay0) + grid0.addLayout(hlay0, 17, 0, 1, 3) hlay0.addWidget(self.flipx_button) hlay0.addWidget(self.flipy_button) @@ -293,7 +294,7 @@ class ToolTransform(FlatCAMTool): "Or enter the coords in format (x, y) in the\n" "Point Entry field and click Flip on X(Y)")) - self.transform_lay.addWidget(self.flip_ref_cb) + grid0.addWidget(self.flip_ref_cb, 18, 0, 1, 3) self.flip_ref_label = QtWidgets.QLabel('%s:' % _("Ref. Point")) self.flip_ref_label.setToolTip( @@ -315,12 +316,60 @@ class ToolTransform(FlatCAMTool): self.ois_flip = OptionalInputSection(self.flip_ref_cb, [self.flip_ref_entry, self.flip_ref_button], logic=True) hlay1 = QtWidgets.QHBoxLayout() - self.transform_lay.addLayout(hlay1) + grid0.addLayout(hlay1, 19, 0, 1, 3) hlay1.addWidget(self.flip_ref_label) hlay1.addWidget(self.flip_ref_entry) - self.transform_lay.addWidget(self.flip_ref_button) + grid0.addWidget(self.flip_ref_button, 20, 0, 1, 3) + + grid0.addWidget(QtWidgets.QLabel(''), 21, 0, 1, 3) + + # ## Buffer Title + buffer_title_label = QtWidgets.QLabel("%s" % self.bufferName) + grid0.addWidget(buffer_title_label, 22, 0, 1, 3) + + self.buffer_label = QtWidgets.QLabel('%s:' % _("Distance")) + self.buffer_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 with the 'distance'.") + ) + + self.buffer_entry = FCDoubleSpinner() + self.buffer_entry.set_precision(self.decimals) + self.buffer_entry.setSingleStep(0.1) + 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.setToolTip( + _("Create the buffer effect on each geometry,\n" + "element from the selected object.") + ) + self.buffer_button.setMinimumWidth(90) + + grid0.addWidget(self.buffer_label, 23, 0) + 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_rounded_cb.setToolTip( + _("If checked then the buffer will surround the buffered shape,\n" + "every corner will be rounded.\n" + "If not checked then the buffer will follow the exact geometry\n" + "of the buffered shape.") + ) + + grid0.addWidget(self.buffer_rounded_cb, 24, 0, 1, 3) + + grid0.addWidget(QtWidgets.QLabel(''), 25, 0, 1, 3) + self.transform_lay.addStretch() # ## Signals @@ -334,14 +383,16 @@ 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.rotate_entry.returnPressed.connect(self.on_rotate) - self.skewx_entry.returnPressed.connect(self.on_skewx) - self.skewy_entry.returnPressed.connect(self.on_skewy) - self.scalex_entry.returnPressed.connect(self.on_scalex) - 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.rotate_entry.returnPressed.connect(self.on_rotate) + # self.skewx_entry.returnPressed.connect(self.on_skewx) + # self.skewy_entry.returnPressed.connect(self.on_skewy) + # self.scalex_entry.returnPressed.connect(self.on_scalex) + # 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) def run(self, toggle=True): self.app.report_usage("ToolTransform()") @@ -430,6 +481,16 @@ class ToolTransform(FlatCAMTool): else: self.flip_ref_entry.set_value((0, 0)) + if self.app.defaults["tools_transform_buffer_dis"]: + self.buffer_entry.set_value(self.app.defaults["tools_transform_buffer_dis"]) + else: + self.buffer_entry.set_value(0.0) + + if self.app.defaults["tools_transform_buffer_corner"]: + self.buffer_rounded_cb.set_value(self.app.defaults["tools_transform_buffer_corner"]) + else: + self.buffer_rounded_cb.set_value(True) + def on_rotate(self): value = float(self.rotate_entry.get_value()) if value == 0: @@ -511,8 +572,7 @@ class ToolTransform(FlatCAMTool): def on_offx(self): value = float(self.offx_entry.get_value()) if value == 0: - self.app.inform.emit('[WARNING_NOTCL] %s' % - _("Offset transformation can not be done for a value of 0.")) + self.app.inform.emit('[WARNING_NOTCL] %s' % _("Offset transformation can not be done for a value of 0.")) return axis = 'X' @@ -522,14 +582,20 @@ class ToolTransform(FlatCAMTool): def on_offy(self): value = float(self.offy_entry.get_value()) if value == 0: - self.app.inform.emit('[WARNING_NOTCL] %s' % - _("Offset transformation can not be done for a value of 0.")) + self.app.inform.emit('[WARNING_NOTCL] %s' % _("Offset transformation can not be done for a value of 0.")) return axis = 'Y' self.app.worker_task.emit({'fcn': self.on_offset, 'params': [axis, value]}) return + def on_buffer(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_rotate_action(self, num): obj_list = self.app.collection.get_selected() xminlist = [] @@ -808,4 +874,40 @@ class ToolTransform(FlatCAMTool): (_("Due of"), str(e), _("action was not executed."))) return + def on_buffer_action(self, value, join): + obj_list = self.app.collection.get_selected() + + if not obj_list: + self.app.inform.emit('[WARNING_NOTCL] %s' % _("No object selected. Please Select an object to buffer!")) + return + else: + with self.app.proc_container.new(_("Applying Buffer")): + try: + for sel_obj in obj_list: + 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.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.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) + + self.app.object_changed.emit(sel_obj) + sel_obj.plot() + + self.app.inform.emit('[success] %s...' % _('Buffer done')) + + except Exception as e: + self.app.log.debug("ToolTransform.on_buffer_action() --> %s" % str(e)) + self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' % + (_("Due of"), str(e), _("action was not executed."))) + return + # end of file