Procházet zdrojové kódy

- working on the Calibrate Excellon Tool
- converted Excellon Editor to usage of SpinBoxes

Marius Stanciu před 6 roky
rodič
revize
120e866a01
4 změnil soubory, kde provedl 194 přidání a 32 odebrání
  1. 2 0
      README.md
  2. 2 2
      camlib.py
  3. 52 23
      flatcamEditors/FlatCAMExcEditor.py
  4. 138 7
      flatcamTools/ToolCalibrateExcellon.py

+ 2 - 0
README.md

@@ -15,6 +15,8 @@ CAD program, and create G-Code for Isolation routing.
 - in legacy2D graphic engine, adding an utility geometry no longer draw the older ones, overwriting them
 - in legacy2D graphic engine, adding an utility geometry no longer draw the older ones, overwriting them
 - fixed some issues in the Gerber Editor (Aperture add was double adding an aperture)
 - fixed some issues in the Gerber Editor (Aperture add was double adding an aperture)
 - converted Gerber Editor to usage of SpinBoxes
 - converted Gerber Editor to usage of SpinBoxes
+- working on the Calibrate Excellon Tool
+- converted Excellon Editor to usage of SpinBoxes
 
 
 27.10.2019
 27.10.2019
 
 

+ 2 - 2
camlib.py

@@ -2448,7 +2448,7 @@ class CNCjob(Geometry):
                 except KeyError:
                 except KeyError:
                     points[drill['tool']] = [drill['point']]
                     points[drill['tool']] = [drill['point']]
 
 
-        #log.debug("Found %d drills." % len(points))
+        # log.debug("Found %d drills." % len(points))
 
 
         self.gcode = []
         self.gcode = []
 
 
@@ -2633,7 +2633,7 @@ class CNCjob(Geometry):
                                 # Drillling! for Absolute coordinates type G90
                                 # Drillling! for Absolute coordinates type G90
                                 # variables to display the percentage of work done
                                 # variables to display the percentage of work done
                                 geo_len = len(node_list)
                                 geo_len = len(node_list)
-                                disp_number = 0
+
                                 old_disp_number = 0
                                 old_disp_number = 0
                                 log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
                                 log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
 
 

+ 52 - 23
flatcamEditors/FlatCAMExcEditor.py

@@ -9,7 +9,7 @@ from PyQt5 import QtGui, QtCore, QtWidgets
 from PyQt5.QtCore import Qt, QSettings
 from PyQt5.QtCore import Qt, QSettings
 
 
 from camlib import distance, arc, FlatCAMRTreeStorage
 from camlib import distance, arc, FlatCAMRTreeStorage
-from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
+from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, RadioSet, FCSpinner
 from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
 from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
 from flatcamParsers.ParseExcellon import Excellon
 from flatcamParsers.ParseExcellon import Excellon
 import FlatCAMApp
 import FlatCAMApp
@@ -1445,6 +1445,9 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.app = app
         self.app = app
         self.canvas = self.app.plotcanvas
         self.canvas = self.app.plotcanvas
 
 
+        # Number of decimals used by tools in this class
+        self.decimals = 4
+
         # ## Current application units in Upper Case
         # ## Current application units in Upper Case
         self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
         self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
 
 
@@ -1518,6 +1521,8 @@ class FlatCAMExcEditor(QtCore.QObject):
 
 
         grid1 = QtWidgets.QGridLayout()
         grid1 = QtWidgets.QGridLayout()
         self.tools_box.addLayout(grid1)
         self.tools_box.addLayout(grid1)
+        grid1.setColumnStretch(0, 0)
+        grid1.setColumnStretch(1, 1)
 
 
         addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('Tool Dia'))
         addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('Tool Dia'))
         addtool_entry_lbl.setToolTip(
         addtool_entry_lbl.setToolTip(
@@ -1525,8 +1530,10 @@ class FlatCAMExcEditor(QtCore.QObject):
         )
         )
 
 
         hlay = QtWidgets.QHBoxLayout()
         hlay = QtWidgets.QHBoxLayout()
