diff --git a/src/Mod/Path/PathScripts/post/uccnc_post.py b/src/Mod/Path/PathScripts/post/uccnc_post.py index 2b310ae4bf..7d3319f865 100644 --- a/src/Mod/Path/PathScripts/post/uccnc_post.py +++ b/src/Mod/Path/PathScripts/post/uccnc_post.py @@ -1,29 +1,29 @@ # -*- coding: utf-8 -*- -#*************************************************************************** -#* * -#* based upon linuxcnc_post.py (c) sliptonic (shopinthewoods@gmail.com) * -#* * -#* changed, but not enough to claim copyrights 2019-2021 * -#* maintainer: A.H.M. Steenveld * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** +# *************************************************************************** +# * * +# * based upon linuxcnc_post.py (c) sliptonic (shopinthewoods@gmail.com) * +# * * +# * changed, but not enough to claim copyrights 2019-2021 * +# * maintainer: A.H.M. Steenveld * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** # See: https://wiki.freecadweb.org/Path_Post # https://wiki.freecadweb.org/Path_Postprocessor_Customization @@ -35,12 +35,12 @@ from FreeCAD import Units import Path import argparse import datetime -#import shlex +# import shlex from PathScripts import PostUtils -VERSION="0.0.4" +VERSION = "0.0.4" -TOOLTIP=''' Post processor for UC-CNC. +TOOLTIP = ''' Post processor for UC-CNC. This is a postprocessor file for the Path workbench. It is used to take a pseudo-gcode fragment outputted by a Path object, and output @@ -107,9 +107,9 @@ POST_OPERATION = '''''' # TOOL_CHANGE: Tool Change commands will be inserted before a tool change TOOL_CHANGE = '''''' -###################################################### -### Other configuration settings ### -###################################################### +################################ +# Other configuration settings # +################################ # GCODE_PROCESSOR possible options # string The target GCode processor name. @@ -121,9 +121,9 @@ GCODE_PROCESSOR = "UC-CNC" # False the file is written directly # set with --no-show-editor if FreeCAD.GuiUp: - SHOW_EDITOR = True + SHOW_EDITOR = True else: - SHOW_EDITOR = False + SHOW_EDITOR = False # PROG_NAME possible values: # text Name of the G-Code program @@ -154,7 +154,7 @@ OUTPUT_LINE_NUMBERS = False # LINE_NUMBER_START possible values: # int unsigned integer. Line number starting value -# 0..N +# 0..N LINE_NUMBER_START = 0 # LINE_NUMBER_STEP possible values: @@ -190,16 +190,16 @@ REPEAT_ARGUMENTS = False # USE_TLO posible values: # bool Set tool length offset. -# True G43 will be output following tool changes +# True G43 will be output following tool changes # False No G43 used. # set with --tool-length-offset USE_TLO = False # PRECISION possible values: -# int Number of digits in axis positions +# int Number of digits in axis positions # 0...N # set with --precision N -PRECISION=3 +PRECISION = 3 # UNITS possible values: # GCODE Code to switch to specific units @@ -235,41 +235,54 @@ UNIT_SPEED_FORMAT_US_IMP = 'in/min' UNIT_SPEED_FORMAT_METRIC = 'mm/min' UNIT_SPEED_FORMAT = UNIT_SPEED_FORMAT_METRIC -###################################################### -### No more configuration settings after this line ### -###################################################### +################################################## +# No more configuration settings after this line # +################################################## # see: https://docs.python.org/3/library/argparse.html parser = argparse.ArgumentParser(prog=__name__, add_help=False) -parser.add_argument('--name', help='GCode program name') -parser.add_argument('--no-header', action='store_true', help='suppress header output') -parser.add_argument('--no-comments', action='store_true', help='suppress comment output') -parser.add_argument('--line-numbers', action='store_true', help='suppress prefix with line numbers') -parser.add_argument('--no-show-editor', action='store_true', help='don\'t pop up editor before writing output') -parser.add_argument('--precision', default='3', help='number of digits of precision, default=3') -parser.add_argument('--preamble', help='set commands to be issued before the first command, default="G17\nG90\nG54"') -parser.add_argument('--postamble', help='set commands to be issued after the last command, default="M05\nM30"') -parser.add_argument('--inches', action='store_true', help='lengths in [in], G20') -parser.add_argument('--metric', action='store_true', help='lengths in [mm], G21') -parser.add_argument('--modal', action='store_true', help='repeat/suppress repeated command arguments') -parser.add_argument('--tool-length-offset', action='store_true', help='suppress tool length offset G43 following tool changes') -parser.add_argument('--repeat', action='store_true', help='repeat axis arguments') +parser.add_argument('--name', + help='GCode program name') +parser.add_argument('--no-header', action='store_true', + help='suppress header output') +parser.add_argument('--no-comments', action='store_true', + help='suppress comment output') +parser.add_argument('--line-numbers', action='store_true', + help='suppress prefix with line numbers') +parser.add_argument('--no-show-editor', action='store_true', + help='don\'t pop up editor before writing output') +parser.add_argument('--precision', default='3', + help='number of digits of precision, default=3') +parser.add_argument('--preamble', + help='set commands to be issued before the first command, default="G17\nG90\nG54"') +parser.add_argument('--postamble', + help='set commands to be issued after the last command, default="M05\nM30"') +parser.add_argument('--inches', action='store_true', + help='lengths in [in], G20') +parser.add_argument('--metric', action='store_true', + help='lengths in [mm], G21') +parser.add_argument('--modal', action='store_true', + help='repeat/suppress repeated command arguments') +parser.add_argument('--tool-length-offset', action='store_true', + help='suppress tool length offset G43 following tool changes') +parser.add_argument('--repeat', action='store_true', + help='repeat axis arguments') TOOLTIP_ARGS = parser.format_help() # to distinguish python built-in open function from the one declared below if open.__module__ in ['__builtin__', 'io']: - pythonopen = open + pythonopen = open # to distinguish python built-in open function from the one declared below if open.__module__ == '__builtin__': - pythonopen = open + pythonopen = open # debug option, trace to screen while processing to see where things break up. trace_gcode = False now = datetime.datetime.now() -LINENR=0 +LINENR = 0 COMMAND_SPACE = " " UNIT_DEFAULT_CHANGED = False @@ -278,364 +291,353 @@ UNIT_DEFAULT_CHANGED = False warnings_count = 0 problems_count = 0 +HEADER = '''(Exported by FreeCAD for {}) +(Post Processor: {}, version {}) +(CAM file: {}) +(Output Time: {}) +''' + def processArguments(argstring): - global GCODE_PROCESSOR # The target GCode processor name - global SHOW_EDITOR # Show gcode before saving. - global PROG_NAME # Name of the G-Code program - global OUTPUT_HEADER # Use of a document header - global OUTPUT_COMMENTS # (Dont) use comments in output - global OUTPUT_LINE_NUMBERS # (Dont) use line numbers in output - global LINE_NUMBER_START # Line number starting value - global LINE_NUMBER_STEP # Line number increment value - global PREAMBLE # Preamble gcode - global POSTAMBLE # Postable gcode - global PRE_OPERATION # Pre operation text will be inserted before every operation - global POST_OPERATION # Post operation text will be inserted after every operation - global MODAL # Repeat/suppress repeated command arguments. - global USE_TLO # Set tool length offset - global PRECISION # Number of digits in feed and axis values - global UNITS # Code to switch to specific units - global UNITS_US_IMP # - global UNITS_METRIC # - global UNIT_FORMAT # Text with specific units - global UNIT_FORMAT_US_IMP # - global UNIT_FORMAT_METRIC # - global UNIT_SPEED_FORMAT # Text with specific units over time units - global UNIT_SPEED_FORMAT_US_IMP # - global UNIT_SPEED_FORMAT_METRIC # - global UNIT_DEFAULT_CHANGED # tracing changes in UNIT settings. - global REPEAT_ARGUMENTS # Repeat or surpress axis values if the same as previous line. + global SHOW_EDITOR # Show gcode before saving. + global PROG_NAME # Name of the G-Code program + global OUTPUT_HEADER # Use of a document header + global OUTPUT_COMMENTS # (Dont) use comments in output + global OUTPUT_LINE_NUMBERS # (Dont) use line numbers in output + global PREAMBLE # Preamble gcode + global POSTAMBLE # Postable gcode + global MODAL # Repeat/suppress repeated command arguments. + global USE_TLO # Set tool length offset + global PRECISION # Number of digits in feed and axis values + global UNITS # Code to switch to specific units + global UNIT_FORMAT # Text with specific units + global UNIT_SPEED_FORMAT # Text with specific units over time units + global UNIT_DEFAULT_CHANGED # tracing changes in UNIT settings. + global REPEAT_ARGUMENTS # Repeat or surpress axis values if the same as previous line. - try: - UNIT_DEFAULT_CHANGED = False - args = parser.parse_args(argstring.split()) + try: + UNIT_DEFAULT_CHANGED = False + args = parser.parse_args(argstring.split()) - if args.name is not None: - PROG_NAME = args.name + if args.name is not None: + PROG_NAME = args.name - if args.no_header: - OUTPUT_HEADER = False + if args.no_header: + OUTPUT_HEADER = False - if args.no_comments: - OUTPUT_COMMENTS = False + if args.no_comments: + OUTPUT_COMMENTS = False - if args.line_numbers: - OUTPUT_LINE_NUMBERS = True + if args.line_numbers: + OUTPUT_LINE_NUMBERS = True - if args.no_show_editor: - SHOW_EDITOR = False + if args.no_show_editor: + SHOW_EDITOR = False - PRECISION = args.precision + PRECISION = args.precision - if args.preamble is not None: - PREAMBLE = args.preamble - elif OUTPUT_COMMENTS: - PREAMBLE = PREAMBLE_DEFAULT - else: - PREAMBLE = PREAMBLE_DEFAULT_NO_COMMENT + if args.preamble is not None: + PREAMBLE = args.preamble + elif OUTPUT_COMMENTS: + PREAMBLE = PREAMBLE_DEFAULT + else: + PREAMBLE = PREAMBLE_DEFAULT_NO_COMMENT - if args.postamble is not None: - POSTAMBLE = args.postamble - elif OUTPUT_COMMENTS: - POSTAMBLE = POSTAMBLE_DEFAULT - else: - POSTAMBLE = POSTAMBLE_DEFAULT_NO_COMMENT + if args.postamble is not None: + POSTAMBLE = args.postamble + elif OUTPUT_COMMENTS: + POSTAMBLE = POSTAMBLE_DEFAULT + else: + POSTAMBLE = POSTAMBLE_DEFAULT_NO_COMMENT - if args.inches and (UNITS != UNITS_US_IMP): - print("Units: US Imperial [inch], check your UC-CNC profile.") - UNITS = UNITS_US_IMP - UNIT_FORMAT = UNIT_FORMAT_US_IMP - UNIT_SPEED_FORMAT = UNIT_SPEED_FORMAT_US_IMP - UNIT_DEFAULT_CHANGED = True + if args.inches and (UNITS != UNITS_US_IMP): + print("Units: US Imperial [inch], check your UC-CNC profile.") + UNITS = UNITS_US_IMP + UNIT_FORMAT = UNIT_FORMAT_US_IMP + UNIT_SPEED_FORMAT = UNIT_SPEED_FORMAT_US_IMP + UNIT_DEFAULT_CHANGED = True - if args.metric and (UNITS != UNITS_METRIC): - print("Units: Metric [mm], check your UC-CNC profile.") - UNITS = UNITS_METRIC - UNIT_FORMAT = UNIT_FORMAT_METRIC - UNIT_SPEED_FORMAT = UNIT_SPEED_FORMAT_METRIC - UNIT_DEFAULT_CHANGED = True + if args.metric and (UNITS != UNITS_METRIC): + print("Units: Metric [mm], check your UC-CNC profile.") + UNITS = UNITS_METRIC + UNIT_FORMAT = UNIT_FORMAT_METRIC + UNIT_SPEED_FORMAT = UNIT_SPEED_FORMAT_METRIC + UNIT_DEFAULT_CHANGED = True - if args.modal: - MODAL = True + if args.modal: + MODAL = True - if args.tool_length_offset: - USE_TLO = True + if args.tool_length_offset: + USE_TLO = True - if args.repeat: - REPEAT_ARGUMENTS = True + if args.repeat: + REPEAT_ARGUMENTS = True - except Exception: - return False + except Exception: + return False + + return True - return True def append0(line): - result = line - if (trace_gcode): - print("export: >>" + result) - return result + result = line + if (trace_gcode): + print("export: >>" + result) + return result + def append(line): - result = linenumber() + line - if (trace_gcode): - print("export: >>" + result) - return result + result = linenumber() + line + if (trace_gcode): + print("export: >>" + result) + return result + def export(objectslist, filename, argstring): - if not processArguments(argstring): - print("export: process arguments failed, '{}'".format(argstring)) - return None + if not processArguments(argstring): + print("export: process arguments failed, '{}'".format(argstring)) + return None - global UNITS - global UNIT_FORMAT - global UNIT_SPEED_FORMAT - global warnings_count - global problems_count + global warnings_count + global problems_count - warnings_count = 0 - problems_count = 0 + warnings_count = 0 + problems_count = 0 - for obj in objectslist: - if not hasattr(obj, "Path"): - print("the object " + obj.Name + " is not a path. Please select only path and Compounds.") - return None + for obj in objectslist: + if not hasattr(obj, "Path"): + print("the object " + obj.Name + " is not a path. Please select only path and Compounds.") + return None - print("export: postprocessing...") - gcode = append0("%" + PROG_NAME + "\n") - if not argstring: - gcode += append("(" + __name__ + " with default settings)\n") - else: - gcode += append("({} {})\n".format(__name__, argstring)) + print("export: postprocessing...") + gcode = append0("%" + PROG_NAME + "\n") + if not argstring: + gcode += append("(" + __name__ + " with default settings)\n") + else: + gcode += append("({} {})\n".format(__name__, argstring)) - # write header - if OUTPUT_HEADER: - HEADER = '''(Exported by FreeCAD for {}) - (Post Processor: {}, version {}) - (CAM file: {}) - (Output Time: {}) - ''' - for line in HEADER.format(GCODE_PROCESSOR, __name__, VERSION, FreeCAD.ActiveDocument.FileName, str(now)).splitlines(): - l = line.strip() - if (l): - gcode += append(l + "\n") + # write header + if OUTPUT_HEADER: + for line in HEADER.format(GCODE_PROCESSOR, + __name__, VERSION, + FreeCAD.ActiveDocument.FileName, str(now)).splitlines(False): + if (line): + gcode += append(line + "\n") - # Write the preamble - # G20/G21 not supported by UC-CNC, *always* report the configured units and deviations from the default settings for safety. - gcode += append("(Units: '" + UNIT_FORMAT + "' and '" + UNIT_SPEED_FORMAT + "')\n") - if (UNIT_DEFAULT_CHANGED): - gcode += append("(WARNING: Units default changed, check your UC-CNC profile)\n") - warnings_count += 1 + # Write the preamble + # G20/G21 not supported by UC-CNC, *always* report the configured units. + gcode += append("(Units: '" + UNIT_FORMAT + "' and '" + UNIT_SPEED_FORMAT + "')\n") + if (UNIT_DEFAULT_CHANGED): + gcode += append("(WARNING: Units default changed, check your UC-CNC profile)\n") + warnings_count += 1 - if OUTPUT_COMMENTS: - gcode += append("(preamble: begin)\n") - #for obj in objectslist: - # if isinstance(obj.Proxy, PathScripts.PathToolController.ToolController): - # gcode += append("(T{}={})\n".format(obj.ToolNumber, item.Name)) - # error: global name 'PathScripts' is not defined - for line in PREAMBLE.splitlines(False): - gcode += append(line + "\n") - if OUTPUT_COMMENTS: - gcode += append("(preamble: done)\n") + if OUTPUT_COMMENTS: + gcode += append("(preamble: begin)\n") + # for obj in objectslist: + # if isinstance(obj.Proxy, PathScripts.PathToolController.ToolController): + # gcode += append("(T{}={})\n".format(obj.ToolNumber, item.Name)) + # error: global name 'PathScripts' is not defined + for line in PREAMBLE.splitlines(False): + gcode += append(line + "\n") + if OUTPUT_COMMENTS: + gcode += append("(preamble: done)\n") - # write the code body - for obj in objectslist: + # write the code body + for obj in objectslist: - # pre_op - if OUTPUT_COMMENTS: - gcode += append("(operation initialise: %s)\n" % obj.Label) - for line in PRE_OPERATION.splitlines(True): - gcode += append(line) + # pre_op + if OUTPUT_COMMENTS: + gcode += append("(operation initialise: %s)\n" % obj.Label) + for line in PRE_OPERATION.splitlines(True): + gcode += append(line) - # turn coolant on if required - if hasattr(obj, "CoolantMode"): - coolantMode = obj.CoolantMode - if coolantMode == 'Mist': - if OUTPUT_COMMENTS: - gcode += append("M7 (coolant: mist on)\n") - else: - gcode += append("M7\n") - if coolantMode == 'Flood': - if OUTPUT_COMMENTS: - gcode += append("M8 (coolant: flood on)\n") - else: - gcode += append("M8\n") + # turn coolant on if required + if hasattr(obj, "CoolantMode"): + coolantMode = obj.CoolantMode + if coolantMode == 'Mist': + if OUTPUT_COMMENTS: + gcode += append("M7 (coolant: mist on)\n") + else: + gcode += append("M7\n") + if coolantMode == 'Flood': + if OUTPUT_COMMENTS: + gcode += append("M8 (coolant: flood on)\n") + else: + gcode += append("M8\n") - # process the operation gcode - if OUTPUT_COMMENTS: - gcode += append("(operation start: %s)\n" % obj.Label) - gcode += parse(obj) - if OUTPUT_COMMENTS: - gcode += append("(operation done: %s)\n" % obj.Label) + # process the operation gcode + if OUTPUT_COMMENTS: + gcode += append("(operation start: %s)\n" % obj.Label) + gcode += parse(obj) + if OUTPUT_COMMENTS: + gcode += append("(operation done: %s)\n" % obj.Label) - # post_op - for line in POST_OPERATION.splitlines(True): - gcode += append(line) + # post_op + for line in POST_OPERATION.splitlines(True): + gcode += append(line) - # turn coolant off if required - if hasattr(obj, "CoolantMode"): - coolantMode = obj.CoolantMode - if not coolantMode == 'None': - if OUTPUT_COMMENTS: - gcode += append("M9 (coolant: off)\n") - else: - gcode += append("M9\n") - if OUTPUT_COMMENTS: - gcode += append("(operation finalised: %s)\n" % obj.Label) + # turn coolant off if required + if hasattr(obj, "CoolantMode"): + coolantMode = obj.CoolantMode + if not coolantMode == 'None': + if OUTPUT_COMMENTS: + gcode += append("M9 (coolant: off)\n") + else: + gcode += append("M9\n") + if OUTPUT_COMMENTS: + gcode += append("(operation finalised: %s)\n" % obj.Label) - # do the post_amble - if OUTPUT_COMMENTS: - gcode += append("(postamble: begin)\n") - for line in POSTAMBLE.splitlines(True): - gcode += append(line) - if OUTPUT_COMMENTS: - gcode += append("(postamble: done)\n") + # do the post_amble + if OUTPUT_COMMENTS: + gcode += append("(postamble: begin)\n") + for line in POSTAMBLE.splitlines(True): + gcode += append(line) + if OUTPUT_COMMENTS: + gcode += append("(postamble: done)\n") - # Show the results - if SHOW_EDITOR: - dia = PostUtils.GCodeEditorDialog() - dia.editor.setText(gcode) - result = dia.exec_() - if result: - final = dia.editor.toPlainText() - else: - final = gcode - else: - final = gcode + # Show the results + if SHOW_EDITOR: + dia = PostUtils.GCodeEditorDialog() + dia.editor.setText(gcode) + result = dia.exec_() + if result: + final = dia.editor.toPlainText() + else: + final = gcode + else: + final = gcode - if (0 < problems_count) or (0 < warnings_count): - print("export: postprocessing: done, warnings: {}, problems: {}, see GCode output for details.".format(warnings_count, problems_count)) - else: - print("export: postprocessing: done (none of the problems detected).") + if (0 < problems_count) or (0 < warnings_count): + print("export: postprocessing: done, warnings: {}, problems: {}, see GCode for details." + .format(warnings_count, problems_count)) + else: + print("export: postprocessing: done (none of the problems detected).") - if not filename == '-': - print("export: writing to '{}'".format(filename)) - gfile = pythonopen(filename, "w") - gfile.write(final) - gfile.close() + if not filename == '-': + print("export: writing to '{}'".format(filename)) + gfile = pythonopen(filename, "w") + gfile.write(final) + gfile.close() + + return final - return final def linenumber(): - global LINE_NUMBER_START - global LINE_NUMBER_STEP - global LINENR + global LINENR + + if (LINENR <= 0): + LINENR = LINE_NUMBER_START + if OUTPUT_LINE_NUMBERS is True: + line = LINENR + LINENR += LINE_NUMBER_STEP + return "N{:03d} ".format(line) + return "" - if LINENR <= 0: - LINENR = LINE_NUMBER_START - if OUTPUT_LINE_NUMBERS is True: - line = LINENR - LINENR += LINE_NUMBER_STEP - return "N{:03d} ".format(line) - return "" def parse(pathobj): - global PRECISION - global MODAL - global REPEAT_ARGUMENTS - global UNIT_FORMAT - global UNIT_SPEED_FORMAT + out = "" + lastcommand = None + precision_string = '.' + str(PRECISION) + 'f' + currLocation = {} # keep track for no doubles - out = "" - lastcommand = None - precision_string = '.' + str(PRECISION) +'f' - currLocation = {} # keep track for no doubles + # The params list control the order of parameters + params = ['X', 'Y', 'Z', 'A', 'B', 'C', 'I', 'J', 'K', 'R', 'F', 'S', 'T', 'H', 'L', 'Q'] + firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0}) + currLocation.update(firstmove.Parameters) # set First location Parameters - # The params list control the order of parameters - params = ['X', 'Y', 'Z', 'A', 'B', 'C', 'I', 'J', 'K', 'R', 'F', 'S', 'T', 'H', 'L', 'Q'] - firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0}) - currLocation.update(firstmove.Parameters) # set First location Parameters + if hasattr(pathobj, "Group"): + # We have a compound or project. - if hasattr(pathobj, "Group"): - # We have a compound or project. + # if OUTPUT_COMMENTS: + # out += linenumber() + "(compound: " + pathobj.Label + ")\n" + for p in pathobj.Group: + out += parse(p) + return out + else: + # parsing simple path - #if OUTPUT_COMMENTS: - # out += linenumber() + "(compound: " + pathobj.Label + ")\n" - for p in pathobj.Group: - out += parse(p) - return out - else: - # parsing simple path + # groups might contain non-path things like stock. + if not hasattr(pathobj, "Path"): + return out - # groups might contain non-path things like stock. - if not hasattr(pathobj, "Path"): - return out + # if OUTPUT_COMMENTS: + # out += linenumber() + "(" + pathobj.Label + ")\n" - #if OUTPUT_COMMENTS: - # out += linenumber() + "(" + pathobj.Label + ")\n" + for c in pathobj.Path.Commands: + commandlist = [] # list of elements in the command, code and params. + command = c.Name.strip() # command M or G code or comment string + commandlist.append(command) - for c in pathobj.Path.Commands: - commandlist = [] # list of elements in the command, code and params. - command = c.Name.strip() # command M or G code or comment string - commandlist.append(command) + # if modal: only print the command if it is not the same as the last one + if MODAL is True: + if command == lastcommand: + commandlist.pop(0) - # if modal: only print the command if it is not the same as the last one - if MODAL is True: - if command == lastcommand: - commandlist.pop(0) + if c.Name[0] == '(' and not OUTPUT_COMMENTS: # command is a comment + continue - if c.Name[0] == '(' and not OUTPUT_COMMENTS: # command is a comment - continue + # Now add the remaining parameters in order + for param in params: + if param in c.Parameters: + if param == 'F' and (currLocation[param] != c.Parameters[param] or REPEAT_ARGUMENTS): + if c.Name not in ["G0", "G00"]: # No F in G0 + speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity) + if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0: + commandlist.append( + param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), + precision_string)) + else: + continue + elif param == 'T': + commandlist.append(param + str(int(c.Parameters['T']))) + elif param == 'H': + commandlist.append(param + str(int(c.Parameters['H']))) + elif param == 'D': + commandlist.append(param + str(int(c.Parameters['D']))) + elif param == 'S': + commandlist.append(param + str(int(c.Parameters['S']))) + else: + if (not REPEAT_ARGUMENTS) and (param in currLocation) and (currLocation[param] == c.Parameters[param]): + continue + else: + pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length) + commandlist.append(param + format(float(pos.getValueAs(UNIT_FORMAT)), + precision_string)) - # Now add the remaining parameters in order - for param in params: - if param in c.Parameters: - if param == 'F' and (currLocation[param] != c.Parameters[param] or REPEAT_ARGUMENTS): - if c.Name not in ["G0", "G00"]: # No F in G0 - speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity) - if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0: - commandlist.append(param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string)) - else: - continue - elif param == 'T': - commandlist.append(param + str(int(c.Parameters['T']))) - elif param == 'H': - commandlist.append(param + str(int(c.Parameters['H']))) - elif param == 'D': - commandlist.append(param + str(int(c.Parameters['D']))) - elif param == 'S': - commandlist.append(param + str(int(c.Parameters['S']))) - else: - if (not REPEAT_ARGUMENTS) and (param in currLocation) and (currLocation[param] == c.Parameters[param]): - continue - else: - pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length) - commandlist.append(param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string)) + # store the latest command + lastcommand = command + currLocation.update(c.Parameters) - # store the latest command - lastcommand = command - currLocation.update(c.Parameters) + # Check for Tool Change: + if command == 'M6': + for line in TOOL_CHANGE.splitlines(True): + out += linenumber() + line - # Check for Tool Change: - if command == 'M6': - for line in TOOL_CHANGE.splitlines(True): - out += linenumber() + line + # add height offset + if USE_TLO: + tool_height = '\nG43 H' + str(int(c.Parameters['T'])) + commandlist.append(tool_height) - # add height offset - if USE_TLO: - tool_height = '\nG43 H' + str(int(c.Parameters['T'])) - commandlist.append(tool_height) + if command == "message": + if OUTPUT_COMMENTS is False: + out = [] + else: + commandlist.pop(0) # remove the command - if command == "message": - if OUTPUT_COMMENTS is False: - out = [] - else: - commandlist.pop(0) # remove the command + # prepend a line number and append a newline + if len(commandlist) >= 1: + if OUTPUT_LINE_NUMBERS: + commandlist.insert(0, (linenumber())) - # prepend a line number and append a newline - if len(commandlist) >= 1: - if OUTPUT_LINE_NUMBERS: - commandlist.insert(0, (linenumber())) + # append the line to the final output + for w in commandlist: + out += w.strip() + COMMAND_SPACE + if (trace_gcode): + print("parse : >>{}".format(out)) + out = out.strip() + "\n" - # append the line to the final output - for w in commandlist: - out += w.strip() + COMMAND_SPACE - if (trace_gcode): - print("parse : >>{}".format(out)) - out = out.strip() + "\n" + return out - return out print(__name__ + " for " + GCODE_PROCESSOR + " loaded.") -