From 06c526db392db0b9aaf592577793370fd0fdb7fd Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Thu, 3 Sep 2020 00:37:10 +0300 Subject: [PATCH] - in CNCJob UI Autolevelling - GRBL controller - added a way to save a GRBL height map - in CNCJob UI Autolevelling: added the UI for choosing the method used for the interpolation used in autolevelling --- CHANGELOG.md | 2 + appGUI/ObjectUI.py | 38 ++++++++++++- appGUI/preferences/PreferencesUIManager.py | 1 + .../cncjob/CNCJobAdvOptPrefGroupUI.py | 14 +++++ appObjects/FlatCAMCNCJob.py | 57 ++++++++++++++++++- defaults.py | 1 + 6 files changed, 107 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e971b06f..234bb4ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ CHANGELOG for FlatCAM beta - in CNCJob UI Autolevelling: in manual adding of probe points make sure you always add a first probe point in origin - in CNCJob UI Autolevelling: first added point when manual adding of probe points is auto added in origin before adding first point - in CNCJob UI Autolevelling: temp geo for adding points in manual mode is now painted in solid black color and with a smaller diameter +- in CNCJob UI Autolevelling - GRBL controller - added a way to save a GRBL height map +- in CNCJob UI Autolevelling: added the UI for choosing the method used for the interpolation used in autolevelling 31.08.2020 diff --git a/appGUI/ObjectUI.py b/appGUI/ObjectUI.py index 04b82fdc..4639aa38 100644 --- a/appGUI/ObjectUI.py +++ b/appGUI/ObjectUI.py @@ -1988,6 +1988,7 @@ class CNCObjectUI(ObjectUI): separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) grid0.addWidget(separator_line, 15, 0, 1, 2) + # AUTOLEVELL MODE al_mode_lbl = FCLabel('%s:' % _("Mode")) al_mode_lbl.setToolTip(_("Choose a mode for height map generation.\n" "- Manual: will pick a selection of probe points by clicking on canvas\n" @@ -1998,8 +1999,26 @@ class CNCObjectUI(ObjectUI): {'label': _('Manual'), 'value': 'manual'}, {'label': _('Grid'), 'value': 'grid'} ]) - grid0.addWidget(al_mode_lbl, 17, 0) - grid0.addWidget(self.al_mode_radio, 17, 1) + grid0.addWidget(al_mode_lbl, 16, 0) + grid0.addWidget(self.al_mode_radio, 16, 1) + + # AUTOLEVELL METHOD + self.al_method_lbl = FCLabel('%s:' % _("Method")) + self.al_method_lbl.setToolTip(_("Choose a method for approximation of heights from autolevelling data.\n" + "- Voronoi: will generate a Voronoi diagram\n" + "- Bilinear: will use bilinear interpolation. Usable only for grid mode.")) + + self.al_method_radio = RadioSet( + [ + {'label': _('Voronoi'), 'value': 'v'}, + {'label': _('Bilinear'), 'value': 'b'} + ]) + self.al_method_lbl.setDisabled(True) + self.al_method_radio.setDisabled(True) + self.al_method_radio.set_value('v') + + grid0.addWidget(self.al_method_lbl, 17, 0) + grid0.addWidget(self.al_method_radio, 17, 1) # ## Columns self.al_columns_entry = FCSpinner() @@ -2338,6 +2357,7 @@ class CNCObjectUI(ObjectUI): ) grbl_send_grid.addWidget(self.grbl_report_button, 10, 0, 1, 2) + hm_lay = QtWidgets.QHBoxLayout() # GET HEIGHT MAP self.grbl_get_heightmap_button = FCButton(_("Apply AutoLevelling")) self.grbl_get_heightmap_button.setToolTip( @@ -2345,13 +2365,25 @@ class CNCObjectUI(ObjectUI): "wait for the Z probing data and then apply this data\n" "over the original GCode therefore doing autolevelling.") ) - grbl_send_grid.addWidget(self.grbl_get_heightmap_button, 12, 0, 1, 2) + hm_lay.addWidget(self.grbl_get_heightmap_button, stretch=1) + + self.grbl_save_height_map_button = QtWidgets.QToolButton() + self.grbl_save_height_map_button.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png')) + self.grbl_save_height_map_button.setToolTip( + _("Will save the GRBL height map.") + ) + hm_lay.addWidget(self.grbl_save_height_map_button, stretch=0, alignment=Qt.AlignRight) + + grbl_send_grid.addLayout(hm_lay, 12, 0, 1, 2) self.grbl_frame.hide() # ############################################################################################################# height_lay = QtWidgets.QHBoxLayout() self.h_gcode_button = FCButton(_("Save Probing GCode")) + self.h_gcode_button.setToolTip( + _("Will save the probing GCode.") + ) self.h_gcode_button.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) height_lay.addWidget(self.h_gcode_button) diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index e6536b1d..ebed23d4 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -310,6 +310,7 @@ class PreferencesUIManager: "cncjob_annotation_fontcolor": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry, # Autolevelling "cncjob_al_mode": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.al_mode_radio, + "cncjob_al_method": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.al_method_radio, "cncjob_al_rows": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.al_rows_entry, "cncjob_al_columns": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.al_columns_entry, "cncjob_al_travelz": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.ptravelz_entry, diff --git a/appGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py b/appGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py index f768f86b..3c985fac 100644 --- a/appGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py +++ b/appGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py @@ -81,6 +81,20 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI): grid0.addWidget(al_mode_lbl, 8, 0) grid0.addWidget(self.al_mode_radio, 8, 1) + # AUTOLEVELL METHOD + self.al_method_lbl = FCLabel('%s:' % _("Method")) + self.al_method_lbl.setToolTip(_("Choose a method for approximation of heights from autolevelling data.\n" + "- Voronoi: will generate a Voronoi diagram\n" + "- Bilinear: will use bilinear interpolation. Usable only for grid mode.")) + + self.al_method_radio = RadioSet( + [ + {'label': _('Voronoi'), 'value': 'v'}, + {'label': _('Bilinear'), 'value': 'b'} + ]) + grid0.addWidget(self.al_method_lbl, 9, 0) + grid0.addWidget(self.al_method_radio, 9, 1) + # ## Columns self.al_columns_entry = FCSpinner() diff --git a/appObjects/FlatCAMCNCJob.py b/appObjects/FlatCAMCNCJob.py index c4f5237b..0c55b888 100644 --- a/appObjects/FlatCAMCNCJob.py +++ b/appObjects/FlatCAMCNCJob.py @@ -171,6 +171,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.source_file = '' self.units_found = self.app.defaults['units'] self.probing_gcode_text = '' + self.grbl_probe_result = '' # store the current selection shape status to be restored after manual adding test points self.old_selection_state = self.app.defaults['global_selection_shape'] @@ -467,11 +468,13 @@ class CNCJobObject(FlatCAMObj, CNCjob): if self.ui.al_probe_points_table.model().rowCount(): self.ui.voronoi_cb.setDisabled(False) self.ui.grbl_get_heightmap_button.setDisabled(False) + self.ui.grbl_save_height_map_button.setDisabled(False) self.ui.h_gcode_button.setDisabled(False) self.ui.view_h_gcode_button.setDisabled(False) else: self.ui.voronoi_cb.setDisabled(True) self.ui.grbl_get_heightmap_button.setDisabled(True) + self.ui.grbl_save_height_map_button.setDisabled(True) self.ui.h_gcode_button.setDisabled(True) self.ui.view_h_gcode_button.setDisabled(True) @@ -501,6 +504,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): "al_probe_depth": self.ui.pdepth_entry, "al_probe_fr": self.ui.feedrate_probe_entry, "al_controller": self.ui.al_controller_combo, + "al_method": self.ui.al_method_radio, "al_mode": self.ui.al_mode_radio, "al_rows": self.ui.al_rows_entry, "al_columns": self.ui.al_columns_entry, @@ -605,6 +609,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.ui.import_heights_button.clicked.connect(self.on_import_height_map) self.ui.pause_resume_button.clicked.connect(self.on_grbl_pause_resume) self.ui.grbl_get_heightmap_button.clicked.connect(self.on_grbl_autolevel) + self.ui.grbl_save_height_map_button.clicked.connect(self.on_grbl_heightmap_save) self.build_al_table_sig.connect(self.build_al_table) @@ -1091,11 +1096,17 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.ui.al_rows_label.setDisabled(True) self.ui.al_columns_entry.setDisabled(True) self.ui.al_columns_label.setDisabled(True) + self.ui.al_method_lbl.setDisabled(True) + self.ui.al_method_radio.setDisabled(True) + self.ui.al_method_radio.set_value('v') else: self.ui.al_rows_entry.setDisabled(False) self.ui.al_rows_label.setDisabled(False) self.ui.al_columns_entry.setDisabled(False) self.ui.al_columns_label.setDisabled(False) + self.ui.al_method_lbl.setDisabled(False) + self.ui.al_method_radio.setDisabled(False) + self.ui.al_method_radio.set_value(self.app.defaults['cncjob_al_method']) def on_controller_change(self): if self.ui.al_controller_combo.get_value() == 'GRBL': @@ -1676,7 +1687,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): def worker_task(): with self.app.proc_container.new(_("Sending GCode...")): - probe_result = '' + self.grbl_probe_result = '' pr_travelz = str(self.ui.ptravelz_entry.get_value()) probe_fr = str(self.ui.feedrate_probe_entry.get_value()) pr_depth = str(self.ui.pdepth_entry.get_value()) @@ -1697,7 +1708,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): cmd = 'G38.2 Z%s F%s' % (pr_depth, probe_fr) output = self.send_grbl_command(command=cmd) - probe_result += output + '\n' + self.grbl_probe_result += output + '\n' cmd = 'M2\n' self.send_grbl_command(command=cmd) @@ -1709,8 +1720,48 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.app.inform.emit('%s' % _("Sending probing GCode to the GRBL controller.")) self.app.worker_task.emit({'fcn': worker_task, 'params': []}) + def on_grbl_heightmap_save(self): + if self.grbl_probe_result != '': + _filter_ = "Text File .txt (*.txt);;All Files (*.*)" + name = "probing_gcode" + try: + dir_file_to_save = self.app.get_last_save_folder() + '/' + str(name) + filename, _f = FCFileSaveDialog.get_saved_filename( + caption=_("Export Code ..."), + directory=dir_file_to_save, + ext_filter=_filter_ + ) + except TypeError: + filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export Code ..."), ext_filter=_filter_) + + if filename == '': + self.app.inform.emit('[WARNING_NOTCL] %s' % _("Export cancelled ...")) + return + else: + try: + force_windows_line_endings = self.app.defaults['cncjob_line_ending'] + if force_windows_line_endings and sys.platform != 'win32': + with open(filename, 'w', newline='\r\n') as f: + for line in self.grbl_probe_result: + f.write(line) + else: + with open(filename, 'w') as f: + for line in self.grbl_probe_result: + f.write(line) + except FileNotFoundError: + self.app.inform.emit('[WARNING_NOTCL] %s' % _("No such file or directory")) + return + except PermissionError: + self.app.inform.emit( + '[WARNING] %s' % _("Permission denied, saving not possible.\n" + "Most likely another app is holding the file open and not accessible.") + ) + return 'fail' + else: + self.app.inform.emit('[ERROR_NOTCL] %s' % _("Empty GRBL heightmap.")) + def on_grbl_apply_autolevel(self): - # TODO here we call the autovell method + # TODO here we call the autolevell method self.app.inform.emit('%s' % _("Finished autolevelling.")) def on_updateplot_button_click(self, *args): diff --git a/defaults.py b/defaults.py index ff2f3d69..43661fb8 100644 --- a/defaults.py +++ b/defaults.py @@ -378,6 +378,7 @@ class FlatCAMDefaults: # Autolevelling "cncjob_al_status": False, "cncjob_al_mode": 'grid', + "cncjob_al_method": 'v', "cncjob_al_rows": 4, "cncjob_al_columns": 4, "cncjob_al_travelz": 2.0,