From ecc3994337c10366a1761130ac7e197d9aee84f2 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 1 Jul 2019 12:02:45 -0500 Subject: [PATCH] path: LGTM cleanup post processors --- src/Mod/Path/PathScripts/PathAdaptiveGui.py | 88 ++++---- .../Path/PathScripts/post/centroid_post.py | 72 +++---- .../Path/PathScripts/post/comparams_post.py | 103 +++++----- src/Mod/Path/PathScripts/post/example_pre.py | 41 ++-- src/Mod/Path/PathScripts/post/fablin_post.py | 188 +++++++++--------- 5 files changed, 236 insertions(+), 256 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathAdaptiveGui.py b/src/Mod/Path/PathScripts/PathAdaptiveGui.py index b35bcbe28f..9f96913722 100644 --- a/src/Mod/Path/PathScripts/PathAdaptiveGui.py +++ b/src/Mod/Path/PathScripts/PathAdaptiveGui.py @@ -19,14 +19,11 @@ # * * # ***************************************************************************/ -import FreeCAD -import FreeCADGui -import PathScripts.PathLog as PathLog -import PathScripts.PathGui as PathGui import PathScripts.PathOpGui as PathOpGui from PySide import QtCore, QtGui import PathScripts.PathAdaptive as PathAdaptive + class TaskPanelOpPage(PathOpGui.TaskPanelPage): def initPage(self, obj): self.setTitle("Adaptive path operation") @@ -35,39 +32,39 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): form = QtGui.QWidget() layout = QtGui.QVBoxLayout() - #tool controller + # tool controller hlayout = QtGui.QHBoxLayout() form.ToolController = QtGui.QComboBox() - form.ToolControllerLabel=QtGui.QLabel("Tool Controller") + form.ToolControllerLabel = QtGui.QLabel("Tool Controller") hlayout.addWidget(form.ToolControllerLabel) hlayout.addWidget(form.ToolController) layout.addLayout(hlayout) - #cut region + # cut region formLayout = QtGui.QFormLayout() form.Side = QtGui.QComboBox() form.Side.addItem("Inside") form.Side.addItem("Outside") form.Side.setToolTip("Cut inside or outside of the selected shapes") - formLayout.addRow(QtGui.QLabel("Cut Region"),form.Side) + formLayout.addRow(QtGui.QLabel("Cut Region"), form.Side) - #operation type + # operation type form.OperationType = QtGui.QComboBox() form.OperationType.addItem("Clearing") form.OperationType.addItem("Profiling") form.OperationType.setToolTip("Type of adaptive operation") - formLayout.addRow(QtGui.QLabel("Operation Type"),form.OperationType) + formLayout.addRow(QtGui.QLabel("Operation Type"), form.OperationType) - #step over + # step over form.StepOver = QtGui.QSpinBox() form.StepOver.setMinimum(15) form.StepOver.setMaximum(75) form.StepOver.setSingleStep(1) form.StepOver.setValue(25) form.StepOver.setToolTip("Optimal value for tool stepover") - formLayout.addRow(QtGui.QLabel("Step Over Percent"),form.StepOver) + formLayout.addRow(QtGui.QLabel("Step Over Percent"), form.StepOver) - #tolerance + # tolerance form.Tolerance = QtGui.QSlider(QtCore.Qt.Horizontal) form.Tolerance.setMinimum(5) form.Tolerance.setMaximum(15) @@ -75,67 +72,62 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): form.Tolerance.setValue(10) form.Tolerance.setTickPosition(QtGui.QSlider.TicksBelow) form.Tolerance.setToolTip("Influences calculation performance vs stability and accuracy.") - formLayout.addRow(QtGui.QLabel("Accuracy vs Performance"),form.Tolerance) + formLayout.addRow(QtGui.QLabel("Accuracy vs Performance"), form.Tolerance) - #helix angle + # helix angle form.HelixAngle = QtGui.QDoubleSpinBox() form.HelixAngle.setMinimum(0.1) form.HelixAngle.setMaximum(90) form.HelixAngle.setSingleStep(0.1) form.HelixAngle.setValue(5) form.HelixAngle.setToolTip("Angle of the helix ramp entry") - formLayout.addRow(QtGui.QLabel("Helix Ramp Angle"),form.HelixAngle) + formLayout.addRow(QtGui.QLabel("Helix Ramp Angle"), form.HelixAngle) - #helix diam. limit + # helix diam. limit form.HelixDiameterLimit = QtGui.QDoubleSpinBox() form.HelixDiameterLimit.setMinimum(0.0) form.HelixDiameterLimit.setMaximum(90) form.HelixDiameterLimit.setSingleStep(0.1) form.HelixDiameterLimit.setValue(0) form.HelixDiameterLimit.setToolTip("If >0 it limits the helix ramp diameter\notherwise the 75 percent of tool diameter is used as helix diameter") - formLayout.addRow(QtGui.QLabel("Helix Max Diameter"),form.HelixDiameterLimit) + formLayout.addRow(QtGui.QLabel("Helix Max Diameter"), form.HelixDiameterLimit) - #lift distance + # lift distance form.LiftDistance = QtGui.QDoubleSpinBox() form.LiftDistance.setMinimum(0.0) form.LiftDistance.setMaximum(1000) form.LiftDistance.setSingleStep(0.1) form.LiftDistance.setValue(1.0) form.LiftDistance.setToolTip("How much to lift the tool up during the rapid linking moves over cleared regions.\nIf linking path is not clear tool is raised to clearence height.") - formLayout.addRow(QtGui.QLabel("Lift Distance"),form.LiftDistance) + formLayout.addRow(QtGui.QLabel("Lift Distance"), form.LiftDistance) - #KeepToolDownRatio + # KeepToolDownRatio form.KeepToolDownRatio = QtGui.QDoubleSpinBox() form.KeepToolDownRatio.setMinimum(1.0) form.KeepToolDownRatio.setMaximum(10) form.KeepToolDownRatio.setSingleStep(1) form.KeepToolDownRatio.setValue(3.0) form.KeepToolDownRatio.setToolTip("Max length of keep-tool-down linking path compared to direct distance between points.\nIf exceeded link will be done by raising the tool to clearence height.") - formLayout.addRow(QtGui.QLabel("Keep Tool Down Ratio"),form.KeepToolDownRatio) + formLayout.addRow(QtGui.QLabel("Keep Tool Down Ratio"), form.KeepToolDownRatio) - #stock to leave + # stock to leave form.StockToLeave = QtGui.QDoubleSpinBox() form.StockToLeave.setMinimum(0.0) form.StockToLeave.setMaximum(1000) form.StockToLeave.setSingleStep(0.1) form.StockToLeave.setValue(0) form.StockToLeave.setToolTip("How much material to leave (i.e. for finishing operation)") - formLayout.addRow(QtGui.QLabel("Stock to Leave"),form.StockToLeave) + formLayout.addRow(QtGui.QLabel("Stock to Leave"), form.StockToLeave) - # #process holes - # form.ProcessHoles = QtGui.QCheckBox() - # form.ProcessHoles.setChecked(True) - # formLayout.addRow(QtGui.QLabel("Process Holes"),form.ProcessHoles) - - #Force inside out + # Force inside out form.ForceInsideOut = QtGui.QCheckBox() form.ForceInsideOut.setChecked(True) - formLayout.addRow(QtGui.QLabel("Force Clearing Inside-Out"),form.ForceInsideOut) + formLayout.addRow(QtGui.QLabel("Force Clearing Inside-Out"), form.ForceInsideOut) layout.addLayout(formLayout) - #stop button - form.StopButton=QtGui.QPushButton("Stop") + # stop button + form.StopButton = QtGui.QPushButton("Stop") form.StopButton.setCheckable(True) layout.addWidget(form.StopButton) @@ -145,7 +137,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): def getSignalsForUpdate(self, obj): '''getSignalsForUpdate(obj) ... return list of signals for updating obj''' signals = [] - #signals.append(self.form.button.clicked) + # signals.append(self.form.button.clicked) signals.append(self.form.Side.currentIndexChanged) signals.append(self.form.OperationType.currentIndexChanged) signals.append(self.form.ToolController.currentIndexChanged) @@ -166,7 +158,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): self.selectInComboBox(obj.Side, self.form.Side) self.selectInComboBox(obj.OperationType, self.form.OperationType) self.form.StepOver.setValue(obj.StepOver) - self.form.Tolerance.setValue(int(obj.Tolerance*100)) + self.form.Tolerance.setValue(int(obj.Tolerance * 100)) self.form.HelixAngle.setValue(obj.HelixAngle) self.form.HelixDiameterLimit.setValue(obj.HelixDiameterLimit) self.form.LiftDistance.setValue(obj.LiftDistance) @@ -180,8 +172,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): self.form.ForceInsideOut.setChecked(obj.ForceInsideOut) self.setupToolController(obj, self.form.ToolController) self.form.StopButton.setChecked(obj.Stopped) - obj.setEditorMode('AdaptiveInputState', 2) #hide this property - obj.setEditorMode('AdaptiveOutputState', 2) #hide this property + obj.setEditorMode('AdaptiveInputState', 2) # hide this property + obj.setEditorMode('AdaptiveOutputState', 2) # hide this property obj.setEditorMode('StopProcessing', 2) # hide this property obj.setEditorMode('Stopped', 2) # hide this property @@ -193,7 +185,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): obj.OperationType = str(self.form.OperationType.currentText()) obj.StepOver = self.form.StepOver.value() - obj.Tolerance = 1.0*self.form.Tolerance.value()/100.0 + obj.Tolerance = 1.0 * self.form.Tolerance.value() / 100.0 obj.HelixAngle = self.form.HelixAngle.value() obj.HelixDiameterLimit = self.form.HelixDiameterLimit.value() obj.LiftDistance = self.form.LiftDistance.value() @@ -204,25 +196,19 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): if hasattr(obj, 'StockToLeave'): obj.StockToLeave = self.form.StockToLeave.value() - # obj.ProcessHoles = self.form.ProcessHoles.isChecked() obj.ForceInsideOut = self.form.ForceInsideOut.isChecked() obj.Stopped = self.form.StopButton.isChecked() if(obj.Stopped): - self.form.StopButton.setChecked(False) #reset the button - obj.StopProcessing=True + self.form.StopButton.setChecked(False) # reset the button + obj.StopProcessing = True self.updateToolController(obj, self.form.ToolController) - obj.setEditorMode('AdaptiveInputState', 2) #hide this property - obj.setEditorMode('AdaptiveOutputState', 2) #hide this property + obj.setEditorMode('AdaptiveInputState', 2) # hide this property + obj.setEditorMode('AdaptiveOutputState', 2) # hide this property obj.setEditorMode('StopProcessing', 2) # hide this property obj.setEditorMode('Stopped', 2) # hide this property - - -Command = PathOpGui.SetupOperation('Adaptive', - PathAdaptive.Create, - TaskPanelOpPage, - 'Path-Adaptive', - QtCore.QT_TRANSLATE_NOOP("PathAdaptive", "Adaptive"), - QtCore.QT_TRANSLATE_NOOP("PathPocket", "Adaptive clearing and profiling")) +Command = PathOpGui.SetupOperation('Adaptive', PathAdaptive.Create, TaskPanelOpPage, + 'Path-Adaptive', QtCore.QT_TRANSLATE_NOOP("PathAdaptive", "Adaptive"), + QtCore.QT_TRANSLATE_NOOP("PathPocket", "Adaptive clearing and profiling")) diff --git a/src/Mod/Path/PathScripts/post/centroid_post.py b/src/Mod/Path/PathScripts/post/centroid_post.py index 3ea3a7ec84..a0f92b7b7e 100644 --- a/src/Mod/Path/PathScripts/post/centroid_post.py +++ b/src/Mod/Path/PathScripts/post/centroid_post.py @@ -21,8 +21,13 @@ # * * # ***************************************************************************/ from __future__ import print_function +import FreeCAD +from FreeCAD import Units +import datetime +import PathScripts +PostUtils = PathScripts.PostUtils -TOOLTIP=''' +TOOLTIP = ''' 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 real GCode suitable for a centroid 3 axis mill. This postprocessor, once placed @@ -33,7 +38,7 @@ import centroid_post centroid_post.export(object,"/path/to/file.ncc","") ''' -TOOLTIP_ARGS=''' +TOOLTIP_ARGS = ''' Arguments for centroid: --header,--no-header ... output headers (--header) --comments,--no-comments ... output comments (--comments) @@ -42,13 +47,6 @@ Arguments for centroid: --feed-precision=1 ... number of digits of precision for feed rate. Default=1 --axis-precision=4 ... number of digits of precision for axis moves. Default=4 ''' -import FreeCAD -from FreeCAD import Units -import datetime -import PathScripts -from PathScripts import PostUtils -#from PathScripts import PathUtils - now = datetime.datetime.now() # These globals set common customization preferences @@ -68,10 +66,10 @@ LINENR = 100 # line number starting value UNITS = "G20" # G21 for metric, G20 for us standard UNIT_FORMAT = 'mm/min' MACHINE_NAME = "Centroid" -CORNER_MIN = {'x':-609.6, 'y':-152.4, 'z':0 } #use metric for internal units -CORNER_MAX = {'x':609.6, 'y':152.4, 'z':304.8 } #use metric for internal units -AXIS_PRECISION=4 -FEED_PRECISION=1 +CORNER_MIN = {'x': -609.6, 'y': -152.4, 'z': 0} # use metric for internal units +CORNER_MAX = {'x': 609.6, 'y': 152.4, 'z': 304.8} # use metric for internal units +AXIS_PRECISION = 4 +FEED_PRECISION = 1 SPINDLE_DECIMALS = 0 COMMENT = ";" @@ -93,7 +91,7 @@ POSTAMBLE = '''M99 TOOLRETURN = '''M5 M25 G49 H0 -''' #spindle off,height offset canceled,spindle retracted (M25 is a centroid command to retract spindle) +''' # spindle off,height offset canceled,spindle retracted (M25 is a centroid command to retract spindle) ZAXISRETURN = '''G91 G28 X0 Z0 G90 @@ -113,9 +111,10 @@ TOOL_CHANGE = '''''' # to distinguish python built-in open function from the one declared below -if open.__module__ in ['__builtin__','io']: +if open.__module__ in ['__builtin__', 'io']: pythonopen = open + def processArguments(argstring): global OUTPUT_HEADER global OUTPUT_COMMENTS @@ -146,22 +145,14 @@ def processArguments(argstring): elif arg.split('=')[0] == '--feed-precision': FEED_PRECISION = arg.split('=')[1] + def export(objectslist, filename, argstring): processArguments(argstring) for i in objectslist: - print (i.Name) + print(i.Name) global UNITS global UNIT_FORMAT - # ISJOB = (len(objectslist) == 1) and isinstance(objectslist[0].Proxy, PathScripts.PathJob.ObjectJob) - # print("isjob: {} {}".format(ISJOB, len(objectslist))) - - # if len(objectslist) > 1: - # 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 - print("postprocessing...") gcode = "" @@ -174,7 +165,7 @@ def export(objectslist, filename, argstring): # Write the preamble if OUTPUT_COMMENTS: for item in objectslist: - if isinstance (item.Proxy, PathScripts.PathToolController.ToolController): + if isinstance(item.Proxy, PathScripts.PathToolController.ToolController): gcode += ";T{}={}\n".format(item.ToolNumber, item.Name) gcode += linenumber() + ";begin preamble\n" for line in PREAMBLE.splitlines(True): @@ -183,11 +174,6 @@ def export(objectslist, filename, argstring): gcode += linenumber() + UNITS + "\n" for obj in objectslist: - #skip postprocessing tools - # if isinstance (obj.Proxy, PathScripts.PathToolController.ToolController): - # continue - - # do the pre_op if OUTPUT_COMMENTS: gcode += linenumber() + ";begin operation\n" @@ -241,13 +227,14 @@ def linenumber(): return "N" + str(LINENR) + " " return "" + def parse(pathobj): global AXIS_PRECISION global FEED_PRECISION out = "" lastcommand = None - axis_precision_string = '.' + str(AXIS_PRECISION) +'f' - feed_precision_string = '.' + str(FEED_PRECISION) +'f' + axis_precision_string = '.' + str(AXIS_PRECISION) + 'f' + feed_precision_string = '.' + str(FEED_PRECISION) + 'f' # params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control # the order of parameters # centroid doesn't want K properties on XY plane Arcs need work. @@ -269,10 +256,10 @@ def parse(pathobj): # out += linenumber() + "(" + pathobj.Label + ")\n" for c in pathobj.Path.Commands: - commandlist = [] #list of elements in the command, code and params. - command = c.Name #command M or G code or comment string + commandlist = [] # list of elements in the command, code and params. + command = c.Name # command M or G code or comment string - if command[0]=='(': + if command[0] == '(': command = PostUtils.fcoms(command, COMMENT) commandlist.append(command) @@ -286,10 +273,10 @@ def parse(pathobj): for param in params: if param in c.Parameters: if param == 'F': - if c.Name not in ["G0", "G00"]: #centroid doesn't use rapid speeds + if c.Name not in ["G0", "G00"]: # centroid doesn't use rapid speeds speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity) commandlist.append( - param + format(float(speed.getValueAs(UNIT_FORMAT)), feed_precision_string) ) + param + format(float(speed.getValueAs(UNIT_FORMAT)), feed_precision_string)) elif param == 'H': commandlist.append(param + str(int(c.Parameters['H']))) elif param == 'S': @@ -300,11 +287,10 @@ def parse(pathobj): commandlist.append( param + format(c.Parameters[param], axis_precision_string)) outstr = str(commandlist) - outstr =outstr.replace('[','') - outstr =outstr.replace(']','') - outstr =outstr.replace("'",'') - outstr =outstr.replace(",",'') - #out += outstr + '\n' + outstr = outstr.replace('[', '') + outstr = outstr.replace(']', '') + outstr = outstr.replace("'", '') + outstr = outstr.replace(",", '') # store the latest command lastcommand = command diff --git a/src/Mod/Path/PathScripts/post/comparams_post.py b/src/Mod/Path/PathScripts/post/comparams_post.py index b8a5fd6b27..2476118959 100644 --- a/src/Mod/Path/PathScripts/post/comparams_post.py +++ b/src/Mod/Path/PathScripts/post/comparams_post.py @@ -1,44 +1,48 @@ # -*- coding: utf-8 -*- -#*************************************************************************** -#* * -#* Copyright (c) 2015 Dan Falck * -#* * -#* 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 * -#* * -#*************************************************************************** -TOOLTIP=''' Example Post, using Path.Commands instead of Path.toGCode strings for Path gcode output. ''' - +# *************************************************************************** +# * * +# * Copyright (c) 2015 Dan Falck * +# * * +# * 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 * +# * * +# *************************************************************************** import FreeCAD -import Path, PathScripts -from PathScripts import PostUtils +import Path +import PathScripts +PostUtils = PathScripts.PostUtils + +TOOLTIP = ''' Example Post, using Path.Commands instead of Path.toGCode strings for Path gcode output. ''' + +SHOW_EDITOR = True -SHOW_EDITOR=True def fmt(num): fnum = "" fnum += '%.3f' % (num) return fnum + def ffmt(num): fnum = "" fnum += '%.1f' % (num) return fnum + class saveVals(object): ''' save command info for modal output''' def __init__(self, command): @@ -48,54 +52,55 @@ class saveVals(object): def retVals(self): return self.com, self.params + def lineout(command, oldvals, modal): line = "" if modal and (oldvals.com == command.Name): - line +="" + line += "" else: line += str(command.Name) if command.Name == 'M6': - line+= 'T'+str(int(command.Parameters['T'])) + line += 'T' + str(int(command.Parameters['T'])) if command.Name == 'M3': - line+= 'S'+str(ffmt(command.Parameters['S'])) + line += 'S' + str(ffmt(command.Parameters['S'])) if command.Name == 'M4': - line+= 'S'+str(ffmt(command.Parameters['S'])) + line += 'S' + str(ffmt(command.Parameters['S'])) if 'X' in command.Parameters: - line += "X"+str(fmt(command.Parameters['X'])) + line += "X" + str(fmt(command.Parameters['X'])) if 'Y' in command.Parameters: - line += "Y"+str(fmt(command.Parameters['Y'])) + line += "Y" + str(fmt(command.Parameters['Y'])) if 'Z' in command.Parameters: - line += "Z"+str(fmt(command.Parameters['Z'])) + line += "Z" + str(fmt(command.Parameters['Z'])) if 'I' in command.Parameters: - line += "I"+str(fmt(command.Parameters['I'])) + line += "I" + str(fmt(command.Parameters['I'])) if 'J' in command.Parameters: - line += "J"+str(fmt(command.Parameters['J'])) + line += "J" + str(fmt(command.Parameters['J'])) if 'F' in command.Parameters: - line += "F"+str(ffmt(command.Parameters['F'])) + line += "F" + str(ffmt(command.Parameters['F'])) return line -def export(obj,filename,argstring): - modal=True - commands = obj[0] + +def export(obj, filename, argstring): + modal = True gcode = '' safetyblock1 = 'G90G40G49\n' - gcode+=safetyblock1 + gcode += safetyblock1 units = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units") if units.GetInt('UserSchema') == 0: - firstcommand = Path.Command('G21') #metric mode + firstcommand = Path.Command('G21') # metric mode else: - firstcommand = Path.Command('G20') #inch mode - oldvals = saveVals(firstcommand) #save first command for modal use + firstcommand = Path.Command('G20') # inch mode + oldvals = saveVals(firstcommand) # save first command for modal use fp = obj[0] - gcode+= firstcommand.Name + gcode += firstcommand.Name - if hasattr(fp,"Path"): + if hasattr(fp, "Path"): for c in fp.Path.Commands: - gcode+= lineout(c, oldvals, modal)+'\n' + gcode += lineout(c, oldvals, modal) + '\n' oldvals = saveVals(c) - gcode+='M2\n' - gfile = open(filename,"w") + gcode += 'M2\n' + gfile = open(filename, "w") gfile.write(gcode) gfile.close() else: @@ -106,5 +111,3 @@ def export(obj,filename,argstring): dia = PostUtils.GCodeEditorDialog() dia.editor.setText(gcode) dia.exec_() - - diff --git a/src/Mod/Path/PathScripts/post/example_pre.py b/src/Mod/Path/PathScripts/post/example_pre.py index c3a7e95680..42197b7a8b 100644 --- a/src/Mod/Path/PathScripts/post/example_pre.py +++ b/src/Mod/Path/PathScripts/post/example_pre.py @@ -36,15 +36,16 @@ import Path import FreeCAD import PathScripts.PathLog as PathLog -if False: - PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) +# LEVEL = PathLog.Level.DEBUG +LEVEL = PathLog.Level.INFO +PathLog.setLevel(LEVEL, PathLog.thisModule()) + +if LEVEL == PathLog.Level.DEBUG: PathLog.trackModule(PathLog.thisModule()) -else: - PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) # to distinguish python built-in open function from the one declared below -if open.__module__ in ['__builtin__','io']: +if open.__module__ in ['__builtin__', 'io']: pythonopen = open @@ -68,6 +69,7 @@ def insert(filename, docname): path = Path.Path(gcode) obj.Path = path + def parse(inputstring): "parse(inputstring): returns a parsed output string" print("preprocessing...") @@ -77,31 +79,30 @@ def parse(inputstring): lines = inputstring.split("\n") output = "" lastcommand = None - print (lines) + print(lines) - for l in lines: + for lin in lines: # remove any leftover trailing and preceding spaces - l = l.strip() - if not l: + lin = lin.strip() + if not lin: # discard empty lines continue - if l[0].upper() in ["N"]: + if lin[0].upper() in ["N"]: # remove line numbers - l = l.split(" ",1) - if len(l)>=1: - l = l[1] + lin = lin.split(" ", 1) + if len(lin) >= 1: + lin = lin[1] else: continue - - if l[0] in ["(","%","#",";"]: + if lin[0] in ["(", "%", "#", ";"]: # discard comment and other non strictly gcode lines continue - if l[0].upper() in ["G","M"]: + if lin[0].upper() in ["G", "M"]: # found a G or M command: we store it - output += l + "\n" - last = l[0].upper() - for c in l[1:]: + output += lin + "\n" + last = lin[0].upper() + for c in lin[1:]: if not c.isdigit(): break else: @@ -109,7 +110,7 @@ def parse(inputstring): lastcommand = last elif lastcommand: # no G or M command: we repeat the last one - output += lastcommand + " " + l + "\n" + output += lastcommand + " " + lin + "\n" print("done preprocessing.") return output diff --git a/src/Mod/Path/PathScripts/post/fablin_post.py b/src/Mod/Path/PathScripts/post/fablin_post.py index ac06969344..f2dccb795b 100644 --- a/src/Mod/Path/PathScripts/post/fablin_post.py +++ b/src/Mod/Path/PathScripts/post/fablin_post.py @@ -1,29 +1,32 @@ -#*************************************************************************** -#* (c) imarin 2017 * -#* * -#* heavily based on gbrl post-procesor by: * -#* (c) sliptonic (shopinthewoods@gmail.com) 2014 * -#* * -#* This file is part of the FreeCAD CAx development system. * -#* * -#* 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. * -#* * -#* FreeCAD 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 Lesser General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with FreeCAD; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#***************************************************************************/ +# *************************************************************************** +# * (c) imarin 2017 * +# * * +# * heavily based on gbrl post-procesor by: * +# * (c) sliptonic (shopinthewoods@gmail.com) 2014 * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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. * +# * * +# * FreeCAD 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 Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# ***************************************************************************/ +import datetime +from PathScripts import PostUtils +now = datetime.datetime.now() ''' Generate g-code compatible with fablin from a Path. @@ -32,7 +35,7 @@ import fablin_post fablin_post.export(object,"/path/to/file.ncc") ''' -TOOLTIP_ARGS=''' +TOOLTIP_ARGS = ''' Arguments for fablin: --rapids-feedrate ... feedrate to be used for rapids (e.g. --rapids-feedrate=300) --header,--no-header ... output headers (--header) @@ -41,59 +44,55 @@ Arguments for fablin: --show-editor, --no-show-editor ... pop up editor before writing output(--show-editor) ''' -import datetime -now = datetime.datetime.now() -from PathScripts import PostUtils - -#These globals set common customization preferences -OUTPUT_COMMENTS = False # Fablin does not support parenthesis, it will echo the command complaining. As a side effect the spinner may turn at a very reduced speed (do not ask me why). -OUTPUT_HEADER = False # Same as above. You can enable this by passing arguments to the post-processor in case you need them for example for debugging the gcode. +# These globals set common customization preferences +OUTPUT_COMMENTS = False # Fablin does not support parenthesis, it will echo the command complaining. As a side effect the spinner may turn at a very reduced speed (do not ask me why). +OUTPUT_HEADER = False # Same as above. You can enable this by passing arguments to the post-processor in case you need them for example for debugging the gcode. OUTPUT_LINE_NUMBERS = False OUTPUT_TOOL_CHANGE = False SHOW_EDITOR = True -MODAL = False #if true commands are suppressed if the same as previous line. +MODAL = False # if true commands are suppressed if the same as previous line. COMMAND_SPACE = " " -LINENR = 100 #line number starting value +LINENR = 100 # line number starting value -#These globals will be reflected in the Machine configuration of the project -UNITS = "" # only metric, G20/G21 is ignored +# These globals will be reflected in the Machine configuration of the project +UNITS = "" # only metric, G20/G21 is ignored MACHINE_NAME = "FABLIN" -CORNER_MIN = {'x':0, 'y':0, 'z':0 } -CORNER_MAX = {'x':500, 'y':300, 'z':300 } +CORNER_MIN = {'x': 0, 'y': 0, 'z': 0} +CORNER_MAX = {'x': 500, 'y': 300, 'z': 300} RAPID_MOVES = ['G0', 'G00'] -#RAPID_MOVES = [] RAPID_FEEDRATE = 10000 -#Preamble text will appear at the beginning of the GCODE output file. +# Preamble text will appear at the beginning of the GCODE output file. PREAMBLE = '''G90 ''' -#Postamble text will appear following the last operation. +# Postamble text will appear following the last operation. POSTAMBLE = '''M5 G00 X-1.0 Y1.0 G90 ''' # These commands are ignored by commenting them out -SUPPRESS_COMMANDS = [ 'G98', 'G80', 'M6', 'G17' ] +SUPPRESS_COMMANDS = ['G98', 'G80', 'M6', 'G17'] -#Pre operation text will be inserted before every operation +# Pre operation text will be inserted before every operation PRE_OPERATION = '''''' -#Post operation text will be inserted after every operation +# Post operation text will be inserted after every operation POST_OPERATION = '''''' -#Tool Change commands will be inserted before a tool change +# Tool Change commands will be inserted before a tool change TOOL_CHANGE = '''''' # to distinguish python built-in open function from the one declared below -if open.__module__ in ['__builtin__','io']: +if open.__module__ in ['__builtin__', 'io']: pythonopen = open + def processArguments(argstring): global OUTPUT_HEADER global OUTPUT_COMMENTS @@ -123,64 +122,67 @@ def processArguments(argstring): if params[0] == '--rapids-feedrate': RAPID_FEEDRATE = params[1] -def export(objectslist,filename,argstring): + +def export(objectslist, filename, argstring): processArguments(argstring) global UNITS for obj in objectslist: - if not hasattr(obj,"Path"): - print ("the object " + obj.Name + " is not a path. Please select only path and Compounds.") + if not hasattr(obj, "Path"): + print("the object " + obj.Name + " is not a path. Please select only path and Compounds.") return - print ("postprocessing...") + print("postprocessing...") gcode = "" - #Find the machine. - #The user my have overridden post processor defaults in the GUI. - #Make sure we're using the current values in the Machine Def. + # Find the machine. + # The user my have overridden post processor defaults in the GUI. + # Make sure we're using the current values in the Machine Def. myMachine = None for pathobj in objectslist: - if hasattr(pathobj,"Group"): #We have a compound or project. + if hasattr(pathobj, "Group"): # We have a compound or project. for p in pathobj.Group: if p.Name == "Machine": myMachine = p if myMachine is None: - print ("No machine found in this project") + print("No machine found in this project") else: if myMachine.MachineUnits == "Metric": - UNITS = "G21" + UNITS = "G21" else: - UNITS = "G20" - + UNITS = "G20" # write header if OUTPUT_HEADER: gcode += linenumber() + "(Exported by FreeCAD)\n" - gcode += linenumber() + "(Post Processor: " + __name__ +")\n" - gcode += linenumber() + "(Output Time:"+str(now)+")\n" + gcode += linenumber() + "(Post Processor: " + __name__ + ")\n" + gcode += linenumber() + "(Output Time:" + str(now) + ")\n" - #Write the preamble - if OUTPUT_COMMENTS: gcode += linenumber() + "(begin preamble)\n" + # Write the preamble + if OUTPUT_COMMENTS: + gcode += linenumber() + "(begin preamble)\n" for line in PREAMBLE.splitlines(True): gcode += linenumber() + line - #gcode += linenumber() + UNITS + "\n" for obj in objectslist: - #do the pre_op - if OUTPUT_COMMENTS: gcode += linenumber() + "(begin operation: " + obj.Label + ")\n" + # do the pre_op + if OUTPUT_COMMENTS: + gcode += linenumber() + "(begin operation: " + obj.Label + ")\n" for line in PRE_OPERATION.splitlines(True): gcode += linenumber() + line gcode += parse(obj) - #do the post_op - if OUTPUT_COMMENTS: gcode += linenumber() + "(finish operation: " + obj.Label + ")\n" + # do the post_op + if OUTPUT_COMMENTS: + gcode += linenumber() + "(finish operation: " + obj.Label + ")\n" for line in POST_OPERATION.splitlines(True): gcode += linenumber() + line - #do the post_amble + # do the post_amble - if OUTPUT_COMMENTS: gcode += "(begin postamble)\n" + if OUTPUT_COMMENTS: + gcode += "(begin postamble)\n" for line in POSTAMBLE.splitlines(True): gcode += linenumber() + line @@ -195,38 +197,40 @@ def export(objectslist,filename,argstring): else: final = gcode - print ("done postprocessing.") + print("done postprocessing.") - gfile = pythonopen(filename,"w") - gfile.write(gcode) + gfile = pythonopen(filename, "w") + gfile.write(final) gfile.close() def linenumber(): global LINENR - if OUTPUT_LINE_NUMBERS == True: + if OUTPUT_LINE_NUMBERS is True: LINENR += 10 return "N" + str(LINENR) + " " return "" + def parse(pathobj): out = "" lastcommand = None - #params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control the order of parameters - params = ['X','Y','Z','A','B','I','J','F','S','T','Q','R','L'] #linuxcnc doesn't want K properties on XY plane Arcs need work. + params = ['X', 'Y', 'Z', 'A', 'B', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L'] # linuxcnc doesn't want K properties on XY plane Arcs need work. - if hasattr(pathobj,"Group"): #We have a compound or project. - if OUTPUT_COMMENTS: out += linenumber() + "(compound: " + pathobj.Label + ")\n" + 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 + else: # parsing simple path - if not hasattr(pathobj,"Path"): #groups might contain non-path things like stock. + if not hasattr(pathobj, "Path"): # groups might contain non-path things like stock. return out - if OUTPUT_COMMENTS: out += linenumber() + "(Path: " + pathobj.Label + ")\n" + if OUTPUT_COMMENTS: + out += linenumber() + "(Path: " + pathobj.Label + ")\n" for c in pathobj.Path.Commands: outstring = [] @@ -234,16 +238,16 @@ def parse(pathobj): # fablin does not support parenthesis syntax, so removing that (pocket) in the agnostic gcode if command[0] == '(': - if not OUTPUT_COMMENTS: pass + if not OUTPUT_COMMENTS: + pass else: outstring.append(command) # if modal: only print the command if it is not the same as the last one - if MODAL == True: + if MODAL is True: if command == lastcommand: outstring.pop(0) - # Now add the remaining parameters in order for param in params: if param in c.Parameters: @@ -263,7 +267,8 @@ def parse(pathobj): # Check for Tool Change: if command == 'M6': - if OUTPUT_COMMENTS: out += linenumber() + "(begin toolchange)\n" + if OUTPUT_COMMENTS: + out += linenumber() + "(begin toolchange)\n" if not OUTPUT_TOOL_CHANGE: outstring.insert(0, ";") else: @@ -271,20 +276,20 @@ def parse(pathobj): out += linenumber() + line if command == "message": - if OUTPUT_COMMENTS == False: + if OUTPUT_COMMENTS is False: out = [] else: - outstring.pop(0) #remove the command + outstring.pop(0) # remove the command if command in SUPPRESS_COMMANDS: outstring = [] - #prepend a line number and append a newline + # prepend a line number and append a newline if len(outstring) >= 1: if OUTPUT_LINE_NUMBERS: - outstring.insert(0,(linenumber())) + outstring.insert(0, (linenumber())) - #append the line to the final output + # append the line to the final output for w in outstring: out += w + COMMAND_SPACE out = out.strip() + "\n" @@ -292,5 +297,4 @@ def parse(pathobj): return out -print (__name__ + " gcode postprocessor loaded.") - +print(__name__ + " gcode postprocessor loaded.")