-        self.addtool_entry = FCEntry()
-        self.addtool_entry.setValidator(QtGui.QDoubleValidator(0.0001, 99.9999, 4))
+        self.addtool_entry = FCDoubleSpinner()
+        self.addtool_entry.set_precision(self.decimals)
+        self.addtool_entry.set_range(0.0000, 9999.9999)
+
         hlay.addWidget(self.addtool_entry)
         hlay.addWidget(self.addtool_entry)
 
 
         self.addtool_btn = QtWidgets.QPushButton(_('Add Tool'))
         self.addtool_btn = QtWidgets.QPushButton(_('Add Tool'))
@@ -1579,7 +1586,10 @@ class FlatCAMExcEditor(QtCore.QObject):
         grid3.addWidget(res_entry_lbl, 0, 0)
         grid3.addWidget(res_entry_lbl, 0, 0)
 
 
         hlay2 = QtWidgets.QHBoxLayout()
         hlay2 = QtWidgets.QHBoxLayout()
-        self.resdrill_entry = LengthEntry()
+        self.resdrill_entry = FCDoubleSpinner()
+        self.resdrill_entry.set_precision(self.decimals)
+        self.resdrill_entry.set_range(0.0000, 9999.9999)
+
         hlay2.addWidget(self.resdrill_entry)
         hlay2.addWidget(self.resdrill_entry)
 
 
         self.resize_btn = QtWidgets.QPushButton(_('Resize'))
         self.resize_btn = QtWidgets.QPushButton(_('Resize'))
@@ -1633,7 +1643,8 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.drill_array_size_label.setToolTip(_("Specify how many drills to be in the array."))
         self.drill_array_size_label.setToolTip(_("Specify how many drills to be in the array."))
         self.drill_array_size_label.setMinimumWidth(100)
         self.drill_array_size_label.setMinimumWidth(100)
 
 
-        self.drill_array_size_entry = LengthEntry()
+        self.drill_array_size_entry = FCSpinner()
+        self.drill_array_size_entry.set_range(1, 9999)
         self.array_form.addRow(self.drill_array_size_label, self.drill_array_size_entry)
         self.array_form.addRow(self.drill_array_size_label, self.drill_array_size_entry)
 
 
         self.array_linear_frame = QtWidgets.QFrame()
         self.array_linear_frame = QtWidgets.QFrame()
@@ -1668,7 +1679,10 @@ class FlatCAMExcEditor(QtCore.QObject):
         )
         )
         self.drill_pitch_label.setMinimumWidth(100)
         self.drill_pitch_label.setMinimumWidth(100)
 
 
-        self.drill_pitch_entry = LengthEntry()
+        self.drill_pitch_entry = FCDoubleSpinner()
+        self.drill_pitch_entry.set_precision(self.decimals)
+        self.drill_pitch_entry.set_range(0.0000, 9999.9999)
+
         self.linear_form.addRow(self.drill_pitch_label, self.drill_pitch_entry)
         self.linear_form.addRow(self.drill_pitch_label, self.drill_pitch_entry)
 
 
         # Linear Drill Array angle
         # Linear Drill Array angle
@@ -1676,15 +1690,15 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.linear_angle_label.setToolTip(
         self.linear_angle_label.setToolTip(
            _("Angle at which the linear array is placed.\n"
            _("Angle at which the linear array is placed.\n"
              "The precision is of max 2 decimals.\n"
              "The precision is of max 2 decimals.\n"
-             "Min value is: -359.99 degrees.\n"
+             "Min value is: -360 degrees.\n"
              "Max value is:  360.00 degrees.")
              "Max value is:  360.00 degrees.")
         )
         )
         self.linear_angle_label.setMinimumWidth(100)
         self.linear_angle_label.setMinimumWidth(100)
 
 
         self.linear_angle_spinner = FCDoubleSpinner()
         self.linear_angle_spinner = FCDoubleSpinner()
-        self.linear_angle_spinner.set_precision(2)
+        self.linear_angle_spinner.set_precision(self.decimals)
         self.linear_angle_spinner.setSingleStep(1.0)
         self.linear_angle_spinner.setSingleStep(1.0)
