Explorar o código

- 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

Marius Stanciu %!s(int64=5) %!d(string=hai) anos
pai
achega
06c526db39

+ 2 - 0
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
 

+ 35 - 3
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('<b>%s</b>:' % _("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)

+ 1 - 0
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,

+ 14 - 0
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()
 

+ 54 - 3
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):

+ 1 - 0
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,