path: LGTM cleanup post processors
This commit is contained in:
@@ -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"))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,44 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2015 Dan Falck <ddfalck@gmail.com> *
|
||||
#* *
|
||||
#* 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 <ddfalck@gmail.com> *
|
||||
# * *
|
||||
# * 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_()
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.")
|
||||
|
||||
Reference in New Issue
Block a user