-        self.linear_angle_spinner.setRange(-359.99, 360.00)
+        self.linear_angle_spinner.setRange(-360.00, 360.00)
         self.linear_form.addRow(self.linear_angle_label, self.linear_angle_spinner)
         self.linear_form.addRow(self.linear_angle_label, self.linear_angle_spinner)
 
 
         self.array_circular_frame = QtWidgets.QFrame()
         self.array_circular_frame = QtWidgets.QFrame()
@@ -1710,7 +1724,11 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.drill_angle_label.setToolTip(_("Angle at which each element in circular array is placed."))
         self.drill_angle_label.setToolTip(_("Angle at which each element in circular array is placed."))
         self.drill_angle_label.setMinimumWidth(100)
         self.drill_angle_label.setMinimumWidth(100)
 
 
-        self.drill_angle_entry = LengthEntry()
+        self.drill_angle_entry = FCDoubleSpinner()
+        self.drill_angle_entry.set_precision(self.decimals)
+        self.drill_angle_entry.setSingleStep(1.0)
+        self.drill_angle_entry.setRange(-360.00, 360.00)
+
         self.circular_form.addRow(self.drill_angle_label, self.drill_angle_entry)
         self.circular_form.addRow(self.drill_angle_label, self.drill_angle_entry)
 
 
         self.array_circular_frame.hide()
         self.array_circular_frame.hide()
@@ -1754,7 +1772,11 @@ class FlatCAMExcEditor(QtCore.QObject):
         )
         )
         self.slot_length_label.setMinimumWidth(100)
         self.slot_length_label.setMinimumWidth(100)
 
 
-        self.slot_length_entry = LengthEntry()
+        self.slot_length_entry = FCDoubleSpinner()
+        self.slot_length_entry.set_precision(self.decimals)
+        self.slot_length_entry.setSingleStep(0.1)
+        self.slot_length_entry.setRange(0.0000, 9999.9999)
+
         self.slot_form.addRow(self.slot_length_label, self.slot_length_entry)
         self.slot_form.addRow(self.slot_length_label, self.slot_length_entry)
 
 
         # Slot direction
         # Slot direction
@@ -1777,15 +1799,15 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.slot_angle_label.setToolTip(
         self.slot_angle_label.setToolTip(
            _("Angle at which the slot is placed.\n"
            _("Angle at which the slot is placed.\n"
              "The precision is of max 2 decimals.\n"
              "The precision is of max 2 decimals.\n"
-             "Min value is: -359.99 degrees.\n"
+             "Min value is: -360 degrees.\n"
              "Max value is:  360.00 degrees.")
              "Max value is:  360.00 degrees.")
         )
         )
         self.slot_angle_label.setMinimumWidth(100)
         self.slot_angle_label.setMinimumWidth(100)
 
 
         self.slot_angle_spinner = FCDoubleSpinner()
         self.slot_angle_spinner = FCDoubleSpinner()
-        self.slot_angle_spinner.set_precision(2)
+        self.slot_angle_spinner.set_precision(self.decimals)
         self.slot_angle_spinner.setWrapping(True)
         self.slot_angle_spinner.setWrapping(True)
-        self.slot_angle_spinner.setRange(-359.99, 360.00)
+        self.slot_angle_spinner.setRange(-360.00, 360.00)
         self.slot_angle_spinner.setSingleStep(1.0)
         self.slot_angle_spinner.setSingleStep(1.0)
         self.slot_form.addRow(self.slot_angle_label, self.slot_angle_spinner)
         self.slot_form.addRow(self.slot_angle_label, self.slot_angle_spinner)
 
 
@@ -1835,7 +1857,9 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.slot_array_size_label.setToolTip(_("Specify how many slots to be in the array."))
         self.slot_array_size_label.setToolTip(_("Specify how many slots to be in the array."))
         self.slot_array_size_label.setMinimumWidth(100)
         self.slot_array_size_label.setMinimumWidth(100)
 
 
