From e7c369ab8e1c1299cfda8f073cfaa73208f5d006 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Tue, 7 Jul 2020 15:52:58 +0300 Subject: [PATCH] - updated the Panelize Tool to save the source code for the panelized Excellon objects so it can be saved from the Save project tab context menu entry - updated the Panelize Tool to save the source code for the panelized Geometry objects as DXF file --- CHANGELOG.md | 5 +++ appObjects/FlatCAMGeometry.py | 15 ++----- appTools/ToolPanelize.py | 8 +++- app_Main.py | 65 +++++++++++++++++++----------- camlib.py | 20 +++++++++ tclCommands/TclCommandExportDXF.py | 2 +- 6 files changed, 79 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f96b5f8e..d074084d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ CHANGELOG for FlatCAM beta ================================================= +7.07.2020 + +- updated the Panelize Tool to save the source code for the panelized Excellon objects so it can be saved from the Save project tab context menu entry +- updated the Panelize Tool to save the source code for the panelized Geometry objects as DXF file + 6.07.2020 - Convert Any to Excellon. Finished Gerber object conversion to Excellon. Flash's are converted to drills. Traces in the form of a linear LineString (no changes in direction) are converted to slots. diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py index 457d5097..11cee268 100644 --- a/appObjects/FlatCAMGeometry.py +++ b/appObjects/FlatCAMGeometry.py @@ -938,20 +938,12 @@ class GeometryObject(FlatCAMObj, Geometry): self.ui_connect() - def on_tool_add(self, dia=None): + def on_tool_add(self, dia=None, new_geo=None): self.ui_disconnect() self.units = self.app.defaults['units'].upper() - if dia is not None: - tooldia = dia - else: - tooldia = float(self.ui.addtool_entry.get_value()) - - # construct a list of all 'tooluid' in the self.tools - # tool_uid_list = [] - # for tooluid_key in self.tools: - # tool_uid_list.append(int(tooluid_key)) + tooldia = dia if dia is not None else float(self.ui.addtool_entry.get_value()) tool_uid_list = [int(tooluid_key) for tooluid_key in self.tools] # find maximum from the temp_uid, add 1 and this is the new 'tooluid' @@ -968,7 +960,8 @@ class GeometryObject(FlatCAMObj, Geometry): last_offset_value = self.tools[max_uid]['offset_value'] last_type = self.tools[max_uid]['type'] last_tool_type = self.tools[max_uid]['tool_type'] - last_solid_geometry = self.tools[max_uid]['solid_geometry'] + + last_solid_geometry = self.tools[max_uid]['solid_geometry'] if new_geo is None else new_geo # if previous geometry was empty (it may happen for the first tool added) # then copy the object.solid_geometry diff --git a/appTools/ToolPanelize.py b/appTools/ToolPanelize.py index 0221f22b..5f90b507 100644 --- a/appTools/ToolPanelize.py +++ b/appTools/ToolPanelize.py @@ -356,6 +356,9 @@ class Panelize(AppTool): obj_fin.create_geometry() obj_fin.zeros = panel_source_obj.zeros obj_fin.units = panel_source_obj.units + app_obj.inform.emit('%s' % _("Generating panel ... Adding the source code.")) + obj_fin.source_file = self.app.export_excellon(obj_name=self.outname, filename=None, + local_use=obj_fin, use_thread=False) app_obj.proc_container.update_view_text('') def job_init_geometry(obj_fin, app_obj): @@ -575,10 +578,13 @@ class Panelize(AppTool): if to_optimize is True: app_obj.inform.emit('%s' % _("Optimization complete.")) + app_obj.inform.emit('%s' % _("Generating panel ... Adding the source code.")) if panel_type == 'gerber': - app_obj.inform.emit('%s' % _("Generating panel ... Adding the Gerber code.")) obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None, local_use=obj_fin, use_thread=False) + if panel_type == 'geometry': + obj_fin.source_file = self.app.export_dxf(obj_name=self.outname, filename=None, + local_use=obj_fin, use_thread=False) # obj_fin.solid_geometry = cascaded_union(obj_fin.solid_geometry) # app_obj.log.debug("Finished creating a cascaded union for the panel.") diff --git a/app_Main.py b/app_Main.py index 3a4f35d7..d4485745 100644 --- a/app_Main.py +++ b/app_Main.py @@ -8363,7 +8363,7 @@ class App(QtCore.QObject): if file_string.getvalue() == '': self.inform.emit('[ERROR_NOTCL] %s' % - _("Save cancelled because source file is empty. Try to export the Gerber file.")) + _("Save cancelled because source file is empty. Try to export the file.")) return 'fail' try: @@ -8544,11 +8544,12 @@ class App(QtCore.QObject): """ Exports a Gerber Object to an Gerber file. - :param obj_name: the name of the FlatCAM object to be saved as Gerber - :param filename: Path to the Gerber file to save to. - :param local_use: if the Gerber code is to be saved to a file (None) or used within FlatCAM. - When not None, the value will be the actual Gerber object for which to create the Gerber code - :param use_thread: if to be run in a separate thread + :param obj_name: the name of the FlatCAM object to be saved as Gerber + :param filename: Path to the Gerber file to save to. + :param local_use: if the Gerber code is to be saved to a file (None) or used within FlatCAM. + When not None, the value will be the actual Gerber object for which to create + the Gerber code + :param use_thread: if to be run in a separate thread :return: """ self.defaults.report_usage("export_gerber()") @@ -8563,7 +8564,7 @@ class App(QtCore.QObject): try: obj = self.collection.get_by_name(str(obj_name)) except Exception: - return "Could not retrieve object: %s" % obj_name + return 'fail' else: obj = local_use @@ -8675,13 +8676,16 @@ class App(QtCore.QObject): if local_use is not None: return gret - def export_dxf(self, obj_name, filename, use_thread=True): + def export_dxf(self, obj_name, filename, local_use=None, use_thread=True): """ Exports a Geometry Object to an DXF file. - :param obj_name: the name of the FlatCAM object to be saved as DXF - :param filename: Path to the DXF file to save to. - :param use_thread: if to be run in a separate thread + :param obj_name: the name of the FlatCAM object to be saved as DXF + :param filename: Path to the DXF file to save to. + :param local_use: if the Gerber code is to be saved to a file (None) or used within FlatCAM. + When not None, the value will be the actual Geometry object for which to create + the Geometry/DXF code + :param use_thread: if to be run in a separate thread :return: """ self.defaults.report_usage("export_dxf()") @@ -8692,21 +8696,34 @@ class App(QtCore.QObject): self.log.debug("export_dxf()") - try: - obj = self.collection.get_by_name(str(obj_name)) - except Exception: - # TODO: The return behavior has not been established... should raise exception? - return "Could not retrieve object: %s" % obj_name + if local_use is None: + try: + obj = self.collection.get_by_name(str(obj_name)) + except Exception: + return 'fail' + else: + obj = local_use def make_dxf(): try: dxf_code = obj.export_dxf() - dxf_code.saveas(filename) - if self.defaults["global_open_style"] is False: - self.file_opened.emit("DXF", filename) - self.file_saved.emit("DXF", filename) - self.inform.emit('[success] %s: %s' % (_("DXF file exported to"), filename)) - except Exception: + if local_use is None: + try: + dxf_code.saveas(filename) + except PermissionError: + self.inform.emit('[WARNING] %s' % + _("Permission denied, saving not possible.\n" + "Most likely another app is holding the file open and not accessible.")) + return 'fail' + + if self.defaults["global_open_style"] is False: + self.file_opened.emit("DXF", filename) + self.file_saved.emit("DXF", filename) + self.inform.emit('[success] %s: %s' % (_("DXF file exported to"), filename)) + else: + return dxf_code + except Exception as e: + log.debug("App.export_dxf.make_dxf() --> %s" % str(e)) return 'fail' if use_thread is True: @@ -8725,6 +8742,8 @@ class App(QtCore.QObject): if ret == 'fail': self.inform.emit('[WARNING_NOTCL] %s' % _('Could not export DXF file.')) return + if local_use is not None: + return ret def import_svg(self, filename, geo_type='geometry', outname=None, plot=True): """ @@ -8785,7 +8804,7 @@ class App(QtCore.QObject): :param plot: If True then the resulting object will be plotted on canvas :return: """ - log.debug(" ********* Importing SVG as: %s ********* " % geo_type.capitalize()) + log.debug(" ********* Importing DXF as: %s ********* " % geo_type.capitalize()) obj_type = "" if geo_type is None or geo_type == "geometry": diff --git a/camlib.py b/camlib.py index e366c45f..d1d9b8a0 100644 --- a/camlib.py +++ b/camlib.py @@ -1101,6 +1101,7 @@ class Geometry(object): # Parse into list of shapely objects dxf = ezdxf.readfile(filename) geos = getdxfgeo(dxf) + # trying to optimize the resulting geometry by merging contiguous lines geos = linemerge(geos) @@ -1116,6 +1117,25 @@ class Geometry(object): else: # It's shapely geometry self.solid_geometry = [self.solid_geometry, geos] + tooldia = float(self.app.defaults["geometry_cnctooldia"]) + tooldia = float('%.*f' % (self.decimals, tooldia)) + + new_data = {k: v for k, v in self.options.items()} + + self.tools.update({ + 1: { + 'tooldia': tooldia, + 'offset': 'Path', + 'offset_value': 0.0, + 'type': _('Rough'), + 'tool_type': 'C1', + 'data': deepcopy(new_data), + 'solid_geometry': self.solid_geometry + } + }) + + self.tools[1]['data']['name'] = self.options['name'] + # commented until this function is ready # geos_text = getdxftext(dxf, object_type, units=units) # if geos_text is not None: diff --git a/tclCommands/TclCommandExportDXF.py b/tclCommands/TclCommandExportDXF.py index 1fe4a361..093276ff 100644 --- a/tclCommands/TclCommandExportDXF.py +++ b/tclCommands/TclCommandExportDXF.py @@ -49,4 +49,4 @@ class TclCommandExportDXF(TclCommand): """ if 'filename' not in args: args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name'] - self.app.export_dxf(use_thread=False, **args) + self.app.export_dxf(use_thread=False, local_use=None, **args)