diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fd3f82c..0fb3379e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ CHANGELOG for FlatCAM beta ================================================= +11.12.2020 + +- updated the 'Default_no_M6' preprocessor by removing the Tx command in the Toolchange section to make it compatible with GRBL controllers +- added a new preprocessor named 'Check_points' which is to be used to check if the PCB is well aligned in position (used by at least the Corners Tool) +- Tool Corners - added a new feature that creates a verification GCode by moving in the locations positions; modfied the UI a bit +- Drilling Tool - removed the mandatory Toolchange event added even if the Toolchange was not selected +- Excellon and Geometry objects no longer have the self.options dict overwritten with the application defaults +- Drilling Tool - first tool that benefit from using the object options instead of application defaults; this is useful if an object is recreated on project load +- Drilling Tool - fixed it to update the UI form also for common parameters on object change + 10.12.2020 - NCC Tool - remade the 'Beginner/Advanced' Mode diff --git a/appObjects/AppObject.py b/appObjects/AppObject.py index 9a8a32f8..9549ebf4 100644 --- a/appObjects/AppObject.py +++ b/appObjects/AppObject.py @@ -217,131 +217,6 @@ class AppObject(QtCore.QObject): return obj - def new_excellon_object(self): - """ - Creates a new, blank Excellon object. - - :return: None - """ - - outname = 'new_exc' - - def obj_init(new_obj, app_obj): - new_obj.tools = {} - new_obj.source_file = '' - new_obj.solid_geometry = [] - - self.new_object('excellon', outname, obj_init, plot=False) - - def new_geometry_object(self): - """ - Creates a new, blank and single-tool Geometry object. - - :return: None - """ - outname = 'new_geo' - - def initialize(new_obj, app): - new_obj.multitool = True - new_obj.multigeo = True - - # store here the default data for Geometry Data - default_data = {} - for opt_key, opt_val in app.options.items(): - if opt_key.find('geometry' + "_") == 0: - oname = opt_key[len('geometry') + 1:] - default_data[oname] = self.app.options[opt_key] - if opt_key.find('tools_') == 0: - default_data[opt_key] = self.app.options[opt_key] - - new_obj.tools = { - 1: { - 'tooldia': float(app.defaults["tools_mill_tooldia"]), - 'offset': 'Path', - 'offset_value': 0.0, - 'type': 'Rough', - 'tool_type': 'C1', - 'data': deepcopy(default_data), - 'solid_geometry': [] - } - } - - new_obj.tools[1]['data']['name'] = outname - - new_obj.source_file = '' - - self.new_object('geometry', outname, initialize, plot=False) - - def new_gerber_object(self): - """ - Creates a new, blank Gerber object. - - :return: None - """ - - def initialize(new_obj, app): - new_obj.multitool = False - new_obj.source_file = '' - new_obj.multigeo = False - new_obj.follow = False - new_obj.apertures = {} - new_obj.solid_geometry = [] - new_obj.follow_geometry = [] - - try: - new_obj.options['xmin'] = 0 - new_obj.options['ymin'] = 0 - new_obj.options['xmax'] = 0 - new_obj.options['ymax'] = 0 - except KeyError: - pass - - self.new_object('gerber', 'new_grb', initialize, plot=False) - - def new_script_object(self): - """ - Creates a new, blank TCL Script object. - - :return: None - """ - - # commands_list = "# AddCircle, AddPolygon, AddPolyline, AddRectangle, AlignDrill, " \ - # "AlignDrillGrid, Bbox, Bounds, ClearShell, CopperClear,\n" \ - # "# Cncjob, Cutout, Delete, Drillcncjob, ExportDXF, ExportExcellon, ExportGcode,\n" \ - # "# ExportGerber, ExportSVG, Exteriors, Follow, GeoCutout, GeoUnion, GetNames,\n" \ - # "# GetSys, ImportSvg, Interiors, Isolate, JoinExcellon, JoinGeometry, " \ - # "ListSys, MillDrills,\n" \ - # "# MillSlots, Mirror, New, NewExcellon, NewGeometry, NewGerber, Nregions, " \ - # "Offset, OpenExcellon, OpenGCode, OpenGerber, OpenProject,\n" \ - # "# Options, Paint, Panelize, PlotAl, PlotObjects, SaveProject, " \ - # "SaveSys, Scale, SetActive, SetSys, SetOrigin, Skew, SubtractPoly,\n" \ - # "# SubtractRectangle, Version, WriteGCode\n" - - new_source_file = '# %s\n' % _('CREATE A NEW FLATCAM TCL SCRIPT') + \ - '# %s:\n' % _('TCL Tutorial is here') + \ - '# https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html\n' + '\n\n' + \ - '# %s:\n' % _("FlatCAM commands list") - new_source_file += '# %s\n\n' % _("Type >help< followed by Run Code for a list of FlatCAM Tcl Commands " - "(displayed in Tcl Shell).") - - def initialize(new_obj, app): - new_obj.source_file = deepcopy(new_source_file) - - outname = 'new_script' - self.new_object('script', outname, initialize, plot=False) - - def new_document_object(self): - """ - Creates a new, blank Document object. - - :return: None - """ - - def initialize(new_obj, app): - new_obj.source_file = "" - - self.new_object('document', 'new_document', initialize, plot=False) - def on_object_created(self, obj, plot, auto_select, callback, callback_params): """ Event callback for object creation. @@ -359,6 +234,9 @@ class AppObject(QtCore.QObject): t0 = time.time() # DEBUG log.debug("on_object_created()") + # ############################################################################################################# + # ############################### Add the new object to the Collection ###################################### + # ############################################################################################################# # The Collection might change the name if there is a collision self.app.collection.append(obj) @@ -513,3 +391,128 @@ class AppObject(QtCore.QObject): :return: None """ self.app.on_zoom_fit() + + def new_excellon_object(self): + """ + Creates a new, blank Excellon object. + + :return: None + """ + + outname = 'new_exc' + + def obj_init(new_obj, app_obj): + new_obj.tools = {} + new_obj.source_file = '' + new_obj.solid_geometry = [] + + self.new_object('excellon', outname, obj_init, plot=False) + + def new_geometry_object(self): + """ + Creates a new, blank and single-tool Geometry object. + + :return: None + """ + outname = 'new_geo' + + def initialize(new_obj, app): + new_obj.multitool = True + new_obj.multigeo = True + + # store here the default data for Geometry Data + default_data = {} + for opt_key, opt_val in app.options.items(): + if opt_key.find('geometry' + "_") == 0: + oname = opt_key[len('geometry') + 1:] + default_data[oname] = self.app.options[opt_key] + if opt_key.find('tools_') == 0: + default_data[opt_key] = self.app.options[opt_key] + + new_obj.tools = { + 1: { + 'tooldia': float(app.defaults["tools_mill_tooldia"]), + 'offset': 'Path', + 'offset_value': 0.0, + 'type': 'Rough', + 'tool_type': 'C1', + 'data': deepcopy(default_data), + 'solid_geometry': [] + } + } + + new_obj.tools[1]['data']['name'] = outname + + new_obj.source_file = '' + + self.new_object('geometry', outname, initialize, plot=False) + + def new_gerber_object(self): + """ + Creates a new, blank Gerber object. + + :return: None + """ + + def initialize(new_obj, app): + new_obj.multitool = False + new_obj.source_file = '' + new_obj.multigeo = False + new_obj.follow = False + new_obj.apertures = {} + new_obj.solid_geometry = [] + new_obj.follow_geometry = [] + + try: + new_obj.options['xmin'] = 0 + new_obj.options['ymin'] = 0 + new_obj.options['xmax'] = 0 + new_obj.options['ymax'] = 0 + except KeyError: + pass + + self.new_object('gerber', 'new_grb', initialize, plot=False) + + def new_script_object(self): + """ + Creates a new, blank TCL Script object. + + :return: None + """ + + # commands_list = "# AddCircle, AddPolygon, AddPolyline, AddRectangle, AlignDrill, " \ + # "AlignDrillGrid, Bbox, Bounds, ClearShell, CopperClear,\n" \ + # "# Cncjob, Cutout, Delete, Drillcncjob, ExportDXF, ExportExcellon, ExportGcode,\n" \ + # "# ExportGerber, ExportSVG, Exteriors, Follow, GeoCutout, GeoUnion, GetNames,\n" \ + # "# GetSys, ImportSvg, Interiors, Isolate, JoinExcellon, JoinGeometry, " \ + # "ListSys, MillDrills,\n" \ + # "# MillSlots, Mirror, New, NewExcellon, NewGeometry, NewGerber, Nregions, " \ + # "Offset, OpenExcellon, OpenGCode, OpenGerber, OpenProject,\n" \ + # "# Options, Paint, Panelize, PlotAl, PlotObjects, SaveProject, " \ + # "SaveSys, Scale, SetActive, SetSys, SetOrigin, Skew, SubtractPoly,\n" \ + # "# SubtractRectangle, Version, WriteGCode\n" + + new_source_file = '# %s\n' % _('CREATE A NEW FLATCAM TCL SCRIPT') + \ + '# %s:\n' % _('TCL Tutorial is here') + \ + '# https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html\n' + '\n\n' + \ + '# %s:\n' % _("FlatCAM commands list") + new_source_file += '# %s\n\n' % _("Type >help< followed by Run Code for a list of FlatCAM Tcl Commands " + "(displayed in Tcl Shell).") + + def initialize(new_obj, app): + new_obj.source_file = deepcopy(new_source_file) + + outname = 'new_script' + self.new_object('script', outname, initialize, plot=False) + + def new_document_object(self): + """ + Creates a new, blank Document object. + + :return: None + """ + + def initialize(new_obj, app): + new_obj.source_file = "" + + self.new_object('document', 'new_document', initialize, plot=False) diff --git a/appObjects/FlatCAMExcellon.py b/appObjects/FlatCAMExcellon.py index 70466073..54c74a30 100644 --- a/appObjects/FlatCAMExcellon.py +++ b/appObjects/FlatCAMExcellon.py @@ -123,15 +123,15 @@ class ExcellonObject(FlatCAMObj, Excellon): self.units = self.app.defaults['units'].upper() - # fill in self.options values for the Drilling Tool from self.app.options - for opt_key, opt_val in self.app.options.items(): - if opt_key.find('tools_drill_') == 0: - self.options[opt_key] = deepcopy(opt_val) - - # fill in self.default_data values from self.options - for opt_key, opt_val in self.app.options.items(): - if opt_key.find('excellon_') == 0 or opt_key.find('tools_drill_') == 0: - self.default_data[opt_key] = deepcopy(opt_val) + # # fill in self.options values for the Drilling Tool from self.app.options + # for opt_key, opt_val in self.app.options.items(): + # if opt_key.find('tools_drill_') == 0: + # self.options[opt_key] = deepcopy(opt_val) + # + # # fill in self.default_data values from self.options + # for opt_key, opt_val in self.app.options.items(): + # if opt_key.find('excellon_') == 0 or opt_key.find('tools_drill_') == 0: + # self.default_data[opt_key] = deepcopy(opt_val) self.form_fields.update({ "plot": self.ui.plot_cb, diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py index 9baa932d..59796360 100644 --- a/appObjects/FlatCAMGeometry.py +++ b/appObjects/FlatCAMGeometry.py @@ -520,18 +520,15 @@ class GeometryObject(FlatCAMObj, Geometry): # store here the default data for Geometry Data self.default_data = {} - for opt_key, opt_val in self.app.options.items(): - if opt_key.find('geometry' + "_") == 0: - oname = opt_key[len('geometry') + 1:] - self.default_data[oname] = self.app.options[opt_key] - elif opt_key.find('tools_') == 0: - self.default_data[opt_key] = self.app.options[opt_key] + # for opt_key, opt_val in self.options.items(): + # if opt_key.find('geometry' + "_") == 0: + # oname = opt_key[len('geometry') + 1:] + # self.default_data[oname] = self.app.options[opt_key] + # elif opt_key.find('tools_') == 0: + # self.default_data[opt_key] = self.app.options[opt_key] # fill in self.default_data values from self.options - for def_key in self.default_data: - for opt_key, opt_val in self.options.items(): - if def_key == opt_key: - self.default_data[def_key] = deepcopy(opt_val) + self.default_data.update(self.options) if type(self.options["tools_mill_tooldia"]) == float: tools_list = [self.options["tools_mill_tooldia"]] diff --git a/appObjects/ObjectCollection.py b/appObjects/ObjectCollection.py index 9271c989..5cbe5220 100644 --- a/appObjects/ObjectCollection.py +++ b/appObjects/ObjectCollection.py @@ -582,7 +582,11 @@ class ObjectCollection(QtCore.QAbstractItemModel): # ############################################################################################################ self.app.myKeywords.append(name) + # ############################################################################################################ + # ############################# Set the Object UI (Properties Tab) ########################################### + # ############################################################################################################ obj.set_ui(obj.ui_type(app=self.app)) + # a way to signal that the object was fully loaded obj.load_complete = True diff --git a/appTools/ToolCorners.py b/appTools/ToolCorners.py index 0715514d..9db0f7c1 100644 --- a/appTools/ToolCorners.py +++ b/appTools/ToolCorners.py @@ -62,6 +62,7 @@ class ToolCorners(AppTool): self.ui.add_marker_button.clicked.connect(self.add_markers) self.ui.toggle_all_cb.toggled.connect(self.on_toggle_all) self.ui.drill_button.clicked.connect(self.on_create_drill_object) + self.ui.check_button.clicked.connect(self.on_create_check_object) def run(self, toggle=True): self.app.defaults.report_usage("ToolCorners()") @@ -435,6 +436,108 @@ class ToolCorners(AppTool): else: self.app.inform.emit('[success] %s' % _("Excellon object with corner drills created.")) + def on_create_check_object(self): + self.app.call_source = "corners_tool" + + tooldia = self.ui.drill_dia_entry.get_value() + + if tooldia == 0: + self.app.inform.emit('[WARNING_NOTCL] %s %s' % (_("Cancelled."), _("The tool diameter is zero."))) + return + + line_thickness = self.ui.thick_entry.get_value() + margin = self.ui.margin_entry.get_value() + tl_state = self.ui.tl_cb.get_value() + tr_state = self.ui.tr_cb.get_value() + bl_state = self.ui.bl_cb.get_value() + br_state = self.ui.br_cb.get_value() + + # get the Gerber object on which the corner marker will be inserted + selection_index = self.ui.object_combo.currentIndex() + model_index = self.app.collection.index(selection_index, 0, self.ui.object_combo.rootModelIndex()) + + try: + self.grb_object = model_index.internalPointer().obj + except Exception as e: + log.debug("ToolCorners.add_markers() --> %s" % str(e)) + self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ...")) + self.app.call_source = "app" + return + + if tl_state is False and tr_state is False and bl_state is False and br_state is False: + self.app.inform.emit("[ERROR_NOTCL] %s." % _("Please select at least a location")) + self.app.call_source = "app" + return + + xmin, ymin, xmax, ymax = self.grb_object.bounds() + + # list of (x,y) tuples. Store here the drill coordinates + drill_list = [] + + if tl_state: + x = xmin - margin - line_thickness / 2.0 + y = ymax + margin + line_thickness / 2.0 + drill_list.append( + Point((x, y)) + ) + + if tr_state: + x = xmax + margin + line_thickness / 2.0 + y = ymax + margin + line_thickness / 2.0 + drill_list.append( + Point((x, y)) + ) + + if bl_state: + x = xmin - margin - line_thickness / 2.0 + y = ymin - margin - line_thickness / 2.0 + drill_list.append( + Point((x, y)) + ) + + if br_state: + x = xmax + margin + line_thickness / 2.0 + y = ymin - margin - line_thickness / 2.0 + drill_list.append( + Point((x, y)) + ) + + tools = { + 1: { + "tooldia": 0.1 if self.units == 'MM' else 0.0254, + "drills": drill_list, + 'data': {}, + "solid_geometry": [] + } + } + + def obj_init(new_obj, app_inst): + new_obj.tools = deepcopy(tools) + + # make sure we use the special preprocessor for checking + for tool in tools: + new_obj.tools[tool]['data']['tools_drill_ppname_e'] = 'Check_points' + + new_obj.create_geometry() + new_obj.options.update({ + 'name': outname, + 'tools_drill_cutz': -0.1, + 'tools_drill_ppname_e': 'Check_points' + }) + new_obj.source_file = app_inst.f_handlers.export_excellon(obj_name=new_obj.options['name'], + local_use=new_obj, + filename=None, + use_thread=False) + + outname = '%s_%s' % (str(self.grb_object.options['name']), 'corner_drills') + ret_val = self.app.app_obj.new_object("excellon", outname, obj_init) + + self.app.call_source = "app" + if ret_val == 'fail': + self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed.")) + else: + self.app.inform.emit('[success] %s' % _("Excellon object with corner drills created.")) + def replot(self, obj, run_thread=True): def worker_task(): with self.app.proc_container.new('%s ...' % _("Plotting")): @@ -511,7 +614,7 @@ class CornersUI: separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) self.layout.addWidget(separator_line) - self.points_label = FCLabel('%s:' % _('Locations')) + self.points_label = FCLabel('%s' % _('Locations').upper()) self.points_label.setToolTip( _("Locations where to place corner markers.") ) @@ -642,7 +745,7 @@ class CornersUI: grid_lay.addWidget(separator_line_2, 14, 0, 1, 2) # Drill is corners - self.drills_label = FCLabel('%s:' % _('Drills in Corners')) + self.drills_label = FCLabel('%s' % _('Drills in Locations').upper()) grid_lay.addWidget(self.drills_label, 16, 0, 1, 2) # Drill Tooldia # @@ -672,6 +775,32 @@ class CornersUI: """) grid_lay.addWidget(self.drill_button, 20, 0, 1, 2) + separator_line_2 = QtWidgets.QFrame() + separator_line_2.setFrameShape(QtWidgets.QFrame.HLine) + separator_line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + grid_lay.addWidget(separator_line_2, 22, 0, 1, 2) + + # Check is corners + self.check_label = FCLabel('%s' % _('Check in Locations').upper()) + grid_lay.addWidget(self.check_label, 24, 0, 1, 2) + + # ## Create an Excellon object for checking the positioning + self.check_button = FCButton(_("Create Excellon Object")) + self.check_button.setIcon(QtGui.QIcon(self.app.resource_location + '/drill32.png')) + self.check_button.setToolTip( + _("Will create an Excellon object using a special preprocessor.\n" + "The spindle will not start and the mounted probe will move to\n" + "the corner locations, wait for the user interaction and then\n" + "move to the next location until the last one.") + ) + self.check_button.setStyleSheet(""" + QPushButton + { + font-weight: bold; + } + """) + grid_lay.addWidget(self.check_button, 26, 0, 1, 2) + self.layout.addStretch() # ## Reset Tool diff --git a/appTools/ToolDrilling.py b/appTools/ToolDrilling.py index dee9e143..1c579eff 100644 --- a/appTools/ToolDrilling.py +++ b/appTools/ToolDrilling.py @@ -146,7 +146,7 @@ class ToolDrilling(AppTool, Excellon): "tools_drill_drill_slots": self.ui.drill_slots_cb, "tools_drill_drill_overlap": self.ui.drill_overlap_entry, - "tools_drill_last_drill": self.ui.last_drill_cb + "tools_drill_last_drill": self.ui.last_drill_cb, } self.general_form_fields = { @@ -331,15 +331,14 @@ class ToolDrilling(AppTool, Excellon): for it in range(self.ui.pp_excellon_name_cb.count()): self.ui.pp_excellon_name_cb.setItemData(it, self.ui.pp_excellon_name_cb.itemText(it), QtCore.Qt.ToolTipRole) - # Show/Hide Advanced Options - app_mode = self.app.defaults["global_app_level"] - self.change_level(app_mode) - - self.ui.tools_frame.show() - self.ui.order_radio.set_value(self.app.defaults["tools_drill_tool_order"]) - loaded_obj = self.app.collection.get_by_name(self.ui.object_combo.get_value()) + try: + loaded_obj = self.app.collection.get_by_name(self.ui.object_combo.get_value()) + except Exception as err: + self.app.log.debug("ToolDrilling -> Loaded Excellon object error. %s" % str(err)) + return + if loaded_obj: outname = loaded_obj.options['name'] else: @@ -347,62 +346,70 @@ class ToolDrilling(AppTool, Excellon): # init the working variables self.default_data.clear() - self.default_data = { - "name": outname + '_drill', - "plot": self.app.defaults["excellon_plot"], - "solid": self.app.defaults["excellon_solid"], - "multicolored": self.app.defaults["excellon_multicolored"], - "merge_fuse_tools": self.app.defaults["excellon_merge_fuse_tools"], - "format_upper_in": self.app.defaults["excellon_format_upper_in"], - "format_lower_in": self.app.defaults["excellon_format_lower_in"], - "format_upper_mm": self.app.defaults["excellon_format_upper_mm"], - "lower_mm": self.app.defaults["excellon_format_lower_mm"], - "zeros": self.app.defaults["excellon_zeros"], - - "tools_drill_tool_order": self.app.defaults["tools_drill_tool_order"], - "tools_drill_cutz": self.app.defaults["tools_drill_cutz"], - "tools_drill_multidepth": self.app.defaults["tools_drill_multidepth"], - "tools_drill_depthperpass": self.app.defaults["tools_drill_depthperpass"], - - "tools_drill_travelz": self.app.defaults["tools_drill_travelz"], - "tools_drill_endz": self.app.defaults["tools_drill_endz"], - "tools_drill_endxy": self.app.defaults["tools_drill_endxy"], - "tools_drill_feedrate_z": self.app.defaults["tools_drill_feedrate_z"], - - "tools_drill_spindlespeed": self.app.defaults["tools_drill_spindlespeed"], - "tools_drill_dwell": self.app.defaults["tools_drill_dwell"], - "tools_drill_dwelltime": self.app.defaults["tools_drill_dwelltime"], - - "tools_drill_toolchange": self.app.defaults["tools_drill_toolchange"], - "tools_drill_toolchangez": self.app.defaults["tools_drill_toolchangez"], - "tools_drill_ppname_e": self.app.defaults["tools_drill_ppname_e"], - - # Drill Slots - "tools_drill_drill_slots": self.app.defaults["tools_drill_drill_slots"], - "tools_drill_drill_overlap": self.app.defaults["tools_drill_drill_overlap"], - "tools_drill_last_drill": self.app.defaults["tools_drill_last_drill"], - - # Advanced Options - "tools_drill_offset": self.app.defaults["tools_drill_offset"], - "tools_drill_toolchangexy": self.app.defaults["tools_drill_toolchangexy"], - "tools_drill_startz": self.app.defaults["tools_drill_startz"], - "tools_drill_feedrate_rapid": self.app.defaults["tools_drill_feedrate_rapid"], - "tools_drill_z_pdepth": self.app.defaults["tools_drill_z_pdepth"], - "tools_drill_feedrate_probe": self.app.defaults["tools_drill_feedrate_probe"], - "tools_drill_spindledir": self.app.defaults["tools_drill_spindledir"], - "tools_drill_f_plunge": self.app.defaults["tools_drill_f_plunge"], - "tools_drill_f_retract": self.app.defaults["tools_drill_f_retract"], - - "tools_drill_area_exclusion": self.app.defaults["tools_drill_area_exclusion"], - "tools_drill_area_shape": self.app.defaults["tools_drill_area_shape"], - "tools_drill_area_strategy": self.app.defaults["tools_drill_area_strategy"], - "tools_drill_area_overz": self.app.defaults["tools_drill_area_overz"], - } # fill in self.default_data values from self.options for opt_key, opt_val in self.app.options.items(): - if opt_key.find('excellon_') == 0 or opt_key.find('tools_drill_') == 0: + if opt_key.find('excellon_') == 0: + oname = opt_key[len('excellon_'):] + self.default_data[oname] = deepcopy(opt_val) + if opt_key.find('tools_drill_') == 0: self.default_data[opt_key] = deepcopy(opt_val) + if opt_key.find('tools_mill_') == 0: + self.default_data[opt_key] = deepcopy(opt_val) + + self.default_data.update( + { + "name": outname + '_drill', + "plot": loaded_obj.options["plot"], + "solid": loaded_obj.options["solid"], + "multicolored": loaded_obj.options["multicolored"], + "merge_fuse_tools": loaded_obj.options["merge_fuse_tools"], + "format_upper_in": loaded_obj.options["format_upper_in"], + "format_lower_in": loaded_obj.options["format_lower_in"], + "format_upper_mm": loaded_obj.options["format_upper_mm"], + "lower_mm": loaded_obj.options["format_lower_mm"], + "zeros": loaded_obj.options["zeros"], + + "tools_drill_tool_order": loaded_obj.options["tools_drill_tool_order"], + "tools_drill_cutz": loaded_obj.options["tools_drill_cutz"], + "tools_drill_multidepth": loaded_obj.options["tools_drill_multidepth"], + "tools_drill_depthperpass": loaded_obj.options["tools_drill_depthperpass"], + + "tools_drill_travelz": loaded_obj.options["tools_drill_travelz"], + "tools_drill_endz": loaded_obj.options["tools_drill_endz"], + "tools_drill_endxy": loaded_obj.options["tools_drill_endxy"], + "tools_drill_feedrate_z": loaded_obj.options["tools_drill_feedrate_z"], + + "tools_drill_spindlespeed": loaded_obj.options["tools_drill_spindlespeed"], + "tools_drill_dwell": loaded_obj.options["tools_drill_dwell"], + "tools_drill_dwelltime": loaded_obj.options["tools_drill_dwelltime"], + + "tools_drill_toolchange": loaded_obj.options["tools_drill_toolchange"], + "tools_drill_toolchangez": loaded_obj.options["tools_drill_toolchangez"], + "tools_drill_ppname_e": loaded_obj.options["tools_drill_ppname_e"], + + # Drill Slots + "tools_drill_drill_slots": loaded_obj.options["tools_drill_drill_slots"], + "tools_drill_drill_overlap": loaded_obj.options["tools_drill_drill_overlap"], + "tools_drill_last_drill": loaded_obj.options["tools_drill_last_drill"], + + # Advanced Options + "tools_drill_offset": loaded_obj.options["tools_drill_offset"], + "tools_drill_toolchangexy": loaded_obj.options["tools_drill_toolchangexy"], + "tools_drill_startz": loaded_obj.options["tools_drill_startz"], + "tools_drill_feedrate_rapid": loaded_obj.options["tools_drill_feedrate_rapid"], + "tools_drill_z_pdepth": loaded_obj.options["tools_drill_z_pdepth"], + "tools_drill_feedrate_probe": loaded_obj.options["tools_drill_feedrate_probe"], + "tools_drill_spindledir": loaded_obj.options["tools_drill_spindledir"], + "tools_drill_f_plunge": loaded_obj.options["tools_drill_f_plunge"], + "tools_drill_f_retract": loaded_obj.options["tools_drill_f_retract"], + + "tools_drill_area_exclusion": loaded_obj.options["tools_drill_area_exclusion"], + "tools_drill_area_shape": loaded_obj.options["tools_drill_area_shape"], + "tools_drill_area_strategy": loaded_obj.options["tools_drill_area_strategy"], + "tools_drill_area_overz": loaded_obj.options["tools_drill_area_overz"], + } + ) self.first_click = False self.cursor_pos = None @@ -431,45 +438,47 @@ class ToolDrilling(AppTool, Excellon): # ####### Fill in the parameters ######### # ######################################## # ######################################## - self.ui.cutz_entry.set_value(self.app.defaults["tools_drill_cutz"]) - self.ui.mpass_cb.set_value(self.app.defaults["tools_drill_multidepth"]) - self.ui.maxdepth_entry.set_value(self.app.defaults["tools_drill_depthperpass"]) - self.ui.travelz_entry.set_value(self.app.defaults["tools_drill_travelz"]) - self.ui.feedrate_z_entry.set_value(self.app.defaults["tools_drill_feedrate_z"]) - self.ui.feedrate_rapid_entry.set_value(self.app.defaults["tools_drill_feedrate_rapid"]) - self.ui.spindlespeed_entry.set_value(self.app.defaults["tools_drill_spindlespeed"]) - self.ui.dwell_cb.set_value(self.app.defaults["tools_drill_dwell"]) - self.ui.dwelltime_entry.set_value(self.app.defaults["tools_drill_dwelltime"]) - self.ui.offset_entry.set_value(self.app.defaults["tools_drill_offset"]) - self.ui.toolchange_cb.set_value(self.app.defaults["tools_drill_toolchange"]) - self.ui.toolchangez_entry.set_value(self.app.defaults["tools_drill_toolchangez"]) - self.ui.estartz_entry.set_value(self.app.defaults["tools_drill_startz"]) - self.ui.endz_entry.set_value(self.app.defaults["tools_drill_endz"]) - self.ui.endxy_entry.set_value(self.app.defaults["tools_drill_endxy"]) - self.ui.pdepth_entry.set_value(self.app.defaults["tools_drill_z_pdepth"]) - self.ui.feedrate_probe_entry.set_value(self.app.defaults["tools_drill_feedrate_probe"]) + self.ui.cutz_entry.set_value(loaded_obj.options["tools_drill_cutz"]) + self.ui.mpass_cb.set_value(loaded_obj.options["tools_drill_multidepth"]) + self.ui.maxdepth_entry.set_value(loaded_obj.options["tools_drill_depthperpass"]) + self.ui.travelz_entry.set_value(loaded_obj.options["tools_drill_travelz"]) + self.ui.feedrate_z_entry.set_value(loaded_obj.options["tools_drill_feedrate_z"]) + self.ui.feedrate_rapid_entry.set_value(loaded_obj.options["tools_drill_feedrate_rapid"]) + self.ui.spindlespeed_entry.set_value(loaded_obj.options["tools_drill_spindlespeed"]) + self.ui.dwell_cb.set_value(loaded_obj.options["tools_drill_dwell"]) + self.ui.dwelltime_entry.set_value(loaded_obj.options["tools_drill_dwelltime"]) + self.ui.offset_entry.set_value(loaded_obj.options["tools_drill_offset"]) + self.ui.toolchange_cb.set_value(loaded_obj.options["tools_drill_toolchange"]) + self.ui.toolchangez_entry.set_value(loaded_obj.options["tools_drill_toolchangez"]) + self.ui.estartz_entry.set_value(loaded_obj.options["tools_drill_startz"]) + self.ui.endz_entry.set_value(loaded_obj.options["tools_drill_endz"]) + self.ui.endxy_entry.set_value(loaded_obj.options["tools_drill_endxy"]) + self.ui.pdepth_entry.set_value(loaded_obj.options["tools_drill_z_pdepth"]) + self.ui.feedrate_probe_entry.set_value(loaded_obj.options["tools_drill_feedrate_probe"]) - self.ui.pp_excellon_name_cb.set_value(self.app.defaults["tools_drill_ppname_e"]) + if loaded_obj.options["tools_drill_ppname_e"] in pp_list: + sel_ppname_e = loaded_obj.options["tools_drill_ppname_e"] + else: + sel_ppname_e = 'default' + self.ui.pp_excellon_name_cb.set_value(sel_ppname_e) - self.ui.exclusion_cb.set_value(self.app.defaults["tools_drill_area_exclusion"]) - self.ui.strategy_radio.set_value(self.app.defaults["tools_drill_area_strategy"]) - self.ui.over_z_entry.set_value(self.app.defaults["tools_drill_area_overz"]) - self.ui.area_shape_radio.set_value(self.app.defaults["tools_drill_area_shape"]) + self.ui.exclusion_cb.set_value(loaded_obj.options["tools_drill_area_exclusion"]) + self.ui.strategy_radio.set_value(loaded_obj.options["tools_drill_area_strategy"]) + self.ui.over_z_entry.set_value(loaded_obj.options["tools_drill_area_overz"]) + self.ui.area_shape_radio.set_value(loaded_obj.options["tools_drill_area_shape"]) # Drill slots - part of the Advanced Excellon params - self.ui.drill_overlap_entry.set_value(self.app.defaults["tools_drill_drill_overlap"]) - self.ui.last_drill_cb.set_value(self.app.defaults["tools_drill_last_drill"]) + self.ui.drill_overlap_entry.set_value(loaded_obj.options["tools_drill_drill_overlap"]) + self.ui.last_drill_cb.set_value(loaded_obj.options["tools_drill_last_drill"]) self.ui.drill_overlap_label.hide() self.ui.drill_overlap_entry.hide() self.ui.last_drill_cb.hide() - # if the app mode is Basic then disable this feature - if app_mode == 'b': - self.ui.drill_slots_cb.set_value(False) - self.ui.drill_slots_cb.hide() - else: - self.ui.drill_slots_cb.show() - self.ui.drill_slots_cb.set_value(self.app.defaults["tools_drill_drill_slots"]) + # Show/Hide Advanced Options + app_mode = self.app.defaults["global_app_level"] + self.change_level(app_mode) + + self.ui.tools_frame.show() try: self.ui.object_combo.currentTextChanged.disconnect() @@ -493,7 +502,11 @@ class ToolDrilling(AppTool, Excellon): def on_level_changed(self, checked): - loaded_obj = self.app.collection.get_by_name(self.ui.object_combo.get_value()) + try: + loaded_obj = self.app.collection.get_by_name(self.ui.object_combo.get_value()) + except Exception as err: + self.app.log.debug("ToolDrilling -> Loaded Excellon object error. %s" % str(err)) + return if not checked: self.ui.level.setText('%s' % _('Beginner')) @@ -552,16 +565,16 @@ class ToolDrilling(AppTool, Excellon): # Tool parameters section if loaded_obj: - app_defaults = self.app.defaults + options = loaded_obj.options for tool in loaded_obj.tools: tool_data = loaded_obj.tools[tool]['data'] - tool_data['tools_drill_multidepth'] = app_defaults['tools_drill_multidepth'] - tool_data['tools_drill_dwell'] = app_defaults['tools_drill_dwell'] - tool_data['tools_drill_drill_slots'] = app_defaults['tools_drill_drill_slots'] + tool_data['tools_drill_multidepth'] = options['tools_drill_multidepth'] + tool_data['tools_drill_dwell'] = options['tools_drill_dwell'] + tool_data['tools_drill_drill_slots'] = options['tools_drill_drill_slots'] - tool_data['tools_drill_toolchangexy'] = app_defaults['tools_drill_toolchangexy'] - tool_data['tools_drill_area_exclusion'] = app_defaults['tools_drill_area_exclusion'] + tool_data['tools_drill_toolchangexy'] = options['tools_drill_toolchangexy'] + tool_data['tools_drill_area_exclusion'] = options['tools_drill_area_exclusion'] self.ui.search_load_db_btn.show() @@ -902,6 +915,8 @@ class ToolDrilling(AppTool, Excellon): self.excellon_tools = self.excellon_obj.tools self.build_tool_ui() + self.update_ui() + sel_rows = set() table_items = self.ui.tools_table.selectedItems() if table_items: @@ -1184,6 +1199,7 @@ class ToolDrilling(AppTool, Excellon): def update_ui(self): self.blockSignals(True) + self.ui_disconnect() sel_rows = set() table_items = self.ui.tools_table.selectedItems() @@ -1199,6 +1215,7 @@ class ToolDrilling(AppTool, Excellon): "%s: %s" % (_('Parameters for'), _("No Tool Selected")) ) self.blockSignals(False) + self.ui_connect() return else: self.ui.generate_cnc_button.setDisabled(False) @@ -1224,12 +1241,15 @@ class ToolDrilling(AppTool, Excellon): self.storage_to_form(self.excellon_tools[tooluid]['data']) else: self.blockSignals(False) + self.ui_connect() return except Exception as e: log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e)) self.blockSignals(False) + self.ui_connect() return self.blockSignals(False) + self.ui_connect() def storage_to_form(self, dict_storage): """ @@ -1240,6 +1260,8 @@ class ToolDrilling(AppTool, Excellon): :return: None :rtype: """ + + # update the Tool parameters for form_key in self.tool_form_fields: for storage_key in dict_storage: if form_key == storage_key and form_key not in \ @@ -1250,6 +1272,16 @@ class ToolDrilling(AppTool, Excellon): log.debug("ToolDrilling.storage_to_form() --> %s" % str(e)) pass + # update the Common parameters + for form_key in self.general_form_fields: + for storage_key in dict_storage: + if form_key == storage_key: + try: + self.general_form_fields[form_key].set_value(dict_storage[form_key]) + except Exception as e: + log.debug("ToolDrilling.storage_to_form() -> common parameters --> %s" % str(e)) + pass + def form_to_storage(self): """ Will update the 'storage' attribute which is the dict self.tools with data collected from GUI @@ -1886,10 +1918,10 @@ class ToolDrilling(AppTool, Excellon): # ############################################################################################################# # General Parameters # ############################################################################################################# - used_excellon_optimization_type = self.app.defaults["excellon_optimization_type"] + used_exc_optim_type = self.app.defaults["excellon_optimization_type"] current_platform = platform.architecture()[0] if current_platform != '64bit': - used_excellon_optimization_type = 'T' + used_exc_optim_type = 'T' # ############################################################################################################# # ############################################################################################################# @@ -2064,8 +2096,8 @@ class ToolDrilling(AppTool, Excellon): first_pt=first_drill_point, is_first=True, is_last=True, - opt_type=used_excellon_optimization_type, - toolchange=True) + opt_type=used_exc_optim_type, + toolchange=False) # parse the Gcode tool_gcode_parsed = job_obj.excellon_tool_gcode_parse(used_tooldia, gcode=tool_gcode, @@ -2116,13 +2148,13 @@ class ToolDrilling(AppTool, Excellon): is_first_tool = True if tool == sel_tools[0] else False # Generate Gcode for the current tool - tool_gcode, last_pt, start_gcode = job_obj.excellon_tool_gcode_gen( - tool, tool_points, self.excellon_tools, - first_pt=first_drill_point, - is_first=is_first_tool, - is_last=is_last_tool, - opt_type=used_excellon_optimization_type, - toolchange=True) + tool_gcode, last_pt, start_gcode = job_obj.excellon_tool_gcode_gen(tool, tool_points, + self.excellon_tools, + first_pt=first_drill_point, + is_first=is_first_tool, + is_last=is_last_tool, + opt_type=used_exc_optim_type, + toolchange=True) # parse Gcode for the current tool tool_gcode_parsed = job_obj.excellon_tool_gcode_parse(used_tooldia, gcode=tool_gcode, @@ -2149,13 +2181,13 @@ class ToolDrilling(AppTool, Excellon): # FIXME is it necessary? didn't we do it previously when filling data in self.exc_cnc_tools dictionary? job_obj.create_geometry() - if used_excellon_optimization_type == 'M': + if used_exc_optim_type == 'M': log.debug("The total travel distance with OR-TOOLS Metaheuristics is: %s" % str(job_obj.measured_distance)) - elif used_excellon_optimization_type == 'B': + elif used_exc_optim_type == 'B': log.debug("The total travel distance with OR-TOOLS Basic Algorithm is: %s" % str(job_obj.measured_distance)) - elif used_excellon_optimization_type == 'T': + elif used_exc_optim_type == 'T': log.debug( "The total travel distance with Travelling Salesman Algorithm is: %s" % str(job_obj.measured_distance)) diff --git a/camlib.py b/camlib.py index 46581d1f..771261ff 100644 --- a/camlib.py +++ b/camlib.py @@ -3301,9 +3301,12 @@ class CNCjob(Geometry): # t_gcode += start_gcode # do the ToolChange event - t_gcode += self.doformat(p.z_feedrate_code) - t_gcode += self.doformat(p.toolchange_code, toolchangexy=(temp_locx, temp_locy)) - t_gcode += self.doformat(p.z_feedrate_code) + if toolchange: + t_gcode += self.doformat(p.z_feedrate_code) + t_gcode += self.doformat(p.toolchange_code, toolchangexy=(temp_locx, temp_locy)) + t_gcode += self.doformat(p.z_feedrate_code) + else: + t_gcode += self.doformat(p.lift_code) # Spindle start t_gcode += self.doformat(p.spindle_code) diff --git a/preprocessors/Check_points.py b/preprocessors/Check_points.py new file mode 100644 index 00000000..fe5c6a6b --- /dev/null +++ b/preprocessors/Check_points.py @@ -0,0 +1,252 @@ +# ########################################################## +# FlatCAM: 2D Post-processing for Manufacturing # +# http://flatcam.org # +# File Author: Marius Stanciu # +# Date: 11-Dec-2020 # +# MIT Licence # +# ########################################################## + +from appPreProcessor import * + + +class Check_points(PreProc): + + include_header = True + coordinate_format = "%.*f" + feedrate_format = '%.*f' + + def start_code(self, p): + units = ' ' + str(p['units']).lower() + coords_xy = p['xy_toolchange'] + end_coords_xy = p['xy_end'] + gcode = '(This preprocessor is used to check the positioning of the PCB,)\n' + gcode += '(by moving a probe - possible a fine drill bit - to custom locations)\n' + gcode += '(and wait for user interaction in order to continue to the next point.)\n\n' + + xmin = '%.*f' % (p.coords_decimals, p['options']['xmin']) + xmax = '%.*f' % (p.coords_decimals, p['options']['xmax']) + ymin = '%.*f' % (p.coords_decimals, p['options']['ymin']) + ymax = '%.*f' % (p.coords_decimals, p['options']['ymax']) + + if str(p['options']['type']) == 'Geometry': + gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n' + gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n' + gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n' + gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n' + gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n' + if p['multidepth'] is True: + gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \ + str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n' + gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n' + + elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True: + gcode += '\n(TOOLS DIAMETER: )\n' + for tool, val in p['exc_tools'].items(): + gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["tooldia"]) + ')\n' + + gcode += '\n(FEEDRATE Z: )\n' + for tool, val in p['exc_tools'].items(): + gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % \ + str(val['data']["tools_drill_feedrate_z"]) + ')\n' + + gcode += '\n(FEEDRATE RAPIDS: )\n' + for tool, val in p['exc_tools'].items(): + gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \ + str(val['data']["tools_drill_feedrate_rapid"]) + ')\n' + + gcode += '\n(Z_CUT: )\n' + for tool, val in p['exc_tools'].items(): + gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["tools_drill_cutz"]) + ')\n' + + gcode += '\n(Tools Offset: )\n' + for tool, val in p['exc_cnc_tools'].items(): + gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % \ + str(val['data']["tools_drill_offset"]) + ')\n' + + if p['multidepth'] is True: + gcode += '\n(DEPTH_PER_CUT: )\n' + for tool, val in p['exc_tools'].items(): + gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \ + str(val['data']["tools_drill_depthperpass"]) + ')\n' + + gcode += '\n(Z_MOVE: )\n' + for tool, val in p['exc_tools'].items(): + gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n' + gcode += '\n' + + if p['toolchange'] is True: + gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n' + + if coords_xy is not None: + gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0], + p.decimals, coords_xy[1]) + units + ')\n' + else: + gcode += '(X,Y Toolchange: ' + "None" + units + ')\n' + + gcode += '(Z Start: ' + str(p['startz']) + units + ')\n' + gcode += '(Z End: ' + str(p['z_end']) + units + ')\n' + if end_coords_xy is not None: + gcode += '(X,Y End: ' + "%.*f, %.*f" % (p.decimals, end_coords_xy[0], + p.decimals, end_coords_xy[1]) + units + ')\n' + else: + gcode += '(X,Y End: ' + "None" + units + ')\n' + gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n' + + if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry': + gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n' + else: + gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n' + + gcode += '(X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + ')\n' + gcode += '(Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + ')\n\n' + + gcode += '(Spindle Speed: %s RPM)\n' % str(p['spindlespeed']) + + gcode += ('G20\n' if p.units.upper() == 'IN' else 'G21\n') + gcode += 'G90\n' + gcode += 'G94' + + return gcode + + def startz_code(self, p): + if p.startz is not None: + return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.startz) + else: + return '' + + def lift_code(self, p): + return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move) + + def down_code(self, p): + # make sure that the probe will always be above the material + cutz_val = -p.z_cut if p.z_cut < 0 else p.z_cut + gcode = 'G01 Z' + self.coordinate_format % (p.coords_decimals, cutz_val) + '\n' + # wait for user interaction + gcode += 'M0' + return gcode + + def toolchange_code(self, p): + z_toolchange = p.z_toolchange + toolchangexy = p.xy_toolchange + f_plunge = p.f_plunge + + if toolchangexy is not None: + x_toolchange = toolchangexy[0] + y_toolchange = toolchangexy[1] + else: + x_toolchange = 0.0 + y_toolchange = 0.0 + + if int(p.tool) == 1 and p.startz is not None: + z_toolchange = p.startz + + if str(p['options']['type']) == 'Excellon': + if toolchangexy is not None: + gcode = """ +M5 +G00 Z{z_toolchange} +G00 X{x_toolchange} Y{y_toolchange} +(MSG, Change to Tool T{tool}. WARNING: the following move is FAST G0) +M0 +G00 Z{z_move} +G01 Z0 +(MSG, Adjust the tool T{tool} to touch the material and then tighten it.) +M0 +(MSG, Changed to Tool T{tool}) +""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange), + y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange), + z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + z_move=self.coordinate_format % (p.coords_decimals, p.z_move), + tool=int(p.tool)) + + else: + gcode = """ +M5 +G00 Z{z_toolchange} +(MSG, Change to Tool T{tool}. WARNING: the following move is FAST G0) +M0 +G00 Z{z_move} +G01 Z0 +(MSG, Adjust the tool T{tool} to touch the material and then tighten it.) +M0 +(MSG, Changed to Tool T{tool}) +""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + z_move=self.coordinate_format % (p.coords_decimals, p.z_move), + tool=int(p.tool)) + + if f_plunge is True: + gcode += '\nG00 Z%.*f' % (p.coords_decimals, p.z_move) + return gcode + + else: + if toolchangexy is not None: + gcode = """ +M5 +G00 Z{z_toolchange} +G00 X{x_toolchange}Y{y_toolchange} +(MSG, Change to Tool T{tool}. WARNING: the following move is FAST G0) +M0 +G00 Z{z_move} +G01 Z0 +(MSG, Adjust the tool T{tool} to touch the material and then tighten it.) +M0 +(MSG, Changed to Tool T{tool}) +""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange), + y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange), + z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + z_move=self.coordinate_format % (p.coords_decimals, p.z_move), + tool=int(p.tool)) + else: + gcode = """ +M5 +G00 Z{z_toolchange} +(MSG, Change to Tool T{tool}. WARNING: the following move is FAST G0) +M0 +G00 Z{z_move} +G01 Z0 +(MSG, Adjust the tool T{tool} to touch the material and then tighten it.) +M0 +(MSG, Changed to Tool T{tool}) +""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + z_move=self.coordinate_format % (p.coords_decimals, p.z_move), + tool=int(p.tool)) + + if f_plunge is True: + gcode += '\nG00 Z%.*f' % (p.coords_decimals, p.z_move) + return gcode + + def up_to_zero_code(self, p): + return '' + + def position_code(self, p): + return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \ + (p.coords_decimals, p.x, p.coords_decimals, p.y) + + def rapid_code(self, p): + return ('G00 ' + self.position_code(p)).format(**p) + + def linear_code(self, p): + return ('G00 ' + self.position_code(p)).format(**p) + + def end_code(self, p): + end_coords_xy = p['xy_end'] + gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n") + + if end_coords_xy and end_coords_xy != '': + gcode += 'G00 X{x} Y{y}'.format(x=end_coords_xy[0], y=end_coords_xy[1]) + "\n" + return gcode + + def feedrate_code(self, p): + return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) + + def z_feedrate_code(self, p): + return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate)) + + def spindle_code(self, p): + return '' + + def dwell_code(self, p): + return '' + + def spindle_stop_code(self, p): + return 'M05' diff --git a/preprocessors/Default_no_M6.py b/preprocessors/Default_no_M6.py index 2b001364..9f257dbd 100644 --- a/preprocessors/Default_no_M6.py +++ b/preprocessors/Default_no_M6.py @@ -147,7 +147,6 @@ class Default_no_M6(PreProc): gcode = """ M5 G00 Z{z_toolchange} -T{tool} G00 X{x_toolchange} Y{y_toolchange} (MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills}) M0 @@ -162,7 +161,6 @@ G00 Z{z_toolchange} gcode = """ M5 G00 Z{z_toolchange} -T{tool} (MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills}) M0 G00 Z{z_toolchange} @@ -181,7 +179,6 @@ G00 Z{z_toolchange} M5 G00 Z{z_toolchange} G00 X{x_toolchange} Y{y_toolchange} -T{tool} (MSG, Change to Tool Dia = {toolC}) M0 G00 Z{z_toolchange} @@ -195,7 +192,6 @@ G00 Z{z_toolchange} gcode = """ M5 G00 Z{z_toolchange} -T{tool} (MSG, Change to Tool Dia = {toolC}) M0 G00 Z{z_toolchange}