Quellcode durchsuchen

- Tool Drilling - brushing through code and solved the report on estimation of execution time
- Tool Drilling - more optimizations regarding of using Toolchange as opposed to not using it
- modfied the preprocessors to work with the new properties for Excellon objects
- added to preprocessors information regarding the X,Y position at the end of the job
- Tool Drilling made sure that on Toolchange event after toolchange event the tool feedrate is set

Marius Stanciu vor 5 Jahren
Ursprung
Commit
5b80760ba7

+ 5 - 0
CHANGELOG.md

@@ -12,6 +12,11 @@ CHANGELOG for FlatCAM beta
 - added icons to some of the push buttons
 - Tool Drilling - automatically switch to the Selected Tab after job finished
 - added Editor Push buttons in Geometry and CNCJob UI's
+- Tool Drilling - brushing through code and solved the report on estimation of execution time
+- Tool Drilling - more optimizations regarding of using Toolchange as opposed to not using it
+- modfied the preprocessors to work with the new properties for Excellon objects
+- added to preprocessors information regarding the X,Y position at the end of the job
+- Tool Drilling made sure that on Toolchange event after toolchange event the tool feedrate is set
 
 14.07.2020
 

+ 7 - 1
appDatabase.py

@@ -1804,7 +1804,6 @@ class ToolsDB2UI:
         self.grid4.addWidget(self.iso_type_label, 8, 0)
         self.grid4.addWidget(self.iso_type_radio, 8, 1)
 
-
         # ###########################################################################
         # ################ DRILLING UI form #########################################
         # ###########################################################################
@@ -2552,6 +2551,7 @@ class ToolsDB2(QtWidgets.QWidget):
                 self.ui.iso_box.show()
                 self.ui.drill_box.show()
             else:
+                self.ui.milling_box.hide()
                 self.ui.ncc_box.hide()
                 self.ui.paint_box.hide()
                 self.ui.iso_box.hide()
@@ -2568,14 +2568,20 @@ class ToolsDB2(QtWidgets.QWidget):
                 if tool_target == _("Isolation"):
                     self.ui.iso_box.setEnabled(True)
                     self.ui.iso_box.show()
+                    self.ui.milling_box.setEnabled(True)
+                    self.ui.milling_box.show()
 
                 if tool_target == _("Paint"):
                     self.ui.paint_box.setEnabled(True)
                     self.ui.paint_box.show()
+                    self.ui.milling_box.setEnabled(True)
+                    self.ui.milling_box.show()
 
                 if tool_target == _("NCC"):
                     self.ui.ncc_box.setEnabled(True)
                     self.ui.ncc_box.show()