-        self.slot_array_size_entry = LengthEntry()
+        self.slot_array_size_entry = FCSpinner()
+        self.slot_array_size_entry.set_range(0, 9999)
+
         self.slot_array_form.addRow(self.slot_array_size_label, self.slot_array_size_entry)
         self.slot_array_form.addRow(self.slot_array_size_label, self.slot_array_size_entry)
 
 
         self.slot_array_linear_frame = QtWidgets.QFrame()
         self.slot_array_linear_frame = QtWidgets.QFrame()
@@ -1870,7 +1894,11 @@ class FlatCAMExcEditor(QtCore.QObject):
         )
         )
         self.slot_array_pitch_label.setMinimumWidth(100)
         self.slot_array_pitch_label.setMinimumWidth(100)
 
 
-        self.slot_array_pitch_entry = LengthEntry()
+        self.slot_array_pitch_entry = FCDoubleSpinner()
+        self.slot_array_pitch_entry.set_precision(self.decimals)
+        self.slot_array_pitch_entry.setSingleStep(0.1)
+        self.slot_array_pitch_entry.setRange(0.0000, 9999.9999)
+
         self.slot_array_linear_form.addRow(self.slot_array_pitch_label, self.slot_array_pitch_entry)
         self.slot_array_linear_form.addRow(self.slot_array_pitch_label, self.slot_array_pitch_entry)
 
 
         # Linear Slot Array angle
         # Linear Slot Array angle
@@ -1878,15 +1906,15 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.slot_array_linear_angle_label.setToolTip(
         self.slot_array_linear_angle_label.setToolTip(
             _("Angle at which the linear array is placed.\n"
             _("Angle at which the linear array is placed.\n"
               "The precision is of max 2 decimals.\n"
               "The precision is of max 2 decimals.\n"
-              "Min value is: -359.99 degrees.\n"
+              "Min value is: -360 degrees.\n"
               "Max value is:  360.00 degrees.")
               "Max value is:  360.00 degrees.")
         )
         )
         self.slot_array_linear_angle_label.setMinimumWidth(100)
         self.slot_array_linear_angle_label.setMinimumWidth(100)
 
 
         self.slot_array_linear_angle_spinner = FCDoubleSpinner()
         self.slot_array_linear_angle_spinner = FCDoubleSpinner()
-        self.slot_array_linear_angle_spinner.set_precision(2)
+        self.slot_array_linear_angle_spinner.set_precision(self.decimals)
         self.slot_array_linear_angle_spinner.setSingleStep(1.0)
         self.slot_array_linear_angle_spinner.setSingleStep(1.0)
-        self.slot_array_linear_angle_spinner.setRange(-359.99, 360.00)
+        self.slot_array_linear_angle_spinner.setRange(-360.00, 360.00)
         self.slot_array_linear_form.addRow(self.slot_array_linear_angle_label, self.slot_array_linear_angle_spinner)
         self.slot_array_linear_form.addRow(self.slot_array_linear_angle_label, self.slot_array_linear_angle_spinner)
 
 
         self.slot_array_circular_frame = QtWidgets.QFrame()
         self.slot_array_circular_frame = QtWidgets.QFrame()
@@ -1912,7 +1940,11 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.slot_array_angle_label.setToolTip(_("Angle at which each element in circular array is placed."))
         self.slot_array_angle_label.setToolTip(_("Angle at which each element in circular array is placed."))
         self.slot_array_angle_label.setMinimumWidth(100)
         self.slot_array_angle_label.setMinimumWidth(100)
 
 
-        self.slot_array_angle_entry = LengthEntry()
+        self.slot_array_angle_entry = FCDoubleSpinner()
+        self.slot_array_angle_entry.set_precision(self.decimals)
+        self.slot_array_angle_entry.setSingleStep(1)
+        self.slot_array_angle_entry.setRange(-360.00, 360.00)
+
         self.slot_array_circular_form.addRow(self.slot_array_angle_label, self.slot_array_angle_entry)
         self.slot_array_circular_form.addRow(self.slot_array_angle_label, self.slot_array_angle_entry)
 
 
         self.slot_array_linear_angle_spinner.hide()
         self.slot_array_linear_angle_spinner.hide()
