diff --git a/src/Mod/Path/Path/Post/Command.py b/src/Mod/Path/Path/Post/Command.py index 76b50e2e57..c6a9c80f86 100644 --- a/src/Mod/Path/Path/Post/Command.py +++ b/src/Mod/Path/Path/Post/Command.py @@ -20,7 +20,7 @@ # * * # *************************************************************************** -""" Post Process command that will make use of the Output File and Post Processor entries in PathJob """ +"""Post Process command that will make use of the Output File and Post Processor entries in PathJob """ from __future__ import print_function diff --git a/src/Mod/Path/Path/Post/UtilsArguments.py b/src/Mod/Path/Path/Post/UtilsArguments.py index 8fafa7b206..b770b33384 100644 --- a/src/Mod/Path/Path/Post/UtilsArguments.py +++ b/src/Mod/Path/Path/Post/UtilsArguments.py @@ -34,8 +34,6 @@ import argparse import os import shlex -import FreeCAD - from FreeCAD import Units # to distinguish python built-in open function from the one declared below @@ -131,10 +129,7 @@ def init_shared_arguments(values, argument_defaults, arguments_visible): arguments_visible["axis-modal"], ) if arguments_visible["axis-precision"]: - help_message = ( - "Number of digits of precision for axis moves, default is " - + str(values["DEFAULT_AXIS_PRECISION"]) - ) + help_message = f'Number of digits of precision for axis moves, default is {str(values["DEFAULT_AXIS_PRECISION"])}' else: help_message = argparse.SUPPRESS shared.add_argument( @@ -162,9 +157,7 @@ def init_shared_arguments(values, argument_defaults, arguments_visible): arguments_visible["comments"], ) if arguments_visible["feed-precision"]: - help_message = "Number of digits of precision for feed rate, default is " + str( - values["DEFAULT_FEED_PRECISION"] - ) + help_message = f'Number of digits of precision for feed rate, default is {str(values["DEFAULT_FEED_PRECISION"])}' else: help_message = argparse.SUPPRESS shared.add_argument( @@ -219,35 +212,21 @@ def init_shared_arguments(values, argument_defaults, arguments_visible): arguments_visible["output_visible_arguments"], ) if arguments_visible["postamble"]: - help_message = ( - 'Set commands to be issued after the last command, default is "' - + values["POSTAMBLE"] - + '"' - ) + help_message = f'Set commands to be issued after the last command, default is "{values["POSTAMBLE"]}"' else: help_message = argparse.SUPPRESS shared.add_argument("--postamble", help=help_message) if arguments_visible["preamble"]: - help_message = ( - 'Set commands to be issued before the first command, default is "' - + values["PREAMBLE"] - + '"' - ) + help_message = f'Set commands to be issued before the first command, default is "{values["PREAMBLE"]}"' else: help_message = argparse.SUPPRESS shared.add_argument("--preamble", help=help_message) - # The --precision argument is included for backwards compatibility with - # some postprocessors. If both --axis-precision and --precision are provided, - # the --axis-precision value "wins". If both --feed-precision and --precision - # are provided, the --feed-precision value "wins". + # The --precision argument is included for backwards compatibility with some + # postprocessors. If both --axis-precision and --precision are provided, the + # --axis-precision value "wins". If both --feed-precision and --precision are + # provided, the --feed-precision value "wins". if arguments_visible["precision"]: - help_message = ( - "Number of digits of precision for both feed rate and axis moves, default is " - + str(values["DEFAULT_AXIS_PRECISION"]) - + " for metric or " - + str(values["DEFAULT_INCH_AXIS_PRECISION"]) - + " for inches" - ) + help_message = f'Number of digits of precision for both feed rate and axis moves, default is {str(values["DEFAULT_AXIS_PRECISION"])} for metric or {str(values["DEFAULT_INCH_AXIS_PRECISION"])} for inches' else: help_message = argparse.SUPPRESS shared.add_argument( @@ -314,10 +293,10 @@ def init_shared_values(values): # values["AXIS_PRECISION"] = 3 # - # How far to move up (in millimeters) in the Z axis when chipbreaking with a G73 command. + # How far to move up (in millimeters) in the Z axis when chipbreaking + # with a G73 command. # - values["CHIPBREAKING_AMOUNT"] = Units.Quantity(0.25, FreeCAD.Units.Length) - + values["CHIPBREAKING_AMOUNT"] = Units.Quantity(0.25, Units.Length) # # If this is set to "", all spaces are removed from between commands and parameters. # @@ -354,7 +333,7 @@ def init_shared_values(values): # If TRANSLATE_DRILL_CYCLES is True, these are the drill cycles # that get translated to G0 and G1 commands. # - values["DRILL_CYCLES_TO_TRANSLATE"] = ("G73", "G81", "G82", "G83") + values["DRILL_CYCLES_TO_TRANSLATE"] = ["G73", "G81", "G82", "G83"] # # The default value of drill retractations (CURRENT_Z). # The other possible value is G99. @@ -439,8 +418,8 @@ def init_shared_values(values): # values["OUTPUT_COMMENTS"] = True # - # if False duplicate axis values are suppressed if they are the same as - # the previous line. + # if False duplicate axis values are suppressed if they are the same + # as the previous line. # values["OUTPUT_DOUBLES"] = True # @@ -626,7 +605,7 @@ def process_shared_arguments(values, parser, argstring, all_visible, filename): if values["UNITS"] == "G21": values["UNIT_FORMAT"] = "mm" values["UNIT_SPEED_FORMAT"] = "mm/min" - if values["UNITS"] == "G20": + elif values["UNITS"] == "G20": values["UNIT_FORMAT"] = "in" values["UNIT_SPEED_FORMAT"] = "in/min" # The precision-related arguments need to be processed @@ -651,7 +630,7 @@ def process_shared_arguments(values, parser, argstring, all_visible, filename): else: if values["UNITS"] == "G21": values["FEED_PRECISION"] = values["DEFAULT_FEED_PRECISION"] - if values["UNITS"] == "G20": + elif values["UNITS"] == "G20": values["FEED_PRECISION"] = values["DEFAULT_INCH_FEED_PRECISION"] if args.axis_modal: values["OUTPUT_DOUBLES"] = False @@ -782,8 +761,8 @@ def process_shared_arguments(values, parser, argstring, all_visible, filename): # # G10 P D H R # -# G65 P L arguments (arguments are A-Z excluding G, L, N, O, and P) -# G65 "program.cnc" L arguments +# G65 P L args (args are A-Z excluding G, L, N, O, and P) +# G65 "program.cnc" L args # # G117, G118, G119 P X Y Z I J K P Q # diff --git a/src/Mod/Path/Path/Post/UtilsExport.py b/src/Mod/Path/Path/Post/UtilsExport.py index aa525aac18..1fad862599 100644 --- a/src/Mod/Path/Path/Post/UtilsExport.py +++ b/src/Mod/Path/Path/Post/UtilsExport.py @@ -70,19 +70,19 @@ if open.__module__ in ["__builtin__", "io"]: def export_common(values, objectslist, filename): """Do the common parts of postprocessing the objects in objectslist to filename.""" # + nl = "\n" + for obj in objectslist: if not hasattr(obj, "Path"): print( - "The object " - + obj.Name - + " is not a path. Please select only path and Compounds." + f"The object {obj.Name} is not a path. Please select only path and Compounds." ) return None # for obj in objectslist: # print(obj.Name) - print("PostProcessor: " + values["POSTPROCESSOR_FILE_NAME"] + " postprocessing...") + print(f'PostProcessor: {values["POSTPROCESSOR_FILE_NAME"]} postprocessing...') gcode = "" # write header @@ -90,24 +90,24 @@ def export_common(values, objectslist, filename): comment = PostUtilsParse.create_comment( "Exported by FreeCAD", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" comment = PostUtilsParse.create_comment( - "Post Processor: " + values["POSTPROCESSOR_FILE_NAME"], + f'Post Processor: {values["POSTPROCESSOR_FILE_NAME"]}', values["COMMENT_SYMBOL"], ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" if FreeCAD.ActiveDocument: cam_file = os.path.basename(FreeCAD.ActiveDocument.FileName) else: cam_file = "" comment = PostUtilsParse.create_comment( - "Cam File: " + cam_file, values["COMMENT_SYMBOL"] + f"Cam File: {cam_file}", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" comment = PostUtilsParse.create_comment( - "Output Time: " + str(datetime.datetime.now()), values["COMMENT_SYMBOL"] + f"Output Time: {str(datetime.datetime.now())}", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" # Check canned cycles for drilling if values["TRANSLATE_DRILL_CYCLES"]: @@ -117,7 +117,7 @@ def export_common(values, objectslist, filename): values["SUPPRESS_COMMANDS"] += ["G99", "G98", "G80"] for line in values["SAFETYBLOCK"].splitlines(False): - gcode += PostUtilsParse.linenumber(values) + line + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{line}{nl}" # Write the preamble if values["OUTPUT_COMMENTS"]: @@ -127,23 +127,23 @@ def export_common(values, objectslist, filename): item.Proxy, PathToolController.ToolController ): comment = PostUtilsParse.create_comment( - "T{}={}".format(item.ToolNumber, item.Name), + f"T{item.ToolNumber}={item.Name}", values["COMMENT_SYMBOL"], ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" comment = PostUtilsParse.create_comment( "Begin preamble", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" for line in values["PREAMBLE"].splitlines(False): - gcode += PostUtilsParse.linenumber(values) + line + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{line}{nl}" # verify if PREAMBLE or SAFETYBLOCK have changed MOTION_MODE or UNITS if "G90" in values["PREAMBLE"] or "G90" in values["SAFETYBLOCK"]: values["MOTION_MODE"] = "G90" elif "G91" in values["PREAMBLE"] or "G91" in values["SAFETYBLOCK"]: values["MOTION_MODE"] = "G91" else: - gcode += PostUtilsParse.linenumber(values) + values["MOTION_MODE"] + "\n" + gcode += f'{PostUtilsParse.linenumber(values)}{values["MOTION_MODE"]}{nl}' if "G21" in values["PREAMBLE"] or "G21" in values["SAFETYBLOCK"]: values["UNITS"] = "G21" values["UNIT_FORMAT"] = "mm" @@ -153,7 +153,7 @@ def export_common(values, objectslist, filename): values["UNIT_FORMAT"] = "in" values["UNIT_SPEED_FORMAT"] = "in/min" else: - gcode += PostUtilsParse.linenumber(values) + values["UNITS"] + "\n" + gcode += f'{PostUtilsParse.linenumber(values)}{values["UNITS"]}{nl}' for obj in objectslist: @@ -163,52 +163,49 @@ def export_common(values, objectslist, filename): # print("*"*70 + "\n") # Skip inactive operations - if hasattr(obj, "Active"): - if not obj.Active: - continue - if hasattr(obj, "Base") and hasattr(obj.Base, "Active"): - if not obj.Base.Active: - continue + if hasattr(obj, "Active") and not obj.Active: + continue + if hasattr(obj, "Base") and hasattr(obj.Base, "Active") and not obj.Base.Active: + continue # do the pre_op if values["OUTPUT_BCNC"]: comment = PostUtilsParse.create_comment( - "Block-name: " + obj.Label, values["COMMENT_SYMBOL"] + f"Block-name: {obj.Label}", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" comment = PostUtilsParse.create_comment( "Block-expand: 0", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" comment = PostUtilsParse.create_comment( "Block-enable: 1", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" if values["OUTPUT_COMMENTS"]: if values["SHOW_OPERATION_LABELS"]: comment = PostUtilsParse.create_comment( - "Begin operation: %s" % obj.Label, values["COMMENT_SYMBOL"] + f"Begin operation: {obj.Label}", values["COMMENT_SYMBOL"] ) else: comment = PostUtilsParse.create_comment( "Begin operation", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" if values["SHOW_MACHINE_UNITS"]: comment = PostUtilsParse.create_comment( - "Machine units: %s" % values["UNIT_SPEED_FORMAT"], + f'Machine units: {values["UNIT_SPEED_FORMAT"]}', values["COMMENT_SYMBOL"], ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" if values["OUTPUT_MACHINE_NAME"]: comment = PostUtilsParse.create_comment( - "Machine: %s, %s" - % (values["MACHINE_NAME"], values["UNIT_SPEED_FORMAT"]), + f'Machine: {values["MACHINE_NAME"]}, {values["UNIT_SPEED_FORMAT"]}', values["COMMENT_SYMBOL"], ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" for line in values["PRE_OPERATION"].splitlines(False): - gcode += PostUtilsParse.linenumber(values) + line + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{line}{nl}" # get coolant mode coolantMode = "None" @@ -224,16 +221,15 @@ def export_common(values, objectslist, filename): # turn coolant on if required if values["ENABLE_COOLANT"]: - if values["OUTPUT_COMMENTS"]: - if not coolantMode == "None": - comment = PostUtilsParse.create_comment( - "Coolant On:" + coolantMode, values["COMMENT_SYMBOL"] - ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + if values["OUTPUT_COMMENTS"] and coolantMode != "None": + comment = PostUtilsParse.create_comment( + f"Coolant On: {coolantMode}", values["COMMENT_SYMBOL"] + ) + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" if coolantMode == "Flood": - gcode += PostUtilsParse.linenumber(values) + "M8" + "\n" - if coolantMode == "Mist": - gcode += PostUtilsParse.linenumber(values) + "M7" + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}M8{nl}" + elif coolantMode == "Mist": + gcode += f"{PostUtilsParse.linenumber(values)}M7{nl}" # process the operation gcode gcode += PostUtilsParse.parse(values, obj) @@ -241,53 +237,53 @@ def export_common(values, objectslist, filename): # do the post_op if values["OUTPUT_COMMENTS"]: comment = PostUtilsParse.create_comment( - "%s operation: %s" % (values["FINISH_LABEL"], obj.Label), + f'{values["FINISH_LABEL"]} operation: {obj.Label}', values["COMMENT_SYMBOL"], ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" for line in values["POST_OPERATION"].splitlines(False): - gcode += PostUtilsParse.linenumber(values) + line + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{line}{nl}" # turn coolant off if required - if values["ENABLE_COOLANT"]: - if not coolantMode == "None": - if values["OUTPUT_COMMENTS"]: - comment = PostUtilsParse.create_comment( - "Coolant Off:" + coolantMode, values["COMMENT_SYMBOL"] - ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" - gcode += PostUtilsParse.linenumber(values) + "M9" + "\n" + if values["ENABLE_COOLANT"] and coolantMode != "None": + if values["OUTPUT_COMMENTS"]: + comment = PostUtilsParse.create_comment( + f"Coolant Off: {coolantMode}", values["COMMENT_SYMBOL"] + ) + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" + gcode += f"{PostUtilsParse.linenumber(values)}M9{nl}" if values["RETURN_TO"]: - gcode += PostUtilsParse.linenumber(values) + "G0 X%s Y%s Z%s\n" % tuple( - values["RETURN_TO"] - ) + num_x = values["RETURN_TO"][0] + num_y = values["RETURN_TO"][1] + num_z = values["RETURN_TO"][2] + gcode += f"{PostUtilsParse.linenumber(values)}G0 X{num_x} Y{num_y} Z{num_z}{nl}" # do the post_amble if values["OUTPUT_BCNC"]: comment = PostUtilsParse.create_comment( "Block-name: post_amble", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" comment = PostUtilsParse.create_comment( "Block-expand: 0", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" comment = PostUtilsParse.create_comment( "Block-enable: 1", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" if values["OUTPUT_COMMENTS"]: comment = PostUtilsParse.create_comment( "Begin postamble", values["COMMENT_SYMBOL"] ) - gcode += PostUtilsParse.linenumber(values) + comment + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{comment}{nl}" for line in values["TOOLRETURN"].splitlines(False): - gcode += PostUtilsParse.linenumber(values) + line + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{line}{nl}" for line in values["SAFETYBLOCK"].splitlines(False): - gcode += PostUtilsParse.linenumber(values) + line + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{line}{nl}" for line in values["POSTAMBLE"].splitlines(False): - gcode += PostUtilsParse.linenumber(values) + line + "\n" + gcode += f"{PostUtilsParse.linenumber(values)}{line}{nl}" if FreeCAD.GuiUp and values["SHOW_EDITOR"]: final = gcode diff --git a/src/Mod/Path/Path/Post/UtilsParse.py b/src/Mod/Path/Path/Post/UtilsParse.py index 58bdc53725..61cce29547 100644 --- a/src/Mod/Path/Path/Post/UtilsParse.py +++ b/src/Mod/Path/Path/Post/UtilsParse.py @@ -39,47 +39,41 @@ import Path.Post.Utils as PostUtils def create_comment(comment_string, comment_symbol): """Create a comment from a string using the correct comment symbol.""" if comment_symbol == "(": - comment_string = "(" + comment_string + ")" + return f"({comment_string})" else: - comment_string = comment_symbol + comment_string - return comment_string + return comment_symbol + comment_string def drill_translate(values, outstring, cmd, params): """Translate drill cycles.""" - axis_precision_string = "." + str(values["AXIS_PRECISION"]) + "f" - feed_precision_string = "." + str(values["FEED_PRECISION"]) + "f" + axis_precision_string = f'.{str(values["AXIS_PRECISION"])}f' + feed_precision_string = f'.{str(values["FEED_PRECISION"])}f' trBuff = "" + nl = "\n" if values["OUTPUT_COMMENTS"]: # Comment the original command - trBuff += ( - linenumber(values) - + create_comment( - values["COMMAND_SPACE"] - + format_outstring(values, outstring) - + values["COMMAND_SPACE"], - values["COMMENT_SYMBOL"], - ) - + "\n" + comment = create_comment( + values["COMMAND_SPACE"] + + format_outstring(values, outstring) + + values["COMMAND_SPACE"], + values["COMMENT_SYMBOL"], ) + trBuff += f"{linenumber(values)}{comment}{nl}" # cycle conversion # currently only cycles in XY are provided (G17) # other plains ZX (G18) and YZ (G19) are not dealt with : Z drilling only. - drill_X = Units.Quantity(params["X"], FreeCAD.Units.Length) - drill_Y = Units.Quantity(params["Y"], FreeCAD.Units.Length) - drill_Z = Units.Quantity(params["Z"], FreeCAD.Units.Length) - RETRACT_Z = Units.Quantity(params["R"], FreeCAD.Units.Length) + drill_X = Units.Quantity(params["X"], Units.Length) + drill_Y = Units.Quantity(params["Y"], Units.Length) + drill_Z = Units.Quantity(params["Z"], Units.Length) + RETRACT_Z = Units.Quantity(params["R"], Units.Length) # R less than Z is error if RETRACT_Z < drill_Z: - trBuff += ( - linenumber(values) - + create_comment( - "Drill cycle error: R less than Z", values["COMMENT_SYMBOL"] - ) - + "\n" + comment = create_comment( + "Drill cycle error: R less than Z", values["COMMENT_SYMBOL"] ) + trBuff += f"{linenumber(values)}{comment}{nl}" return trBuff if values["MOTION_MODE"] == "G91": # G91 relative movements @@ -92,115 +86,87 @@ def drill_translate(values, outstring, cmd, params): RETRACT_Z = values["CURRENT_Z"] # get the other parameters - drill_feedrate = Units.Quantity(params["F"], FreeCAD.Units.Velocity) + drill_feedrate = Units.Quantity(params["F"], Units.Velocity) if cmd in ("G73", "G83"): - drill_Step = Units.Quantity(params["Q"], FreeCAD.Units.Length) + drill_Step = Units.Quantity(params["Q"], Units.Length) # NIST 3.5.16.4 G83 Cycle: "current hole bottom, backed off a bit." a_bit = drill_Step * 0.05 elif cmd == "G82": drill_DwellTime = params["P"] - # wrap this block to ensure machine's values["MOTION_MODE"] is restored in case of error - # try: - if values["MOTION_MODE"] == "G91": - # force absolute coordinates during cycles - trBuff += linenumber(values) + "G90\n" - - strG0_RETRACT_Z = ( - "G0 Z" - + format( - float(RETRACT_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string + # wrap this block to ensure machine's values["MOTION_MODE"] is restored + # in case of error + try: + if values["MOTION_MODE"] == "G91": + # force absolute coordinates during cycles + trBuff += f"{linenumber(values)}G90{nl}" + num = format( + float(RETRACT_Z.getValueAs(values["UNIT_FORMAT"])), + axis_precision_string, ) - + "\n" - ) - strF_Feedrate = ( - " F" - + format( + strG0_RETRACT_Z = f"G0 Z{num}{nl}" + num = format( float(drill_feedrate.getValueAs(values["UNIT_SPEED_FORMAT"])), feed_precision_string, ) - + "\n" - ) - # print(strF_Feedrate) + strF_Feedrate = f" F{num}{nl}" + # print(strF_Feedrate) - # preliminary movement(s) - if values["CURRENT_Z"] < RETRACT_Z: - trBuff += linenumber(values) + strG0_RETRACT_Z - trBuff += ( - linenumber(values) - + "G0 X" - + format( + # preliminary movement(s) + if values["CURRENT_Z"] < RETRACT_Z: + trBuff += f"{linenumber(values)}{strG0_RETRACT_Z}" + num_x = format( float(drill_X.getValueAs(values["UNIT_FORMAT"])), axis_precision_string ) - + " Y" - + format( + num_y = format( float(drill_Y.getValueAs(values["UNIT_FORMAT"])), axis_precision_string ) - + "\n" - ) - if values["CURRENT_Z"] > RETRACT_Z: - # NIST GCODE 3.5.16.1 Preliminary and In-Between Motion says G0 to RETRACT_Z - # Here use G1 since retract height may be below surface ! - trBuff += ( - linenumber(values) - + "G1 Z" - + format( + trBuff += f"{linenumber(values)}G0 X{num_x} Y{num_y}{nl}" + if values["CURRENT_Z"] > RETRACT_Z: + # NIST GCODE 3.5.16.1 Preliminary and In-Between Motion says G0 to RETRACT_Z + # Here use G1 since retract height may be below surface ! + num_z = format( float(RETRACT_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string, ) - + strF_Feedrate - ) - last_Stop_Z = RETRACT_Z + trBuff += f"{linenumber(values)}G1 Z{num_z}{strF_Feedrate}" + last_Stop_Z = RETRACT_Z - # drill moves - if cmd in ("G81", "G82"): - trBuff += ( - linenumber(values) - + "G1 Z" - + format( - float(drill_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string + # drill moves + if cmd in ("G81", "G82"): + num_z = format( + float(drill_Z.getValueAs(values["UNIT_FORMAT"])), + axis_precision_string, ) - + strF_Feedrate - ) - # pause where applicable - if cmd == "G82": - trBuff += linenumber(values) + "G4 P" + str(drill_DwellTime) + "\n" - trBuff += linenumber(values) + strG0_RETRACT_Z - else: # "G73" or "G83" - if params["Q"] != 0: - while 1: - if last_Stop_Z != RETRACT_Z: - # rapid move to just short of last drilling depth - clearance_depth = last_Stop_Z + a_bit - trBuff += ( - linenumber(values) - + "G0 Z" - + format( + trBuff += f"{linenumber(values)}G1 Z{num_z}{strF_Feedrate}" + # pause where applicable + if cmd == "G82": + trBuff += f"{linenumber(values)}G4 P{str(drill_DwellTime)}{nl}" + trBuff += f"{linenumber(values)}{strG0_RETRACT_Z}" + elif cmd in ("G73", "G83"): + if params["Q"] != 0: + while 1: + if last_Stop_Z != RETRACT_Z: + # rapid move to just short of last drilling depth + clearance_depth = last_Stop_Z + a_bit + num_z = format( float(clearance_depth.getValueAs(values["UNIT_FORMAT"])), axis_precision_string, ) - + "\n" - ) - next_Stop_Z = last_Stop_Z - drill_Step - if next_Stop_Z > drill_Z: - trBuff += ( - linenumber(values) - + "G1 Z" - + format( + trBuff += f"{linenumber(values)}G0 Z{num_z}{nl}" + next_Stop_Z = last_Stop_Z - drill_Step + if next_Stop_Z > drill_Z: + num_z = format( float(next_Stop_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string, ) - + strF_Feedrate - ) - if cmd == "G73": - # Rapid up "a small amount". - chip_breaker_height = ( - next_Stop_Z + values["CHIPBREAKING_AMOUNT"] - ) - trBuff += ( - linenumber(values) - + "G0 Z" - + format( + trBuff += f"{linenumber(values)}G1 Z{num_z}{strF_Feedrate}" + if cmd == "G73": + # Rapid up "a small amount". + chip_breaker_height = ( + next_Stop_Z + values["CHIPBREAKING_AMOUNT"] + ) + num_z = format( float( chip_breaker_height.getValueAs( values["UNIT_FORMAT"] @@ -208,46 +174,33 @@ def drill_translate(values, outstring, cmd, params): ), axis_precision_string, ) - + "\n" - ) - else: # "G83" - # Rapid up to the retract height - trBuff += linenumber(values) + strG0_RETRACT_Z - last_Stop_Z = next_Stop_Z - else: - trBuff += ( - linenumber(values) - + "G1 Z" - + format( + trBuff += f"{linenumber(values)}G0 Z{num_z}{nl}" + elif cmd == "G83": + # Rapid up to the retract height + trBuff += f"{linenumber(values)}{strG0_RETRACT_Z}" + last_Stop_Z = next_Stop_Z + else: + num_z = format( float(drill_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string, ) - + strF_Feedrate - ) - trBuff += linenumber(values) + strG0_RETRACT_Z - break - - # except Exception: - # print("exception occurred") - # pass + trBuff += f"{linenumber(values)}G1 Z{num_z}{strF_Feedrate}" + trBuff += f"{linenumber(values)}{strG0_RETRACT_Z}" + break + except Exception as err: + print("exception occurred", err) if values["MOTION_MODE"] == "G91": - trBuff += linenumber(values) + "G91\n" # Restore if changed + trBuff += f"{linenumber(values)}G91{nl}" # Restore if changed return trBuff -def dump(obj): - """For debug...""" - for attr in dir(obj): - print("obj.%s = %s" % (attr, getattr(obj, attr))) - - def format_outstring(values, strTable): """Construct the line for the final output.""" s = "" for w in strTable: - s += w + values["COMMAND_SPACE"] + s += f'{w}{values["COMMAND_SPACE"]}' s = s.strip() return s @@ -259,16 +212,17 @@ def linenumber(values, space=None): space = values["COMMAND_SPACE"] line_num = str(values["line_number"]) values["line_number"] += values["LINE_INCREMENT"] - return "N" + line_num + space + return f"N{line_num}{space}" return "" def parse(values, pathobj): """Parse a Path.""" + nl = "\n" out = "" lastcommand = None - axis_precision_string = "." + str(values["AXIS_PRECISION"]) + "f" - feed_precision_string = "." + str(values["FEED_PRECISION"]) + "f" + axis_precision_string = f'.{str(values["AXIS_PRECISION"])}f' + feed_precision_string = f'.{str(values["FEED_PRECISION"])}f' currLocation = {} # keep track for no doubles firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0}) @@ -279,7 +233,7 @@ def parse(values, pathobj): comment = create_comment( "Compound: " + pathobj.Label, values["COMMENT_SYMBOL"] ) - out += linenumber(values) + comment + "\n" + out += f"{linenumber(values)}{comment}{nl}" for p in pathobj.Group: out += parse(values, p) return out @@ -291,7 +245,7 @@ def parse(values, pathobj): if values["OUTPUT_PATH_LABELS"] and values["OUTPUT_COMMENTS"]: comment = create_comment("Path: " + pathobj.Label, values["COMMENT_SYMBOL"]) - out += linenumber(values) + comment + "\n" + out += f"{linenumber(values)}{comment}{nl}" if values["OUTPUT_ADAPTIVE"]: adaptiveOp = False @@ -305,22 +259,22 @@ def parse(values, pathobj): and pathobj.ToolController.HorizRapid > 0 ): opHorizRapid = Units.Quantity( - pathobj.ToolController.HorizRapid, FreeCAD.Units.Velocity + pathobj.ToolController.HorizRapid, Units.Velocity ) else: FreeCAD.Console.PrintWarning( - "Tool Controller Horizontal Rapid Values are unset" + "\n" + "Tool Controller Horizontal Rapid Values are unset\n" ) if ( hasattr(pathobj.ToolController, "VertRapid") and pathobj.ToolController.VertRapid > 0 ): opVertRapid = Units.Quantity( - pathobj.ToolController.VertRapid, FreeCAD.Units.Velocity + pathobj.ToolController.VertRapid, Units.Velocity ) else: FreeCAD.Console.PrintWarning( - "Tool Controller Vertical Rapid Values are unset" + "\n" + "Tool Controller Vertical Rapid Values are unset\n" ) for c in pathobj.Path.Commands: @@ -335,21 +289,21 @@ def parse(values, pathobj): command = PostUtils.fcoms(command, values["COMMENT_SYMBOL"]) else: continue - if values["OUTPUT_ADAPTIVE"]: - if adaptiveOp and command in values["RAPID_MOVES"]: - if opHorizRapid and opVertRapid: - command = "G1" - else: - outstring.append( - "(Tool Controller Rapid Values are unset)" + "\n" - ) + if ( + values["OUTPUT_ADAPTIVE"] + and adaptiveOp + and command in values["RAPID_MOVES"] + ): + if opHorizRapid and opVertRapid: + command = "G1" + else: + outstring.append("(Tool Controller Rapid Values are unset)\n") outstring.append(command) # if modal: suppress the command if it is the same as the last one - if values["MODAL"]: - if command == lastcommand: - outstring.pop(0) + if values["MODAL"] and command == lastcommand: + outstring.pop(0) # Now add the remaining parameters in order for param in values["PARAMETER_ORDER"]: @@ -360,50 +314,40 @@ def parse(values, pathobj): ): # centroid and linuxcnc don't use rapid speeds if command not in values["RAPID_MOVES"]: - speed = Units.Quantity( - c.Parameters["F"], FreeCAD.Units.Velocity - ) + speed = Units.Quantity(c.Parameters["F"], Units.Velocity) if speed.getValueAs(values["UNIT_SPEED_FORMAT"]) > 0.0: - outstring.append( - param - + format( - float( - speed.getValueAs( - values["UNIT_SPEED_FORMAT"] - ) - ), - feed_precision_string, - ) + param_num = format( + float( + speed.getValueAs(values["UNIT_SPEED_FORMAT"]) + ), + feed_precision_string, ) + outstring.append(f"{param}{param_num}") else: continue elif param in ("H", "L", "T"): - outstring.append(param + str(int(c.Parameters[param]))) + outstring.append(f"{param}{str(int(c.Parameters[param]))}") elif param == "D": if command in ("G41", "G42"): - outstring.append(param + str(int(c.Parameters[param]))) + outstring.append(f"{param}{str(int(c.Parameters[param]))}") elif command in ("G41.1", "G42.1"): - pos = Units.Quantity( - c.Parameters[param], FreeCAD.Units.Length - ) - outstring.append( - param - + format( - float(pos.getValueAs(values["UNIT_FORMAT"])), - axis_precision_string, - ) + pos = Units.Quantity(c.Parameters[param], Units.Length) + param_num = format( + float(pos.getValueAs(values["UNIT_FORMAT"])), + axis_precision_string, ) + outstring.append(f"{param}{param_num}") elif command in ("G96", "G97"): - outstring.append( - param - + PostUtils.fmt( - c.Parameters[param], - values["SPINDLE_DECIMALS"], - "G21", - ) + param_num = PostUtils.fmt( + c.Parameters[param], + values["SPINDLE_DECIMALS"], + "G21", ) + outstring.append(f"{param}{param_num}") else: # anything else that is supported - outstring.append(param + str(float(c.Parameters[param]))) + outstring.append( + f"{param}{str(float(c.Parameters[param]))}" + ) elif param == "P": if command in ( "G2", @@ -416,43 +360,35 @@ def parse(values, pathobj): "G54.1", "G59", ): - outstring.append(param + str(int(c.Parameters[param]))) + outstring.append(f"{param}{str(int(c.Parameters[param]))}") elif command in ("G4", "G04", "G76", "G82", "G86", "G89"): - outstring.append(param + str(float(c.Parameters[param]))) - elif command in ("G5", "G05", "G64"): - pos = Units.Quantity( - c.Parameters[param], FreeCAD.Units.Length - ) outstring.append( - param - + format( - float(pos.getValueAs(values["UNIT_FORMAT"])), - axis_precision_string, - ) + f"{param}{str(float(c.Parameters[param]))}" ) + elif command in ("G5", "G05", "G64"): + pos = Units.Quantity(c.Parameters[param], Units.Length) + param_num = format( + float(pos.getValueAs(values["UNIT_FORMAT"])), + axis_precision_string, + ) + outstring.append(f"{param}{param_num}") else: # anything else that is supported - outstring.append(param + str(c.Parameters[param])) + outstring.append(f"{param}{str(c.Parameters[param])}") elif param == "Q": if command == "G10": - outstring.append(param + str(int(c.Parameters[param]))) + outstring.append(f"{param}{str(int(c.Parameters[param]))}") elif command in ("G64", "G73", "G83"): - pos = Units.Quantity( - c.Parameters[param], FreeCAD.Units.Length - ) - outstring.append( - param - + format( - float(pos.getValueAs(values["UNIT_FORMAT"])), - axis_precision_string, - ) + pos = Units.Quantity(c.Parameters[param], Units.Length) + param_num = format( + float(pos.getValueAs(values["UNIT_FORMAT"])), + axis_precision_string, ) + outstring.append(f"{param}{param_num}") elif param == "S": - outstring.append( - param - + PostUtils.fmt( - c.Parameters[param], values["SPINDLE_DECIMALS"], "G21" - ) + param_num = PostUtils.fmt( + c.Parameters[param], values["SPINDLE_DECIMALS"], "G21" ) + outstring.append(f"{param}{param_num}") else: if ( (not values["OUTPUT_DOUBLES"]) @@ -461,44 +397,32 @@ def parse(values, pathobj): ): continue else: - pos = Units.Quantity( - c.Parameters[param], FreeCAD.Units.Length - ) - outstring.append( - param - + format( - float(pos.getValueAs(values["UNIT_FORMAT"])), - axis_precision_string, - ) + pos = Units.Quantity(c.Parameters[param], Units.Length) + param_num = format( + float(pos.getValueAs(values["UNIT_FORMAT"])), + axis_precision_string, ) + outstring.append(f"{param}{param_num}") - if values["OUTPUT_ADAPTIVE"]: - if adaptiveOp and command in values["RAPID_MOVES"]: - if opHorizRapid and opVertRapid: - if "Z" not in c.Parameters: - outstring.append( - "F" - + format( - float( - opHorizRapid.getValueAs( - values["UNIT_SPEED_FORMAT"] - ) - ), - axis_precision_string, - ) - ) - else: - outstring.append( - "F" - + format( - float( - opVertRapid.getValueAs( - values["UNIT_SPEED_FORMAT"] - ) - ), - axis_precision_string, - ) - ) + if ( + values["OUTPUT_ADAPTIVE"] + and adaptiveOp + and command in values["RAPID_MOVES"] + and opHorizRapid + and opVertRapid + ): + if "Z" not in c.Parameters: + param_num = format( + float(opHorizRapid.getValueAs(values["UNIT_SPEED_FORMAT"])), + axis_precision_string, + ) + outstring.append(f"F{param_num}") + else: + param_num = format( + float(opVertRapid.getValueAs(values["UNIT_SPEED_FORMAT"])), + axis_precision_string, + ) + outstring.append(f"F{param_num}") # store the latest command lastcommand = command @@ -509,42 +433,35 @@ def parse(values, pathobj): if command in values["MOTION_COMMANDS"]: if "X" in c.Parameters: values["CURRENT_X"] = Units.Quantity( - c.Parameters["X"], FreeCAD.Units.Length + c.Parameters["X"], Units.Length ) if "Y" in c.Parameters: values["CURRENT_Y"] = Units.Quantity( - c.Parameters["Y"], FreeCAD.Units.Length + c.Parameters["Y"], Units.Length ) if "Z" in c.Parameters: values["CURRENT_Z"] = Units.Quantity( - c.Parameters["Z"], FreeCAD.Units.Length + c.Parameters["Z"], Units.Length ) if command in ("G98", "G99"): values["DRILL_RETRACT_MODE"] = command - - if command in ("G90", "G91"): + elif command in ("G90", "G91"): values["MOTION_MODE"] = command - if values["TRANSLATE_DRILL_CYCLES"]: - if command in values["DRILL_CYCLES_TO_TRANSLATE"]: - out += drill_translate(values, outstring, command, c.Parameters) - # Erase the line we just translated - outstring = [] + if ( + values["TRANSLATE_DRILL_CYCLES"] + and command in values["DRILL_CYCLES_TO_TRANSLATE"] + ): + out += drill_translate(values, outstring, command, c.Parameters) + # Erase the line we just translated + outstring = [] - if values["SPINDLE_WAIT"] > 0: - if command in ("M3", "M03", "M4", "M04"): - out += ( - linenumber(values) + format_outstring(values, outstring) + "\n" - ) - out += ( - linenumber(values) - + format_outstring( - values, ["G4", "P%s" % values["SPINDLE_WAIT"]] - ) - + "\n" - ) - outstring = [] + if values["SPINDLE_WAIT"] > 0 and command in ("M3", "M03", "M4", "M04"): + out += f"{linenumber(values)}{format_outstring(values, outstring)}{nl}" + num = format_outstring(values, ["G4", f'P{values["SPINDLE_WAIT"]}']) + out += f"{linenumber(values)}{num}{nl}" + outstring = [] # Check for Tool Change: if command in ("M6", "M06"): @@ -552,24 +469,23 @@ def parse(values, pathobj): comment = create_comment( "Begin toolchange", values["COMMENT_SYMBOL"] ) - out += linenumber(values) + comment + "\n" + out += f"{linenumber(values)}{comment}{nl}" if values["OUTPUT_TOOL_CHANGE"]: if values["STOP_SPINDLE_FOR_TOOL_CHANGE"]: # stop the spindle - out += linenumber(values) + "M5\n" + out += f"{linenumber(values)}M5{nl}" for line in values["TOOL_CHANGE"].splitlines(False): - out += linenumber(values) + line + "\n" - else: - if values["OUTPUT_COMMENTS"]: - # convert the tool change to a comment - comment = create_comment( - values["COMMAND_SPACE"] - + format_outstring(values, outstring) - + values["COMMAND_SPACE"], - values["COMMENT_SYMBOL"], - ) - out += linenumber(values) + comment + "\n" - outstring = [] + out += f"{linenumber(values)}{line}{nl}" + elif values["OUTPUT_COMMENTS"]: + # convert the tool change to a comment + comment = create_comment( + values["COMMAND_SPACE"] + + format_outstring(values, outstring) + + values["COMMAND_SPACE"], + values["COMMENT_SYMBOL"], + ) + out += f"{linenumber(values)}{comment}{nl}" + outstring = [] if command == "message" and values["REMOVE_MESSAGES"]: if values["OUTPUT_COMMENTS"] is False: @@ -586,7 +502,7 @@ def parse(values, pathobj): + values["COMMAND_SPACE"], values["COMMENT_SYMBOL"], ) - out += linenumber(values) + comment + "\n" + out += f"{linenumber(values)}{comment}{nl}" # remove the command outstring = [] @@ -601,11 +517,11 @@ def parse(values, pathobj): out += values["COMMAND_SPACE"].join(outstring) # Note: Do *not* strip `out`, since that forces the allocation # of a contiguous string & thus quadratic complexity. - out += "\n" + out += f"{nl}" # add height offset if command in ("M6", "M06") and values["USE_TLO"]: - out += linenumber(values) + "G43 H" + str(int(c.Parameters["T"])) + "\n" + out += f'{linenumber(values)}G43 H{str(int(c.Parameters["T"]))}{nl}' # Check for comments containing machine-specific commands # to pass literally to the controller @@ -613,6 +529,6 @@ def parse(values, pathobj): m = re.match(r"^\(MC_RUN_COMMAND: ([^)]+)\)$", command) if m: raw_command = m.group(1) - out += linenumber(values) + raw_command + "\n" + out += f"{linenumber(values)}{raw_command}{nl}" return out diff --git a/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py b/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py index e1e1fa9271..b326bdf13c 100644 --- a/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py +++ b/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py @@ -210,7 +210,8 @@ def init_arguments(values, argument_defaults, arguments_visible): values, argument_defaults, arguments_visible ) # - # Add any argument definitions that are not shared with all other postprocessors here. + # Add any argument definitions that are not shared with all other + # postprocessors here. # return parser diff --git a/src/Mod/Path/Path/Post/scripts/refactored_grbl_post.py b/src/Mod/Path/Path/Post/scripts/refactored_grbl_post.py index cb8d88eea7..3b7aefda22 100644 --- a/src/Mod/Path/Path/Post/scripts/refactored_grbl_post.py +++ b/src/Mod/Path/Path/Post/scripts/refactored_grbl_post.py @@ -80,7 +80,8 @@ def init_values(values): # values["OUTPUT_PATH_LABELS"] = True # - # Default to not outputting M6 tool changes (comment it) as grbl currently does not handle it + # Default to not outputting M6 tool changes (comment it) as grbl + # currently does not handle it # values["OUTPUT_TOOL_CHANGE"] = False # @@ -177,7 +178,8 @@ def init_arguments(values, argument_defaults, arguments_visible): values, argument_defaults, arguments_visible ) # - # Add any argument definitions that are not shared with all other postprocessors here. + # Add any argument definitions that are not shared with all other + # postprocessors here. # return parser diff --git a/src/Mod/Path/Path/Post/scripts/refactored_linuxcnc_post.py b/src/Mod/Path/Path/Post/scripts/refactored_linuxcnc_post.py index d5db6983df..ab7f5ceb3c 100644 --- a/src/Mod/Path/Path/Post/scripts/refactored_linuxcnc_post.py +++ b/src/Mod/Path/Path/Post/scripts/refactored_linuxcnc_post.py @@ -144,7 +144,8 @@ def init_arguments(values, argument_defaults, arguments_visible): values, argument_defaults, arguments_visible ) # - # Add any argument definitions that are not shared with all other postprocessors here. + # Add any argument definitions that are not shared with all other + # postprocessors here. # return parser diff --git a/src/Mod/Path/Path/Post/scripts/refactored_mach3_mach4_post.py b/src/Mod/Path/Path/Post/scripts/refactored_mach3_mach4_post.py index 881f385f2e..841fe0ac9e 100644 --- a/src/Mod/Path/Path/Post/scripts/refactored_mach3_mach4_post.py +++ b/src/Mod/Path/Path/Post/scripts/refactored_mach3_mach4_post.py @@ -151,7 +151,8 @@ def init_arguments(values, argument_defaults, arguments_visible): values, argument_defaults, arguments_visible ) # - # Add any argument definitions that are not shared with all other postprocessors here. + # Add any argument definitions that are not shared with all other + # postprocessors here. # return parser diff --git a/src/Mod/Path/Path/Post/scripts/refactored_test_post.py b/src/Mod/Path/Path/Post/scripts/refactored_test_post.py index 6ae414244d..9f91c9ac6a 100644 --- a/src/Mod/Path/Path/Post/scripts/refactored_test_post.py +++ b/src/Mod/Path/Path/Post/scripts/refactored_test_post.py @@ -145,7 +145,8 @@ def init_arguments(values, argument_defaults, arguments_visible): values, argument_defaults, arguments_visible ) # - # Add any argument definitions that are not shared with all other postprocessors here. + # Add any argument definitions that are not shared with all other + # postprocessors here. # return parser diff --git a/src/Mod/Path/PathTests/TestRefactoredTestPost.py b/src/Mod/Path/PathTests/TestRefactoredTestPost.py index dec1e23014..546aa494d5 100644 --- a/src/Mod/Path/PathTests/TestRefactoredTestPost.py +++ b/src/Mod/Path/PathTests/TestRefactoredTestPost.py @@ -90,15 +90,17 @@ class TestRefactoredTestPost(PathTestUtils.PathTestBase): def single_compare(self, path, expected, args, debug=False): """Perform a test with a single comparison.""" + nl = "\n" self.docobj.Path = Path.Path(path) postables = [self.docobj] gcode = postprocessor.export(postables, "gcode.tmp", args) if debug: - print("--------\n" + gcode + "--------\n") + print(f"--------{nl}{gcode}--------{nl}") self.assertEqual(gcode, expected) def compare_third_line(self, path_string, expected, args, debug=False): - """Perform a test with a single comparison only to the third line of the output.""" + """Perform a test with a single comparison to the third line of the output.""" + nl = "\n" if path_string: self.docobj.Path = Path.Path([Path.Command(path_string)]) else: @@ -106,7 +108,7 @@ class TestRefactoredTestPost(PathTestUtils.PathTestBase): postables = [self.docobj] gcode = postprocessor.export(postables, "gcode.tmp", args) if debug: - print("--------\n" + gcode + "--------\n") + print(f"--------{nl}{gcode}--------{nl}") self.assertEqual(gcode.splitlines()[2], expected) # @@ -885,7 +887,7 @@ G52 X0.0000 Y0.0000 Z0.0000 A0.0000 B0.0000 C0.0000 U0.0000 V0.0000 W0.0000 """Test G59 command Generation.""" self.compare_third_line("G59", "G59", "") # - # Some gcode interpreters us G59 P- to select additional + # Some gcode interpreters use G59 P- to select additional # work coordinate systems. This is considered somewhat # obsolete and is being replaces by G54.1 P- instead. #