+                    self.ui.milling_box.setEnabled(True)
+                    self.ui.milling_box.show()
 
     def on_tool_add(self):
         """

+ 3 - 89
appObjects/FlatCAMCNCJob.py

@@ -765,95 +765,9 @@ class CNCJobObject(FlatCAMObj, CNCjob):
         # if this dict is not empty then the object is an Excellon object
         if self.exc_cnc_tools:
             first_key = next(iter(self.exc_cnc_tools))
-            include_header = self.app.preprocessors[self.exc_cnc_tools[first_key]['data']['ppname_e']].include_header
-
-        # # detect if using Roland preprocessor
-        # try:
-        #     for key in self.cnc_tools:
-        #         if self.cnc_tools[key]['data']['ppname_g'] == 'Roland_MDX_20':
-        #             roland = True
-        #             break
-        # except Exception:
-        #     try:
-        #         for key in self.cnc_tools:
-        #             if self.cnc_tools[key]['data']['ppname_e'] == 'Roland_MDX_20':
-        #                 roland = True
-        #                 break
-        #     except Exception:
-        #         pass
-        #
-        # # detect if using HPGL preprocessor
-        # try:
-        #     for key in self.cnc_tools:
-        #         if self.cnc_tools[key]['data']['ppname_g'] == 'hpgl':
-        #             hpgl = True
-        #             break
-        # except Exception:
-        #     try:
-        #         for key in self.cnc_tools:
-        #             if self.cnc_tools[key]['data']['ppname_e'] == 'hpgl':
-        #                 hpgl = True
-        #                 break
-        #     except Exception:
-        #         pass
-        #
-        # # detect if using ISEL_ICP_CNC preprocessor
-        # try:
-        #     for key in self.cnc_tools:
-        #         if 'ISEL_ICP' in self.cnc_tools[key]['data']['ppname_g'].upper():
-        #             isel_icp = True
-        #             break
-        # except Exception:
-        #     try:
-        #         for key in self.cnc_tools:
-        #             if 'ISEL_ICP' in self.cnc_tools[key]['data']['ppname_e'].upper():
-        #                 isel_icp = True
-        #                 break
-        #     except Exception:
-        #         pass
-
-        # do not add gcode_header when using the Roland preprocessor, add it for every other preprocessor
-        # if roland is False and hpgl is False and isel_icp is False:
-        #     gcode = self.gcode_header()
-
-        # do not add gcode_header when using the Roland, HPGL or ISEP_ICP_CNC preprocessor (or any other preprocessor
-        # that has the include_header attribute set as False, add it for every other preprocessor
-        # if include_header:
-        #     gcode = self.gcode_header()
-        # else:
-        #     gcode = ''
-
-        # # detect if using multi-tool and make the Gcode summation correctly for each case
-        # if self.multitool is True:
-        #     for tooluid_key in self.cnc_tools:
-        #         for key, value in self.cnc_tools[tooluid_key].items():
-        #             if key == 'gcode':
-        #                 gcode += value
-        #                 break
-        # else:
-        #     gcode += self.gcode
-
-        # if roland is True:
-        #     g = preamble + gcode + postamble
-        # elif hpgl is True:
-        #     g = self.gcode_header() + preamble + gcode + postamble
-        # else:
-        #     # fix so the preamble gets inserted in between the comments header and the actual start of GCODE
-        #     g_idx = gcode.rfind('G20')
-        #
-        #     # if it did not find 'G20' then search for 'G21'
-        #     if g_idx == -1:
-        #         g_idx = gcode.rfind('G21')
-        #
-        #     # if it did not find 'G20' and it did not find 'G21' then there is an error and return
-        #     # but only when the preprocessor is not ISEL_ICP who is allowed not to have the G20/G21 command
-        #     if g_idx == -1 and isel_icp is False:
-        #         self.app.inform.emit('[ERROR_NOTCL] %s' % _("G-code does not have a units code: either G20 or G21"))
-        #         return
-        #
-        #     footer = self.app.defaults['cncjob_footer']
-        #     end_gcode = self.gcode_footer() if footer is True else ''
-        #     g = gcode[:g_idx] + preamble + '\n' + gcode[g_idx:] + postamble + end_gcode
+            include_header = self.app.preprocessors[
+                self.exc_cnc_tools[first_key]['data']['tools_drill_ppname_e']
+            ].include_header
 
         gcode = ''
         if include_header is False:

+ 103 - 82
appTools/ToolDrilling.py

@@ -20,6 +20,7 @@ from shapely.geometry import LineString
 
 import json
 import sys
+import re
 
 from matplotlib.backend_bases import KeyEvent as mpl_key_event
 
@@ -1425,6 +1426,10 @@ class ToolDrilling(AppTool, Excellon):
                             points[tool_key] = [drill_pt]
         log.debug("Found %d TOOLS with drills." % len(points))
 
+        # #############################################################################################################
+        # ############ SLOTS TO DRILLS CONVERSION SECTION #############################################################
+        # #############################################################################################################
+
         # convert slots to a sequence of drills and add them to drill points
         should_add_last_pt = self.t_ui.last_drill_cb.get_value()
 
@@ -1528,12 +1533,10 @@ class ToolDrilling(AppTool, Excellon):
         sel_tools = [i for i, j in sorted_tools for k in selected_tools_id if i == k]
 
         log.debug("Tools sorted are: %s" % str(sel_tools))
-        # #############################################################################################################
-        # #############################################################################################################
 
         # #############################################################################################################
         # #############################################################################################################
-        # Points (Group by tool): a dictionary of shapely Point geo elements grouped by tool number
+        # #### Create Points (Group by tool): a dictionary of shapely Point geo elements grouped by tool number #######
         # #############################################################################################################
         # #############################################################################################################
         self.app.inform.emit(_("Creating a list of points to drill..."))
@@ -1590,14 +1593,18 @@ class ToolDrilling(AppTool, Excellon):
                     if to_ol == it[0]:
                         sol_geo = []
 
+                        # solid geometry addition; we look into points because we may have slots converted to drills
+                        # therefore more drills than there were originally in
+                        # the self.excellon_tools[to_ol]['drills'] list
                         drill_no = 0
-                        if 'drills' in self.excellon_tools[to_ol]:
-                            drill_no = len(self.excellon_tools[to_ol]['drills'])
-                            for drill in self.excellon_tools[to_ol]['drills']:
+                        if to_ol in points and points[to_ol]:
+                            drill_no = len(points[to_ol])
+                            for drill in points[to_ol]:
                                 sol_geo.append(drill.buffer((it[1] / 2.0), resolution=job_obj.geo_steps_per_circle))
 
                         slot_no = 0
-                        if 'slots' in self.excellon_tools[to_ol]:
+                        convert_slots = self.excellon_tools[to_ol]['data']['tools_drill_drill_slots']
+                        if 'slots' in self.excellon_tools[to_ol] and convert_slots is False:
                             slot_no = len(self.excellon_tools[to_ol]['slots'])
                             for eslot in self.excellon_tools[to_ol]['slots']:
                                 start = (eslot[0].x, eslot[0].y)
@@ -1607,15 +1614,18 @@ class ToolDrilling(AppTool, Excellon):
                                                                      resolution=job_obj.geo_steps_per_circle)
                                 )
 
+                        # adjust Offset for current tool
                         try:
                             z_off = float(self.excellon_tools[it[0]]['data']['offset']) * (-1)
                         except KeyError:
                             z_off = 0
 
+                        # default tool data
                         default_data = {}
                         for kk, vv in list(obj.options.items()):
                             default_data[kk] = deepcopy(vv)
 
+                        # populate the Excellon CNC tools storage
                         job_obj.exc_cnc_tools[it[1]] = {}
                         job_obj.exc_cnc_tools[it[1]]['tool'] = it[0]
                         job_obj.exc_cnc_tools[it[1]]['nr_drills'] = drill_no
@@ -1658,67 +1668,37 @@ class ToolDrilling(AppTool, Excellon):
             job_obj.options['ymax'] = ymax
 
             job_obj.origin_kind = 'excellon'
+            job_obj.use_ui = True
             job_obj.toolchange_xy_type = "excellon"
             job_obj.coords_decimals = int(self.app.defaults["cncjob_coords_decimals"])
             job_obj.fr_decimals = int(self.app.defaults["cncjob_fr_decimals"])
             job_obj.multitool = True
 
             # first drill point
-            job_obj.xy_toolchange = self.app.defaults["excellon_toolchangexy"]
-            if job_obj.xy_toolchange is not None:
-                job_obj.oldx = job_obj.xy_toolchange[0]
-                job_obj.oldy = job_obj.xy_toolchange[1]
-            else:
-                job_obj.oldx = 0.0
-                job_obj.oldy = 0.0
+            job_obj.xy_toolchange = self.app.defaults["tools_drill_toolchangexy"]
+            x_tc, y_tc = [0, 0]
+            try:
+                if job_obj.xy_toolchange != '':
+                    tcxy_temp = re.sub('[()\[\]]', '', str(job_obj.xy_toolchange))
+                    if tcxy_temp:
+                        x_tc, y_tc = [float(eval(a)) for a in tcxy_temp.split(",")]
+            except Exception:
+                x_tc, y_tc = [0, 0]
+                self.app.inform.emit('[ERROR]%s' % _("The Toolchange X,Y format has to be (x, y)."))
+
+            job_obj.oldx = x_tc
+            job_obj.oldy = y_tc
             first_drill_point = (job_obj.oldx, job_obj.oldy)
 
-            # ####################### TOOLCHANGE ######################################################
-            if toolchange is True:
-                for tool in sel_tools:
-                    tool_points = points[tool]
-                    used_tooldia = self.excellon_tools[tool]['tooldia']
-
-                    convert_slots = self.excellon_tools[tool]['data']['tools_drill_drill_slots']
-                    if convert_slots is True:
-                        nr_drills = len(points[tool])
-                        nr_slots = 0
-                        job_obj.exc_cnc_tools[used_tooldia]['nr_drills'] = nr_drills
-                        job_obj.exc_cnc_tools[used_tooldia]['nr_slots'] = nr_slots
-
-                        for line in range(1, len(job_obj.options['Tools_in_use'])):
-                            if self.dec_format(float(job_obj.options['Tools_in_use'][line][1])) == \
-                                    self.dec_format(used_tooldia):
-                                job_obj.options['Tools_in_use'][line][2] = str(nr_drills)
-                                job_obj.options['Tools_in_use'][line][3] = str(nr_slots)
-
-                    is_last_tool = True if tool == sel_tools[-1] else False
-                    is_first_tool = True if tool == sel_tools[0] else False
-                    tool_gcode, last_pt = 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_parsed = job_obj.excellon_tool_gcode_parse(used_tooldia, gcode=tool_gcode,
-                                                                          start_pt=first_drill_point)
-                    first_drill_point = last_pt
-
-                    # store the results
-                    job_obj.exc_cnc_tools[used_tooldia]['gcode'] = tool_gcode
-                    job_obj.exc_cnc_tools[used_tooldia]['gcode_parsed'] = tool_gcode_parsed
-
-                    self.total_gcode += tool_gcode
-                    self.total_gcode_parsed += tool_gcode_parsed
-
-            # ####################### NO TOOLCHANGE ######################################################
-            else:
-
+            # #########################################################################################################
+            # ####################### NO TOOLCHANGE ###################################################################
+            # #########################################################################################################
+            if toolchange is False:
                 tool_points = []
                 for tool in sel_tools:
                     tool_points += points[tool]
 
+                # use the first tool in the selection as the tool that we are going to use
                 used_tool = sel_tools[0]
                 used_tooldia = self.excellon_tools[used_tool]['tooldia']
 
@@ -1730,37 +1710,20 @@ class ToolDrilling(AppTool, Excellon):
                 # process all in one go with no toolchange and with only one tool
                 nr_drills = 0
                 nr_slots = 0
+                total_solid_geo = []
 
-                convert_slots = self.excellon_tools[used_tool]['data']['tools_drill_drill_slots']
-                if convert_slots is False:
-                    for line in range(1, len(tool_table_items)):
-                        # we may have exception ValueError if there are no drills/slots for the current tool/line
-                        try:
-                            nr_drills += int(tool_table_items[line][2])
-                        except ValueError:
-                            pass
-                        try:
-                            nr_slots += int(tool_table_items[line][3])
-                        except ValueError:
-                            pass
-                else:
-                    # if the slots are converted to drills then make slots number = 0 and count the converted drills
-                    for t in points:
-                        nr_drills += len(points[t])
-
-                    nr_slots = 0
-                    job_obj.exc_cnc_tools[used_tooldia]['nr_drills'] = nr_drills
-                    job_obj.exc_cnc_tools[used_tooldia]['nr_slots'] = nr_slots
+                # calculate the total number of drills and of slots
+                for e_tool_dia in job_obj.exc_cnc_tools:
+                    nr_drills += int(job_obj.exc_cnc_tools[e_tool_dia]['nr_drills'])
+                    nr_slots += int(job_obj.exc_cnc_tools[e_tool_dia]['nr_slots'])
+                    total_solid_geo += job_obj.exc_cnc_tools[e_tool_dia]['solid_geometry']
 
                 tool_table_items.clear()
                 tool_table_items = [[str(used_tool), str(used_tooldia), str(nr_drills), str(nr_slots)]]
                 tool_table_items.insert(0, [_("Tool_nr"), _("Diameter"), _("Drills_Nr"), _("Slots_Nr")])
                 job_obj.options['Tools_in_use'] = tool_table_items
 
-                # tool_gcode = start_gcode
-                # TODO set the oldx and oldy to start values
-                # add a Toolchange event here to load the first tool
-                # tool_gcode += job_obj.doformat(p.toolchange_code, toolchangexy=(job_obj.oldx, job_obj.oldy))
+                # generate GCode
                 tool_gcode, __ = job_obj.excellon_tool_gcode_gen(used_tool, tool_points, self.excellon_tools,
                                                                  first_pt=first_drill_point,
                                                                  is_first=True,
@@ -1768,20 +1731,78 @@ class ToolDrilling(AppTool, Excellon):
                                                                  opt_type=used_excellon_optimization_type,
                                                                  toolchange=True)
 
+                # parse the Gcode
                 tool_gcode_parsed = job_obj.excellon_tool_gcode_parse(used_tooldia, gcode=tool_gcode,
                                                                       start_pt=first_drill_point)
-                # store the results
+
+                # store the results in Excellon CNC tools storage
+                job_obj.exc_cnc_tools[used_tooldia]['nr_drills'] = nr_drills
+                job_obj.exc_cnc_tools[used_tooldia]['nr_slots'] = nr_slots
                 job_obj.exc_cnc_tools[used_tooldia]['gcode'] = tool_gcode
                 job_obj.exc_cnc_tools[used_tooldia]['gcode_parsed'] = tool_gcode_parsed
+                job_obj.exc_cnc_tools[used_tooldia]['solid_geometry'] = total_solid_geo
+
+                # delete all tools from the Excellon CNC tools storage except the used one
+                for e_tool_dia in list(job_obj.exc_cnc_tools.keys()):
+                    if e_tool_dia != used_tooldia:
+                        job_obj.exc_cnc_tools.pop(e_tool_dia, None)
 
                 self.total_gcode = tool_gcode
                 self.total_gcode_parsed = tool_gcode_parsed
 
+            # ####################### TOOLCHANGE ACTIVE ######################################################
+            else:
+                for tool in sel_tools:
+                    tool_points = points[tool]
+                    used_tooldia = self.excellon_tools[tool]['tooldia']
+
+                    # if slots are converted to drill for this tool, update the number of drills and make slots nr zero
+                    convert_slots = self.excellon_tools[tool]['data']['tools_drill_drill_slots']
+                    if convert_slots is True:
+                        nr_drills = len(points[tool])
+                        nr_slots = 0
+                        job_obj.exc_cnc_tools[used_tooldia]['nr_drills'] = nr_drills
+                        job_obj.exc_cnc_tools[used_tooldia]['nr_slots'] = nr_slots
+
+                        for line in range(1, len(job_obj.options['Tools_in_use'])):
+                            if self.dec_format(float(job_obj.options['Tools_in_use'][line][1])) == \
+                                    self.dec_format(used_tooldia):
+                                job_obj.options['Tools_in_use'][line][2] = str(nr_drills)
+                                job_obj.options['Tools_in_use'][line][3] = str(nr_slots)
+
+                    # calculate if the current tool is the first one or if it is the last one
+                    # for the first tool we add some extra GCode (start Gcode, header etc)
+                    # for the last tool we add other GCode (the end code, what is happening at the end of the job)
+                    is_last_tool = True if tool == sel_tools[-1] else False
+                    is_first_tool = True if tool == sel_tools[0] else False
+
+                    # Generate Gcode for the current tool
+                    tool_gcode, last_pt = 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)
+
+                    # parse Gcode for the current tool
+                    tool_gcode_parsed = job_obj.excellon_tool_gcode_parse(used_tooldia, gcode=tool_gcode,
+                                                                          start_pt=first_drill_point)
+                    first_drill_point = last_pt
+
+                    # store the results of GCode generation and parsing
+                    job_obj.exc_cnc_tools[used_tooldia]['gcode'] = tool_gcode
+                    job_obj.exc_cnc_tools[used_tooldia]['gcode_parsed'] = tool_gcode_parsed
+
+                    self.total_gcode += tool_gcode
+                    self.total_gcode_parsed += tool_gcode_parsed
+
             job_obj.gcode = self.total_gcode
             job_obj.gcode_parsed = self.total_gcode_parsed
             if job_obj.gcode == 'fail':
                 return 'fail'
 
+            # create Geometry for plotting
+            # 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':
@@ -1816,7 +1837,7 @@ class ToolDrilling(AppTool, Excellon):
             # for G0 move (the fastest speed available to the CNC router). Although self.feedrate_rapids is used only
             # with Marlin preprocessor and derivatives.
             job_obj.routing_time = \
-                (job_obj.measured_down_distance + job_obj.measured_up_to_zero_distance) / job_obj.feedrate
+                (job_obj.measured_down_distance + job_obj.measured_up_to_zero_distance) / job_obj.z_feedrate
             lift_time = job_obj.measured_lift_distance / job_obj.feedrate_rapid
             traveled_time = job_obj.measured_distance / job_obj.feedrate_rapid
             job_obj.routing_time += lift_time + traveled_time

+ 66 - 66
camlib.py

@@ -2499,6 +2499,8 @@ class CNCjob(Geometry):
         self.units = units
 
         self.z_cut = z_cut
+        self.multidepth = False
+        self.z_depthpercut = depthpercut
         self.z_move = z_move
 
         self.feedrate = feedrate
@@ -2506,20 +2508,16 @@ class CNCjob(Geometry):
         self.feedrate_rapid = feedrate_rapid
 
         self.tooldia = tooldia
+        self.toolC = tooldia
         self.toolchange = False
         self.z_toolchange = toolchangez
         self.xy_toolchange = toolchange_xy
         self.toolchange_xy_type = None
 
-        self.toolC = tooldia
-
         self.startz = None
         self.z_end = endz
         self.xy_end = endxy
 
-        self.multidepth = False
-        self.z_depthpercut = depthpercut
-
         self.extracut_length = None
 
         # used by the self.generate_from_excellon_by_tool() method
@@ -2901,8 +2899,6 @@ class CNCjob(Geometry):
 
         self.exc_tools = deepcopy(tools)
         t_gcode = ''
-        p = self.pp_excellon
-        self.toolchange = toolchange
 
         # holds the temporary coordinates of the processed drill point
         locx, locy = first_pt
@@ -2934,15 +2930,12 @@ class CNCjob(Geometry):
 
         # #########################################################################################################
         # #########################################################################################################
-        # ############# PARAMETERS ################################################################################
+        # ############# PARAMETERS used in PREPROCESSORS so they need to be updated ###############################
         # #########################################################################################################
         # #########################################################################################################
         self.tool = str(tool)
-        self.tooldia = tools[tool]["tooldia"]
-        self.postdata['toolC'] = tools[tool]["tooldia"]
-
-        self.z_feedrate = tool_dict['tools_drill_feedrate_z']
-        self.feedrate = tool_dict['tools_drill_feedrate_z']
+        # Preprocessor
+        p = self.pp_excellon
 
         # Z_cut parameter
         if self.machinist_setting == 0:
@@ -2950,49 +2943,81 @@ class CNCjob(Geometry):
             if self.z_cut == 'fail':
                 return 'fail'
 
+        # Depth parameters
         self.z_cut = tool_dict['tools_drill_cutz']
-        # multidepth use this
-        old_zcut = tool_dict["tools_drill_cutz"]
-
+        old_zcut = deepcopy(tool_dict["tools_drill_cutz"])  # multidepth use this
+        self.multidepth = tool_dict['tools_drill_multidepth']
+        self.z_depthpercut = tool_dict['tools_drill_depthperpass']
         self.z_move = tool_dict['tools_drill_travelz']
+        self.f_plunge = tool_dict["tools_drill_f_plunge"]   # used directly in the preprocessor Toolchange method
+        self.f_retract = tool_dict["tools_drill_f_retract"] # used in the current method
+
+        # Feedrate parameters
+        self.z_feedrate = tool_dict['tools_drill_feedrate_z']
+        self.feedrate = tool_dict['tools_drill_feedrate_z']
+        self.feedrate_rapid = tool_dict['tools_drill_feedrate_rapid']
+
+        # Spindle parameters
         self.spindlespeed = tool_dict['tools_drill_spindlespeed']
         self.dwell = tool_dict['tools_drill_dwell']
         self.dwelltime = tool_dict['tools_drill_dwelltime']
-        self.multidepth = tool_dict['tools_drill_multidepth']
-        self.z_depthpercut = tool_dict['tools_drill_depthperpass']
+        self.spindledir = tool_dict['tools_drill_spindledir']
 
+        self.tooldia = tools[tool]["tooldia"]
+        self.postdata['toolC'] = tools[tool]["tooldia"]
+        self.toolchange = toolchange
+
+        # Z_toolchange parameter
+        self.z_toolchange = tool_dict['tools_drill_toolchangez']
         # XY_toolchange parameter
         self.xy_toolchange = tool_dict["tools_drill_toolchangexy"]
         try:
             if self.xy_toolchange == '':
                 self.xy_toolchange = None
             else:
+                # either originally it was a string or not, xy_toolchange will be made string
                 self.xy_toolchange = re.sub('[()\[\]]', '', str(self.xy_toolchange)) if self.xy_toolchange else None
 
+                # and now, xy_toolchange is made into a list of floats in format [x, y]
                 if self.xy_toolchange:
                     self.xy_toolchange = [
                         float(eval(a)) for a in self.xy_toolchange.split(",")
                     ]
 
                 if self.xy_toolchange and len(self.xy_toolchange) != 2:
-                    self.app.inform.emit('[ERROR]%s' %
-                                         _("The Toolchange X,Y field in Edit -> Preferences has to be "
-                                           "in the format (x, y) \nbut now there is only one value, not two. "))
+                    self.app.inform.emit('[ERROR]%s' % _("The Toolchange X,Y format has to be (x, y)."))
                     return 'fail'
         except Exception as e:
-            log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> %s" % str(e))
-            pass
-
-        # XY_end parameter
+            log.debug("camlib.CNCJob.generate_from_excellon_by_tool() xy_toolchange --> %s" % str(e))
+            self.xy_toolchange = [0, 0]
+
+        # End position parameters
+        self.startz = tool_dict["tools_drill_startz"]
+        if self.startz == '':
+            self.startz = None
+        self.z_end = tool_dict["tools_drill_endz"]
         self.xy_end = tool_dict["tools_drill_endxy"]
-        self.xy_end = re.sub('[()\[\]]', '', str(self.xy_end)) if self.xy_end else None
-        if self.xy_end and self.xy_end != '':
-            self.xy_end = [float(eval(a)) for a in self.xy_end.split(",")]
-        if self.xy_end and len(self.xy_end) < 2:
-            self.app.inform.emit(
-                '[ERROR]  %s' % _("The End Move X,Y field in Edit -> Preferences has to be "
-                                  "in the format (x, y) but now there is only one value, not two."))
-            return 'fail'
+        try:
+            if self.xy_end == '':
+                self.xy_end = None
+            else:
+                # either originally it was a string or not, xy_end will be made string
+                self.xy_end = re.sub('[()\[\]]', '', str(self.xy_end)) if self.xy_end else None
+
+                # and now, xy_end is made into a list of floats in format [x, y]
+                if self.xy_end:
+                    self.xy_end = [float(eval(a)) for a in self.xy_end.split(",")]
+
+                if self.xy_end and len(self.xy_end) != 2:
+                    self.app.inform.emit('[ERROR]%s' % _("The End X,Y format has to be (x, y)."))
+                    return 'fail'
+        except Exception as e:
+            log.debug("camlib.CNCJob.generate_from_excellon_by_tool() xy_end --> %s" % str(e))
+            self.xy_end = [0, 0]
+
+        # Probe parameters
+        self.z_pdepth = tool_dict["tools_drill_z_pdepth"]
+        self.feedrate_probe = tool_dict["tools_drill_feedrate_probe"]
         # #########################################################################################################
         # #########################################################################################################
 
@@ -3034,6 +3059,7 @@ class CNCjob(Geometry):
 
         # Only if there are locations to drill
         if not optimized_path:
+            log.debug("CNCJob.excellon_tool_gcode_gen() -> Optimized path is empty.")
             return 'fail'
 
         if self.app.abort_flag:
@@ -3044,21 +3070,10 @@ class CNCjob(Geometry):
         if is_first:
             t_gcode += start_gcode
 
-        t_gcode += self.doformat(p.z_feedrate_code)
-
-        # Tool change sequence (optional)
-        # if toolchange:
-        #     t_gcode += self.doformat(p.toolchange_code, toolchangexy=(temp_locx, temp_locy))
-        # else:
-        #     if self.xy_toolchange is not None and isinstance(self.xy_toolchange, (tuple, list)):
-        #         t_gcode += self.doformat(p.lift_code, x=self.xy_toolchange[0], y=self.xy_toolchange[1])
-        #         t_gcode += self.doformat(p.startz_code, x=self.xy_toolchange[0], y=self.xy_toolchange[1])
-        #     else:
-        #         t_gcode += self.doformat(p.lift_code, x=0.0, y=0.0)
-        #         t_gcode += self.doformat(p.startz_code, x=0.0, y=0.0)
-
         # 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)
 
         # Spindle start
         t_gcode += self.doformat(p.spindle_code)
@@ -3067,7 +3082,6 @@ class CNCjob(Geometry):
             t_gcode += self.doformat(p.dwell_code)
 
         current_tooldia = float('%.*f' % (self.decimals, float(tools[tool]["tooldia"])))
-
         self.app.inform.emit(
             '%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
                            str(current_tooldia),
@@ -3151,8 +3165,10 @@ class CNCjob(Geometry):
                         self.z_cut -= self.z_depthpercut
                         if abs(doc) < abs(self.z_cut) < (abs(doc) + self.z_depthpercut):
                             self.z_cut = doc
+                        # Move down the drill bit
                         t_gcode += self.doformat(p.down_code, x=locx, y=locy)
 
+                        # Update the distance travelled down with the current one
                         self.measured_down_distance += abs(self.z_cut) + abs(self.z_move)
 
                         if self.f_retract is False:
@@ -3402,10 +3418,6 @@ class CNCjob(Geometry):
 
         # this holds the resulting GCode
         self.gcode = []
-
-        self.f_plunge = self.app.defaults["tools_drill_f_plunge"]
-        self.f_retract = self.app.defaults["tools_drill_f_retract"]
-
         # #############################################################################################################
         # #############################################################################################################
         # Initialization
@@ -5995,16 +6007,8 @@ class CNCjob(Geometry):
                 current['G'] = int(gobj['G'])
 
             if 'X' in gobj or 'Y' in gobj:
-                if 'X' in gobj:
-                    x = gobj['X']
-                    # current['X'] = x
-                else:
-                    x = current['X']
-
-                if 'Y' in gobj:
-                    y = gobj['Y']
-                else:
-                    y = current['Y']
+                x = gobj['X'] if 'X' in gobj else current['X']
+                y = gobj['Y'] if 'Y' in gobj else current['Y']
 
                 kind = ["C", "F"]  # T=travel, C=cut, F=fast, S=slow
 
@@ -6012,7 +6016,6 @@ class CNCjob(Geometry):
                     kind[0] = 'T'
                 if current['G'] > 0:
                     kind[1] = 'S'
-
                 if current['G'] in [0, 1]:  # line
                     path.append((x, y))
 
@@ -6032,9 +6035,7 @@ class CNCjob(Geometry):
                 current[code] = gobj[code]
 
         self.app.inform.emit('%s: %s' % (_("Creating Geometry from the parsed GCode file for tool diameter"), str(dia)))
-        # There might not be a change in height at the
-        # end, therefore, see here too if there is
-        # a final path.
+        # There might not be a change in height at the end, therefore, see here too if there is a final path.
         if len(path) > 1:
             geometry.append(
                 {
@@ -6042,7 +6043,6 @@ class CNCjob(Geometry):
                     "kind": kind
                 }
             )
-
         return geometry
 
     # def plot(self, tooldia=None, dpi=75, margin=0.1,

+ 15 - 6
preprocessors/Berta_CNC.py

@@ -22,6 +22,7 @@ class Berta_CNC(PreProc):
     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 with a BERTA CNC router.)\n\n'
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -52,30 +53,32 @@ class Berta_CNC(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -89,6 +92,12 @@ class Berta_CNC(PreProc):
 
         gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
         gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
+        if 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'
         gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
 
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':

+ 15 - 6
preprocessors/ISEL_CNC.py

@@ -17,6 +17,7 @@ class ISEL_CNC(PreProc):
     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 with a ISEL CNC router.)\n\n'
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -42,30 +43,32 @@ class ISEL_CNC(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -79,6 +82,12 @@ class ISEL_CNC(PreProc):
 
         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'
         gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
 
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':

+ 15 - 6
preprocessors/ISEL_ICP_CNC.py

@@ -15,6 +15,7 @@ class ISEL_ICP_CNC(PreProc):
     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 with a ISEL ICP CNC router.\n\n'
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -42,30 +43,32 @@ class ISEL_ICP_CNC(PreProc):
 
             gcode += '\n;FEEDRATE Z: \n'
             for tool, val in p['exc_tools'].items():
-                gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
+                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']["feedrate_rapid"]) + '\n'
+                         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']["cutz"]) + '\n'
+                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['offset_z']) + '\n'
+                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']["depthperpass"]) + '\n'
+                             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']["travelz"]) + '\n'
+                gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + '\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -79,6 +82,12 @@ class ISEL_ICP_CNC(PreProc):
 
         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'
         gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
 
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':

+ 15 - 6
preprocessors/Marlin.py

@@ -19,6 +19,7 @@ class Marlin(PreProc):
     def start_code(self, p):
         units = ' ' + str(p['units']).lower()
         coords_xy = p['xy_toolchange']
+        end_coords_xy = p['xy_end']
         gcode = ''
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -44,30 +45,32 @@ class Marlin(PreProc):
 
             gcode += '\n;FEEDRATE Z: \n'
             for tool, val in p['exc_tools'].items():
-                gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
+                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']["feedrate_rapid"]) + '\n'
+                         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']["cutz"]) + '\n'
+                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['offset_z']) + '\n'
+                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']["depthperpass"]) + '\n'
+                             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']["travelz"]) + '\n'
+                gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + '\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -81,6 +84,12 @@ class Marlin(PreProc):
 
         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'
         gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
 
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':

+ 8 - 1
preprocessors/Marlin_laser_FAN_pin.py

@@ -19,6 +19,7 @@ class Marlin_laser_FAN_pin(PreProc):
     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 with a motion controller loaded with MARLIN firmware.\n'
         gcode += ';It is for the case when it is used together with a LASER connected on one of the FAN pins.\n\n'
 
@@ -37,7 +38,13 @@ class Marlin_laser_FAN_pin(PreProc):
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
             gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
         else:
-            gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
+            gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\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'
 
         gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
         gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'

+ 7 - 1
preprocessors/Marlin_laser_Spindle_pin.py

@@ -19,6 +19,7 @@ class Marlin_laser_Spindle_pin(PreProc):
     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 with a motion controller loaded with MARLIN firmware.\n'
         gcode += ';It is for the case when it is used together with a LASER connected on the SPINDLE connector.\n\n'
 
@@ -37,7 +38,12 @@ class Marlin_laser_Spindle_pin(PreProc):
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
             gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
         else:
-            gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
+            gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\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\n'
 
         gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
         gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'

+ 14 - 6
preprocessors/Repetier.py

@@ -19,6 +19,7 @@ class Repetier(PreProc):
     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 with a motion controller loaded with REPETIER firmware.\n\n'
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -44,30 +45,32 @@ class Repetier(PreProc):
 
             gcode += '\n;FEEDRATE Z: \n'
             for tool, val in p['exc_tools'].items():
-                gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
+                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']["feedrate_rapid"]) + '\n'
+                         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']["cutz"]) + '\n'
+                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['offset_z']) + '\n'
+                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']["depthperpass"]) + '\n'
+                             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']["travelz"]) + '\n'
+                gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + '\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -81,6 +84,11 @@ class Repetier(PreProc):
 
         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':

+ 14 - 6
preprocessors/Toolchange_Custom.py

@@ -18,6 +18,7 @@ class Toolchange_Custom(PreProc):
     def start_code(self, p):
         units = ' ' + str(p['units']).lower()
         coords_xy = p['xy_toolchange']
+        end_coords_xy = p['xy_end']
         gcode = ''
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -43,30 +44,32 @@ class Toolchange_Custom(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -80,6 +83,11 @@ class Toolchange_Custom(PreProc):
 
         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':

+ 14 - 6
preprocessors/Toolchange_Manual.py

@@ -18,6 +18,7 @@ class Toolchange_Manual(PreProc):
     def start_code(self, p):
         units = ' ' + str(p['units']).lower()
         coords_xy = p['xy_toolchange']
+        end_coords_xy = p['xy_end']
         gcode = ''
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -43,30 +44,32 @@ class Toolchange_Manual(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -80,6 +83,11 @@ class Toolchange_Manual(PreProc):
 
         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':

+ 14 - 6
preprocessors/Toolchange_Probe_MACH3.py

@@ -18,6 +18,7 @@ class Toolchange_Probe_MACH3(PreProc):
     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 with MACH3 with probing height.)\n\n'
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -43,30 +44,32 @@ class Toolchange_Probe_MACH3(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -80,6 +83,11 @@ class Toolchange_Probe_MACH3(PreProc):
 
         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':

+ 14 - 6
preprocessors/default.py

@@ -18,6 +18,7 @@ class default(PreProc):
     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 the default preprocessor used by FlatCAM.)\n'
         gcode += '(It is made to work with MACH3 compatible motion controllers.)\n\n'
 
@@ -44,30 +45,32 @@ class default(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -81,6 +84,11 @@ class default(PreProc):
 
         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':

+ 15 - 6
preprocessors/grbl_11.py

@@ -18,6 +18,7 @@ class grbl_11(PreProc):
     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 with a motion controller loaded with GRBL firmware.)\n'
         gcode += '(It is configured to be compatible with almost any version of GRBL firmware.)\n\n'
 
@@ -44,30 +45,32 @@ class grbl_11(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -81,6 +84,12 @@ class grbl_11(PreProc):
 
         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'
         gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
 
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':

+ 15 - 6
preprocessors/line_xyz.py

@@ -18,6 +18,7 @@ class line_xyz(PreProc):
     def start_code(self, p):
         units = ' ' + str(p['units']).lower()
         coords_xy = p['xy_toolchange']
+        end_coords_xy = p['end_xy']
         gcode = ''
 
         xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
@@ -43,30 +44,32 @@ class line_xyz(PreProc):
 
             gcode += '\n(FEEDRATE Z: )\n'
             for tool, val in p['exc_tools'].items():
-                gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+                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']["feedrate_rapid"]) + ')\n'
+                         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']["cutz"]) + ')\n'
+                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['offset_z']) + ')\n'
+                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']["depthperpass"]) + ')\n'
+                             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']["travelz"]) + ')\n'
+                gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["tools_drill_travelz"]) + ')\n'
             gcode += '\n'
 
         if p['toolchange'] is True:
@@ -80,6 +83,12 @@ class line_xyz(PreProc):
 
         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'
         gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
 
         if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':