@@ -2050,9 +2082,6 @@ class FlatCAMExcEditor(QtCore.QObject):
 
 
         self.complete = False
         self.complete = False
 
 
-        # Number of decimals used by tools in this class
-        self.decimals = 4
-
         def make_callback(thetool):
         def make_callback(thetool):
             def f():
             def f():
                 self.on_tool_select(thetool)
                 self.on_tool_select(thetool)

+ 138 - 7
flatcamTools/ToolCalibrateExcellon.py

@@ -8,7 +8,7 @@
 from PyQt5 import QtWidgets, QtCore
 from PyQt5 import QtWidgets, QtCore
 
 
 from FlatCAMTool import FlatCAMTool
 from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCDoubleSpinner, EvalEntry, FCCheckBox
+from flatcamGUI.GUIElements import FCDoubleSpinner, EvalEntry, FCCheckBox, OptionalInputSection
 
 
 from shapely.geometry import Point
 from shapely.geometry import Point
 from shapely.geometry.base import *
 from shapely.geometry.base import *
@@ -80,6 +80,9 @@ class ToolCalibrateExcellon(FlatCAMTool):
 
 
         # Travel Z entry
         # Travel Z entry
         travelz_lbl = QtWidgets.QLabel('%s:' % _("Travel Z"))
         travelz_lbl = QtWidgets.QLabel('%s:' % _("Travel Z"))
+        travelz_lbl.setToolTip(
+            _("Height (Z) for travelling between the points.")
+        )
 
 
         self.travelz_entry = FCDoubleSpinner()
         self.travelz_entry = FCDoubleSpinner()
         self.travelz_entry.set_range(-9999.9999, 9999.9999)
         self.travelz_entry.set_range(-9999.9999, 9999.9999)
@@ -91,6 +94,9 @@ class ToolCalibrateExcellon(FlatCAMTool):
 
 
         # Verification Z entry
         # Verification Z entry
         verz_lbl = QtWidgets.QLabel('%s:' % _("Verification Z"))
         verz_lbl = QtWidgets.QLabel('%s:' % _("Verification Z"))
+        verz_lbl.setToolTip(
+            _("Height (Z) for checking the point.")
+        )
 
 
         self.verz_entry = FCDoubleSpinner()
         self.verz_entry = FCDoubleSpinner()
         self.verz_entry.set_range(-9999.9999, 9999.9999)
         self.verz_entry.set_range(-9999.9999, 9999.9999)
@@ -103,12 +109,29 @@ class ToolCalibrateExcellon(FlatCAMTool):
         # Zero the Z of the verification tool
         # Zero the Z of the verification tool
         self.zeroz_cb = FCCheckBox('%s' % _("Zero Z tool"))
         self.zeroz_cb = FCCheckBox('%s' % _("Zero Z tool"))
         self.zeroz_cb.setToolTip(
         self.zeroz_cb.setToolTip(
-            _("Include a secquence to zero the height (Z)\n"
+            _("Include a sequence to zero the height (Z)\n"
               "of the verification tool.")
               "of the verification tool.")
         )
         )
+
         i_grid_lay.addWidget(self.zeroz_cb, 4, 0, 1, 3)
         i_grid_lay.addWidget(self.zeroz_cb, 4, 0, 1, 3)
 
 
-        i_grid_lay.addWidget(QtWidgets.QLabel(''), 5, 0, 1, 3)
+        # Toochange Z entry
+        toolchangez_lbl = QtWidgets.QLabel('%s:' % _("Toolchange Z"))
+        toolchangez_lbl.setToolTip(
+            _("Height (Z) for mounting the verification probe.")
+        )
+
+        self.toolchangez_entry = FCDoubleSpinner()
+        self.toolchangez_entry.set_range(0.0000, 9999.9999)
+        self.toolchangez_entry.set_precision(self.decimals)
+        self.toolchangez_entry.setSingleStep(0.1)
+
+        i_grid_lay.addWidget(toolchangez_lbl, 5, 0)
+        i_grid_lay.addWidget(self.toolchangez_entry, 5, 1, 1, 2)
+
+        self.z_ois = OptionalInputSection(self.zeroz_cb, [toolchangez_lbl, self.toolchangez_entry])
+
+        i_grid_lay.addWidget(QtWidgets.QLabel(''), 6, 0, 1, 3)
 
 
         # ## Grid Layout
         # ## Grid Layout
         grid_lay = QtWidgets.QGridLayout()
         grid_lay = QtWidgets.QGridLayout()
@@ -402,10 +425,14 @@ class ToolCalibrateExcellon(FlatCAMTool):
         # here store 4 points to be used for calibration
         # here store 4 points to be used for calibration
         self.click_points = list()
         self.click_points = list()
 
 
+        # store the status of the grid
+        self.grid_status_memory = None
+
         self.exc_obj = None
         self.exc_obj = None
 
 
         # ## Signals
         # ## Signals
         self.start_button.clicked.connect(self.on_start_collect_points)
         self.start_button.clicked.connect(self.on_start_collect_points)
+        self.gcode_button.clicked.connect(self.generate_verification_gcode)
 
 
     def run(self, toggle=True):
     def run(self, toggle=True):
         self.app.report_usage("ToolCalibrateExcellon()")
         self.app.report_usage("ToolCalibrateExcellon()")
@@ -445,6 +472,13 @@ class ToolCalibrateExcellon(FlatCAMTool):
         # self.mm_entry.set_value('%.*f' % (self.decimals, 0))
         # self.mm_entry.set_value('%.*f' % (self.decimals, 0))
 
 
     def on_start_collect_points(self):
     def on_start_collect_points(self):
+        # disengage the grid snapping since it will be hard to find the drills on grid
+        if self.app.ui.grid_snap_btn.isChecked():
+            self.grid_status_memory = True
+            self.app.ui.grid_snap_btn.trigger()
+        else:
+            self.grid_status_memory = False
+
         self.mr = self.canvas.graph_event_connect('mouse_release', self.on_mouse_click_release)
         self.mr = self.canvas.graph_event_connect('mouse_release', self.on_mouse_click_release)
 
 
         if self.app.is_legacy is False:
         if self.app.is_legacy is False:
@@ -502,9 +536,7 @@ class ToolCalibrateExcellon(FlatCAMTool):
             self.top_right_coordy_tgt.set_value(self.click_points[3][1])
             self.top_right_coordy_tgt.set_value(self.click_points[3][1])
             self.app.inform.emit('[success] %s' % _("Done. All four points have been acquired."))
             self.app.inform.emit('[success] %s' % _("Done. All four points have been acquired."))
             self.disconnect_cal_events()
             self.disconnect_cal_events()
-
-    def generate_verification_gcode(self):
-        pass
+            self.app.ui.grid_snap_btn.setChecked(self.grid_status_memory)
 
 
     def gcode_header(self):
     def gcode_header(self):
         log.debug("ToolCalibrateExcellon.gcode_header()")
         log.debug("ToolCalibrateExcellon.gcode_header()")
@@ -517,9 +549,108 @@ class ToolCalibrateExcellon(FlatCAMTool):
 
 
         gcode += '(Units: ' + self.units.upper() + ')\n' + "\n"
         gcode += '(Units: ' + self.units.upper() + ')\n' + "\n"
         gcode += '(Created on ' + time_str + ')\n' + '\n'
         gcode += '(Created on ' + time_str + ')\n' + '\n'
-
+        gcode += 'G20\n' if self.units.upper() == 'IN' else 'G21\n'
+        gcode += 'G90\n'
+        gcode += 'G17\n'
+        gcode += 'G94\n\n'
         return gcode
         return gcode
 
 
+    def generate_verification_gcode(self):
+        travel_z = '%.*f' % (self.decimals, self.travelz_entry.get_value())
+        toolchange_z = '%.*f' % (self.decimals, self.toolchangez_entry.get_value())
+        verification_z = '%.*f' % (self.decimals, self.verz_entry.get_value())
+
+        if len(self.click_points) != 4:
+            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Four points are needed for GCode generation."))
+            return 'fail'
+
+        gcode = self.gcode_header()
+        if self.zeroz_cb.get_value():
+            gcode += 'M5\n'
+            gcode += f'G00 Z{toolchange_z}\n'
+            gcode += 'M0\n'
+            gcode += 'G01 Z0\n'
+            gcode += 'M0\n'
+            gcode += f'G00 Z{toolchange_z}\n'
+            gcode += 'M0\n'
+
+        gcode += f'G00 Z{travel_z}\n'
+        gcode += f'G00 X{self.click_points[0][0]} Y{self.click_points[0][1]}\n'
+        gcode += f'G01 Z{verification_z}\n'
+        gcode += 'M0\n'
+
+        gcode += f'G00 Z{travel_z}\n'
+        gcode += f'G00 X{self.click_points[2][0]} Y{self.click_points[2][1]}\n'
+        gcode += f'G01 Z{verification_z}\n'
+        gcode += 'M0\n'
+
+        gcode += f'G00 Z{travel_z}\n'
+        gcode += f'G00 X{self.click_points[3][0]} Y{self.click_points[3][1]}\n'
+        gcode += f'G01 Z{verification_z}\n'
+        gcode += 'M0\n'
+
+        gcode += f'G00 Z{travel_z}\n'
+        gcode += f'G00 X{self.click_points[1][0]} Y{self.click_points[1][1]}\n'
+        gcode += f'G01 Z{verification_z}\n'
+        gcode += 'M0\n'
+
+        gcode += f'G00 Z{travel_z}\n'
+        gcode += f'G00 X0 Y0\n'
+        gcode += f'G00 Z{toolchange_z}\n'
+
+        gcode += 'M2'
+
+        _filter_ = "G-Code Files (*.nc);;All Files (*.*)"
+
+        try:
+            dir_file_to_save = self.app.get_last_save_folder() + '/' + 'ver_gcode'
+            filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+                caption=_("Export Machine Code ..."),
+                directory=dir_file_to_save,
+                filter=_filter_
+            )
+        except TypeError:
+            filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Machine Code ..."), filter=_filter_)
+
+        filename = str(filename)
+
+        if filename == '':
+            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Export Machine Code cancelled ..."))
+            return
+
+        with open(filename, 'w') as f:
+            f.write(gcode)
+
+    def calculate_factors(self):
+        origin_x = self.click_points[0][0]
+        origin_y = self.click_points[0][1]
+
+        top_left_x = float('%.*f' % (self.decimals, self.click_points[2][0]))
+        top_left_y = float('%.*f' % (self.decimals, self.click_points[2][1]))
+
+        top_left_dx = float('%.*f' % (self.decimals, self.top_left_coordx_found.get_value()))
+        top_left_dy = float('%.*f' % (self.decimals, self.top_left_coordy_found.get_value()))
+
+        top_right_x = float('%.*f' % (self.decimals, self.click_points[3][0]))
+        top_right_y = float('%.*f' % (self.decimals, self.click_points[3][1]))
+
+        top_right_dx = float('%.*f' % (self.decimals, self.top_right_coordx_found.get_value()))
+        top_right_dy = float('%.*f' % (self.decimals, self.top_right_coordy_found.get_value()))
+
+        bot_right_x = float('%.*f' % (self.decimals, self.click_points[1][0]))
+        bot_right_y = float('%.*f' % (self.decimals, self.click_points[1][1]))
+
+        bot_right_dx = float('%.*f' % (self.decimals, self.bottom_right_coordx_found.get_value()))
+        bot_right_dy = float('%.*f' % (self.decimals, self.bottom_right_coordy_found.get_value()))
+
+        if top_left_dy != top_left_y:
+            scale_y = (top_left_dy - origin_y) / (top_left_y - origin_y)
+            self.scaley_entry.set_value(scale_y)
+
+        if top_right_dx != top_right_x:
+            scale_x = (top_right_dx - origin_x) / (top_right_x - origin_x)
+            self.scalex_entry.set_value(scale_x)
+
     def disconnect_cal_events(self):
     def disconnect_cal_events(self):
         self.app.mr = self.canvas.graph_event_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
         self.app.mr = self.canvas.graph_event_connect('mouse_release', self.app.on_mouse_click_release_over_plot)