fixes from IchGucksLive for drilling simulation. Tweaks to linuxcnc post

This commit is contained in:
sliptonic
2018-01-04 13:50:07 -06:00
committed by Yorik van Havre
parent 0c54e0dc3a
commit 5bca294d16
2 changed files with 149 additions and 104 deletions

View File

@@ -1,6 +1,4 @@
import os
_filePath = os.path.dirname(os.path.abspath(__file__))
import FreeCAD
import Path
import Part
@@ -10,12 +8,15 @@ import math
from FreeCAD import Vector, Base
from PathScripts.PathGeom import PathGeom
_filePath = os.path.dirname(os.path.abspath(__file__))
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtGui, QtCore
#compiled with pyrcc4 -py3 Resources\CAM_Sim.qrc -o CAM_Sim_rc.py
# compiled with pyrcc4 -py3 Resources\CAM_Sim.qrc -o CAM_Sim_rc.py
class CAMSimTaskUi:
def __init__(self, parent):
# this will create a Qt widget from our ui file
@@ -30,20 +31,17 @@ class CAMSimTaskUi:
self.parent.cancel()
FreeCADGui.Control.closeDialog()
#for cmd in obj.Path.Commands:
# if cmd.Name[0] == 'G':
# e1 =
# print cmd.Name
def TSError(msg):
QtGui.QMessageBox.information(None,"Path Simulation",msg)
def TSError(msg):
QtGui.QMessageBox.information(None, "Path Simulation", msg)
class PathSimulation:
def __init__(self):
self.debug = False
self.timer = QtCore.QTimer()
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.PerformCut)
self.stdrot = FreeCAD.Rotation(Vector(0,0,1),0)
self.stdrot = FreeCAD.Rotation(Vector(0, 0, 1), 0)
self.iprogress = 0
self.numCommands = 0
self.simperiod = 20
@@ -71,23 +69,25 @@ class PathSimulation:
form.comboJobs.currentIndexChanged.connect(self.onJobChange)
jobList = FreeCAD.ActiveDocument.findObjects("Path::FeaturePython", "Job.*")
form.comboJobs.clear()
self.jobs = []
self.jobs = []
for j in jobList:
self.jobs.append(j)
form.comboJobs.addItem(j.ViewObject.Icon, j.Label)
FreeCADGui.Control.showDialog(self.taskForm)
self.disableAnim = False
self.isVoxel = True
self.firstDrill = True
self.voxSim = PathSimulator.PathSim()
self.SimulateMill()
def SetupSimulation(self):
form = self.taskForm.form
form = self.taskForm.form
self.activeOps = []
self.numCommands = 0
self.ioperation = 0
for i in range(form.listOperations.count()):
if form.listOperations.item(i).checkState() == QtCore.Qt.CheckState.Checked:
self.firstDrill = True
self.activeOps.append(self.operations[i])
self.numCommands += len(self.operations[i].Path.Commands)
if len(self.activeOps) == 0:
@@ -104,48 +104,47 @@ class PathSimulation:
self.busy = False
self.tool = None
for i in range(len(self.activeOps)):
self.SetupOperation(0)
if (self.tool is not None):
break
self.SetupOperation(0)
if (self.tool is not None):
break
self.iprogress = 0
self.UpdateProgress()
def SetupOperation(self, itool):
self.operation = self.activeOps[itool]
if hasattr(self.operation, "ToolController"):
self.tool = self.operation.ToolController.Tool
self.tool = self.operation.ToolController.Tool
if (self.tool is not None):
toolProf = self.CreateToolProfile(self.tool, Vector(0,1,0), Vector(0,0,0), self.tool.Diameter / 2.0)
self.cutTool.Shape = Part.makeSolid(toolProf.revolve(Vector(0,0,0), Vector(0,0,1)))
self.cutTool.ViewObject.show()
self.voxSim.SetCurrentTool(self.tool)
toolProf = self.CreateToolProfile(self.tool, Vector(0, 1, 0), Vector(0, 0, 0), self.tool.Diameter / 2.0)
self.cutTool.Shape = Part.makeSolid(toolProf.revolve(Vector(0, 0, 0), Vector(0, 0, 1)))
self.cutTool.ViewObject.show()
self.voxSim.SetCurrentTool(self.tool)
self.icmd = 0
self.curpos = FreeCAD.Placement(self.initialPos, self.stdrot)
#self.cutTool.Placement = FreeCAD.Placement(self.curpos, self.stdrot)
# self.cutTool.Placement = FreeCAD.Placement(self.curpos, self.stdrot)
self.cutTool.Placement = self.curpos
def SimulateMill(self):
self.job = self.jobs[self.taskForm.form.comboJobs.currentIndex()]
self.busy = False
#self.timer.start(100)
# self.timer.start(100)
self.height = 10
self.skipStep = False
self.initialPos = Vector(0, 0, self.job.Stock.Shape.BoundBox.ZMax)
# Add cut tool
self.cutTool = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","CutTool")
self.cutTool = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "CutTool")
self.cutTool.ViewObject.Proxy = 0
self.cutTool.ViewObject.hide()
# Add cut material
if self.isVoxel:
self.cutMaterial = FreeCAD.ActiveDocument.addObject("Mesh::FeaturePython","CutMaterial")
self.cutMaterialIn = FreeCAD.ActiveDocument.addObject("Mesh::FeaturePython","CutMaterialIn")
self.cutMaterial = FreeCAD.ActiveDocument.addObject("Mesh::FeaturePython", "CutMaterial")
self.cutMaterialIn = FreeCAD.ActiveDocument.addObject("Mesh::FeaturePython", "CutMaterialIn")
self.cutMaterialIn.ViewObject.Proxy = 0
self.cutMaterialIn.ViewObject.show()
self.cutMaterialIn.ViewObject.ShapeColor = (1.0, 0.85, 0.45, 0.0)
else:
self.cutMaterial = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","CutMaterial")
self.cutMaterial = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "CutMaterial")
self.cutMaterial.Shape = self.job.Stock.Shape
self.cutMaterial.ViewObject.Proxy = 0
self.cutMaterial.ViewObject.show()
@@ -153,21 +152,18 @@ class PathSimulation:
# Add cut path solid for debug
if self.debug:
self.cutSolid = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","CutDebug")
self.cutSolid = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "CutDebug")
self.cutSolid.ViewObject.Proxy = 0
self.cutSolid.ViewObject.hide()
self.SetupSimulation()
self.resetSimulation = True
FreeCAD.ActiveDocument.recompute()
#self.dialog.show()
def SkipStep(self):
self.skipStep = True
self.PerformCut()
def PerformCutBoolean(self):
if self.resetSimulation:
self.resetSimulation = False
@@ -178,8 +174,9 @@ class PathSimulation:
self.busy = True
cmd = self.operation.Path.Commands[self.icmd]
#for cmd in job.Path.Commands:
# for cmd in job.Path.Commands:
pathSolid = None
if cmd.Name in ['G0']:
self.curpos = self.RapidMove(cmd, self.curpos)
if cmd.Name in ['G1', 'G2', 'G3']:
@@ -187,6 +184,17 @@ class PathSimulation:
self.curpos = self.RapidMove(cmd, self.curpos)
else:
(pathSolid, self.curpos) = self.GetPathSolid(self.tool, cmd, self.curpos)
if cmd.Name in ['G81', 'G82', 'G83']:
if self.firstDrill:
extendcommand = Path.Command('G1', {"X": 0.0, "Y": 0.0, "Z": cmd.r})
self.curpos = self.RapidMove(extendcommand, self.curpos)
self.firstDrill = False
extendcommand = Path.Command('G1', {"X": cmd.x, "Y": cmd.y, "Z": cmd.r})
self.curpos = self.RapidMove(extendcommand, self.curpos)
extendcommand = Path.Command('G1', {"X": cmd.x, "Y": cmd.y, "Z": cmd.z})
self.curpos = self.RapidMove(extendcommand, self.curpos)
extendcommand = Path.Command('G1', {"X": cmd.x, "Y": cmd.y, "Z": cmd.r})
self.curpos = self.RapidMove(extendcommand, self.curpos)
self.skipStep = False
if pathSolid is not None:
if self.debug:
@@ -197,14 +205,14 @@ class PathSimulation:
self.stock = newStock.removeSplitter()
except:
if self.debug:
print "invalid cut at cmd #" + str(self.icmd)
print("invalid cut at cmd #{}".format(self.icmd))
if not self.disableAnim:
self.cutTool.Placement = FreeCAD.Placement(self.curpos, self.stdrot)
self.icmd += 1
self.iprogress += 1
self.UpdateProgress()
if self.icmd >= len(self.operation.Path.Commands):
#self.cutMaterial.Shape = self.stock.removeSplitter()
# self.cutMaterial.Shape = self.stock.removeSplitter()
self.ioperation += 1
if self.ioperation >= len(self.activeOps):
self.EndSimulation()
@@ -214,7 +222,7 @@ class PathSimulation:
if not self.disableAnim:
self.cutMaterial.Shape = self.stock
self.busy = False
def PerformCutVoxel(self):
if self.resetSimulation:
self.resetSimulation = False
@@ -225,17 +233,30 @@ class PathSimulation:
self.busy = True
cmd = self.operation.Path.Commands[self.icmd]
#for cmd in job.Path.Commands:
# for cmd in job.Path.Commands:
if cmd.Name in ['G0', 'G1', 'G2', 'G3']:
self.curpos = self.voxSim.ApplyCommand(self.curpos, cmd)
if not self.disableAnim:
self.cutTool.Placement = self.curpos #FreeCAD.Placement(self.curpos, self.stdrot)
self.cutTool.Placement = self.curpos # FreeCAD.Placement(self.curpos, self.stdrot)
(self.cutMaterial.Mesh, self.cutMaterialIn.Mesh) = self.voxSim.GetResultMesh()
if cmd.Name in ['G81', 'G82', 'G83']:
extendcommands = []
if self.firstDrill:
extendcommands.append(Path.Command('G1', {"X": 0.0, "Y": 0.0, "Z": cmd.r}))
self.firstDrill = False
extendcommands.append(Path.Command('G1', {"X": cmd.x, "Y": cmd.y, "Z": cmd.r}))
extendcommands.append(Path.Command('G1', {"X": cmd.x, "Y": cmd.y, "Z": cmd.z}))
extendcommands.append(Path.Command('G1', {"X": cmd.x, "Y": cmd.y, "Z": cmd.r}))
for ecmd in extendcommands:
self.curpos = self.voxSim.ApplyCommand(self.curpos, ecmd)
if not self.disableAnim:
self.cutTool.Placement = self.curpos # FreeCAD.Placement(self.curpos, self.stdrot)
(self.cutMaterial.Mesh, self.cutMaterialIn.Mesh) = self.voxSim.GetResultMesh()
self.icmd += 1
self.iprogress += 1
self.UpdateProgress()
if self.icmd >= len(self.operation.Path.Commands):
#self.cutMaterial.Shape = self.stock.removeSplitter()
# self.cutMaterial.Shape = self.stock.removeSplitter()
self.ioperation += 1
if self.ioperation >= len(self.activeOps):
self.EndSimulation()
@@ -249,16 +270,16 @@ class PathSimulation:
self.PerformCutVoxel()
else:
self.PerformCutBoolean()
def RapidMove(self, cmd, curpos):
path = PathGeom.edgeForCmd(cmd, curpos) # hack to overcome occ bug
path = PathGeom.edgeForCmd(cmd, curpos) # hack to overcome occ bug
if path is None:
return curpos
return path.valueAt(path.LastParameter)
def GetPathSolidOld(self, tool, cmd, curpos):
e1 = PathGeom.edgeForCmd(cmd, curpos)
#curpos = e1.valueAt(e1.LastParameter)
# curpos = e1.valueAt(e1.LastParameter)
n1 = e1.tangentAt(0)
n1[2] = 0.0
try:
@@ -266,10 +287,10 @@ class PathSimulation:
except:
return (None, e1.valueAt(e1.LastParameter))
height = self.height
rad = tool.Diameter / 2.0 - 0.001 * curpos[2] # hack to overcome occ bug
if type(e1.Curve) is Part.Circle and e1.Curve.Radius <= rad: # hack to overcome occ bug
rad = tool.Diameter / 2.0 - 0.001 * curpos[2] # hack to overcome occ bug
if type(e1.Curve) is Part.Circle and e1.Curve.Radius <= rad: # hack to overcome occ bug
rad = e1.Curve.Radius - 0.001
#return (None, e1.valueAt(e1.LastParameter))
# return (None, e1.valueAt(e1.LastParameter))
xf = n1[0] * rad
yf = n1[1] * rad
xp = curpos[0]
@@ -279,33 +300,33 @@ class PathSimulation:
v2 = Vector(yf + xp, -xf + yp, zp + height)
v3 = Vector(-yf + xp, xf + yp, zp + height)
v4 = Vector(-yf + xp, xf + yp, zp)
vc1 = Vector(xf + xp, yf + yp, zp)
vc2 = Vector(xf + xp, yf + yp, zp + height)
# vc1 = Vector(xf + xp, yf + yp, zp)
# vc2 = Vector(xf + xp, yf + yp, zp + height)
l1 = Part.makeLine(v1, v2)
l2 = Part.makeLine(v2, v3)
#l2 = Part.Edge(Part.Arc(v2, vc2, v3))
# l2 = Part.Edge(Part.Arc(v2, vc2, v3))
l3 = Part.makeLine(v3, v4)
l4 = Part.makeLine(v4, v1)
#l4 = Part.Edge(Part.Arc(v4, vc1, v1))
# l4 = Part.Edge(Part.Arc(v4, vc1, v1))
w1 = Part.Wire([l1, l2, l3, l4])
w2 = Part.Wire(e1)
try:
ex1 = w2.makePipeShell([w1],True, True)
ex1 = w2.makePipeShell([w1], True, True)
except:
#Part.show(w1)
#Part.show(w2)
# Part.show(w1)
# Part.show(w2)
return (None, e1.valueAt(e1.LastParameter))
cyl1 = Part.makeCylinder(rad, height, curpos)
curpos = e1.valueAt(e1.LastParameter)
cyl2 = Part.makeCylinder(rad, height, curpos)
ex1s = Part.Solid(ex1)
f1 = ex1s.fuse([cyl1,cyl2]).removeSplitter()
f1 = ex1s.fuse([cyl1, cyl2]).removeSplitter()
return (f1, curpos)
# get a solid representation of a tool going along path
def GetPathSolid(self, tool, cmd, pos):
toolPath = PathGeom.edgeForCmd(cmd, pos)
#curpos = e1.valueAt(e1.LastParameter)
# curpos = e1.valueAt(e1.LastParameter)
startDir = toolPath.tangentAt(0)
startDir[2] = 0.0
endPos = toolPath.valueAt(toolPath.LastParameter)
@@ -315,11 +336,11 @@ class PathSimulation:
endDir.normalize()
except:
return (None, endPos)
height = self.height
# height = self.height
# hack to overcome occ bugs
rad = tool.Diameter / 2.0 - 0.001 * pos[2]
#rad = rad + 0.001 * self.icmd
# rad = rad + 0.001 * self.icmd
if type(toolPath.Curve) is Part.Circle and toolPath.Curve.Radius <= rad:
rad = toolPath.Curve.Radius - 0.01 * (pos[2] + 1)
return (None, endPos)
@@ -334,7 +355,7 @@ class PathSimulation:
fullProf = Part.Wire([toolProf, mirroredProf])
pathWire = Part.Wire(toolPath)
try:
pathShell = pathWire.makePipeShell([fullProf],False, True)
pathShell = pathWire.makePipeShell([fullProf], False, True)
except:
if self.debug:
Part.show(pathWire)
@@ -342,11 +363,11 @@ class PathSimulation:
return (None, endPos)
# create the start cup
startCup = toolProf.revolve(pos, Vector(0,0,1), -180)
startCup = toolProf.revolve(pos, Vector(0, 0, 1), -180)
#create the end cup
# create the end cup
endProf = self.CreateToolProfile(tool, endDir, endPos, rad)
endCup = endProf.revolve(endPos, Vector(0,0,1), 180)
endCup = endProf.revolve(endPos, Vector(0, 0, 1), 180)
fullShell = Part.makeShell(startCup.Faces + pathShell.Faces + endCup.Faces)
return (Part.makeSolid(fullShell).removeSplitter(), endPos)
@@ -354,7 +375,7 @@ class PathSimulation:
# create radial profile of the tool (90 degrees to the direction of the path)
def CreateToolProfile(self, tool, dir, pos, rad):
type = tool.ToolType
#rad = tool.Diameter / 2.0 - 0.001 * pos[2] # hack to overcome occ bug
# rad = tool.Diameter / 2.0 - 0.001 * pos[2] # hack to overcome occ bug
xf = dir[0] * rad
yf = dir[1] * rad
xp = pos[0]
@@ -393,13 +414,13 @@ class PathSimulation:
lR = Part.makeLine(vBR, vTR)
res = Part.Wire([cB, lR, lT])
else: # default: assume type == "EndMill"
else: # default: assume type == "EndMill"
vBR = Vector(xp + yf, yp - xf, zp)
lR = Part.makeLine(vBR, vTR)
lB = Part.makeLine(vBC, vBR)
res = Part.Wire([lB, lR, lT])
return res
return res
def onJobChange(self):
form = self.taskForm.form
@@ -407,19 +428,18 @@ class PathSimulation:
form.listOperations.clear()
self.operations = []
for op in j.Operations.OutList:
listItem = QtGui.QListWidgetItem(op.ViewObject.Icon, op.Label)
listItem = QtGui.QListWidgetItem(op.ViewObject.Icon, op.Label)
listItem.setFlags(listItem.flags() | QtCore.Qt.ItemIsUserCheckable)
listItem.setCheckState(QtCore.Qt.CheckState.Checked)
self.operations.append(op)
form.listOperations.addItem(listItem)
def onSpeedBarChange(self):
form = self.taskForm.form
self.simperiod = 1000 / form.sliderSpeed.value()
form.labelGPerSec.setText(str(form.sliderSpeed.value()) + " G/s")
#if (self.timer.isActive()):
# if (self.timer.isActive()):
self.timer.setInterval(self.simperiod)
def onAccuracyBarChange(self):
form = self.taskForm.form
@@ -428,7 +448,7 @@ class PathSimulation:
def GuiBusy(self, isBusy):
form = self.taskForm.form
#form.toolButtonStop.setEnabled()
# form.toolButtonStop.setEnabled()
form.toolButtonPlay.setEnabled(not isBusy)
form.toolButtonPause.setEnabled(isBusy)
form.toolButtonStep.setEnabled(not isBusy)
@@ -493,18 +513,17 @@ class PathSimulation:
FreeCAD.ActiveDocument.removeObject(self.cutMaterial.Name)
self.cutMaterial = None
self.RemoveInnerMaterial()
def accept(self):
self.EndSimulation()
self.RemoveInnerMaterial()
self.RemoveTool()
def cancel(self):
self.EndSimulation()
self.RemoveTool()
self.RemoveMaterial()
class CommandPathSimulate:
@@ -527,7 +546,5 @@ class CommandPathSimulate:
pathSimulation = PathSimulation()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Simulator',CommandPathSimulate())
FreeCADGui.addCommand('Path_Simulator', CommandPathSimulate())
FreeCAD.Console.PrintLog("Loading PathSimulator Gui... done\n")

View File

@@ -21,8 +21,16 @@
# * *
# ***************************************************************************/
from __future__ import print_function
import FreeCAD
from FreeCAD import Units
import Path
import argparse
import datetime
import shlex
from PathScripts import PostUtils
from PathScripts import PathUtils
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 linuxcnc 3 axis mill. This postprocessor, once placed
@@ -33,14 +41,6 @@ import linuxcnc_post
linuxcnc_post.export(object,"/path/to/file.ncc","")
'''
import FreeCAD
from FreeCAD import Units
import argparse
import datetime
import shlex
from PathScripts import PostUtils
from PathScripts import PathUtils
now = datetime.datetime.now()
parser = argparse.ArgumentParser(prog='linuxcnc', add_help=False)
@@ -52,12 +52,14 @@ parser.add_argument('--line-numbers', action='store_true', help='prefix with lin
parser.add_argument('--no-line-numbers', action='store_true', help='don\'t prefix with line numbers (default)')
parser.add_argument('--show-editor', action='store_true', help='pop up editor before writing output (default)')
parser.add_argument('--no-show-editor', action='store_true', help='don\'t pop up editor before writing output')
parser.add_argument('--precision', default='4', help='number of digits of precision, default=4')
parser.add_argument('--precision', default='3', help='number of digits of precision, default=4')
parser.add_argument('--preamble', help='set commands to be issued before the first command, default="G17\nG90"')
parser.add_argument('--postamble', help='set commands to be issued after the last command, default="M05\nG17 G90\nM2"')
parser.add_argument('--inches', action='store_true', help='Convert output for US imperial mode (G20)')
parser.add_argument('--modal', action='store_true', help='Dont output the Same Gcommand Name USE Modal Mode')
parser.add_argument('--no-doubles', action='store_true', help='Dont output the Same Axis Value Mode')
TOOLTIP_ARGS=parser.format_help()
TOOLTIP_ARGS = parser.format_help()
# These globals set common customization preferences
OUTPUT_COMMENTS = True
@@ -65,6 +67,7 @@ OUTPUT_HEADER = True
OUTPUT_LINE_NUMBERS = False
SHOW_EDITOR = True
MODAL = False # if true commands are suppressed if the same as previous line.
OUTPUT_DOUBLES = True
COMMAND_SPACE = " "
LINENR = 100 # line number starting value
@@ -76,7 +79,7 @@ UNIT_FORMAT = 'mm'
MACHINE_NAME = "LinuxCNC"
CORNER_MIN = {'x': 0, 'y': 0, 'z': 0}
CORNER_MAX = {'x': 500, 'y': 300, 'z': 300}
PRECISION=4
PRECISION = 3
# Preamble text will appear at the beginning of the GCODE output file.
PREAMBLE = '''G17 G90
@@ -103,6 +106,7 @@ TOOL_CHANGE = ''''''
if open.__module__ == '__builtin__':
pythonopen = open
def processArguments(argstring):
global OUTPUT_HEADER
global OUTPUT_COMMENTS
@@ -114,6 +118,8 @@ def processArguments(argstring):
global UNITS
global UNIT_SPEED_FORMAT
global UNIT_FORMAT
global MODAL
global OUTPUT_DOUBLES
try:
args = parser.parse_args(shlex.split(argstring))
@@ -143,12 +149,18 @@ def processArguments(argstring):
UNITS = 'G20'
UNIT_SPEED_FORMAT = 'in/min'
UNIT_FORMAT = 'in'
PRECISION = 4
if args.modal:
MODAL = True
if args.no_doubles:
OUTPUT_DOUBLES = False
except:
return False
return True
def export(objectslist, filename, argstring):
if not processArguments(argstring):
return None
@@ -183,17 +195,16 @@ def export(objectslist, filename, argstring):
myMachine = 'not set'
if hasattr(job,"MachineName"):
if hasattr(job, "MachineName"):
myMachine = job.MachineName
if hasattr(job, "MachineUnits"):
if job.MachineUnits == "Metric":
UNITS = "G21"
UNIT_SPEED_FORMAT = 'mm/min'
UNITS = "G21"
UNIT_SPEED_FORMAT = 'mm/min'
else:
UNITS = "G20"
UNIT_SPEED_FORMAT = 'in/min'
UNITS = "G20"
UNIT_SPEED_FORMAT = 'in/min'
# do the pre_op
if OUTPUT_COMMENTS:
@@ -245,16 +256,24 @@ def linenumber():
return "N" + str(LINENR) + " "
return ""
def parse(pathobj):
global PRECISION
global MODAL
global OUTPUT_DOUBLES
out = ""
lastcommand = None
precision_string = '.' + str(PRECISION) +'f'
precision_string = '.' + str(PRECISION) + 'f'
# params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control
# the order of parameters
# 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', 'H']
params = ['X', 'Y', 'Z', 'A', 'B', 'C', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L', 'H', 'D', 'P']
# keep track for no doubles
currLocation = {}
firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": -1})
currLocation.update(firstmove.Parameters)
if hasattr(pathobj, "Group"): # We have a compound or project.
# if OUTPUT_COMMENTS:
@@ -284,22 +303,31 @@ def parse(pathobj):
# Now add the remaining parameters in order
for param in params:
if param in c.Parameters:
if param == 'F':
if c.Name not in ["G0", "G00"]: #linuxcnc doesn't use rapid speeds
if param == 'F' and (currLocation[param] == c.Parameters[param] and OUTPUT_DOUBLES):
if c.Name not in ["G0", "G00"]: # linuxcnc doesn't use rapid speeds
speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity)
outstring.append(
param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string) )
param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string))
elif param == 'T':
outstring.append(param + str(int(c.Parameters['T'])))
elif param == 'H':
outstring.append(param + str(int(c.Parameters['H'])))
elif param == 'D':
outstring.append(param + str(int(c.Parameters['D'])))
elif param == 'S':
outstring.append(param + str(int(c.Parameters['S'])))
else:
pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length)
outstring.append(
param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string) )
#param + format(c.Parameters[param], precision_string))
if (not OUTPUT_DOUBLES) and (param in currLocation) and (currLocation[param] == c.Parameters[param]):
continue
else:
pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length)
outstring.append(
param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string))
# param + format(c.Parameters[param], precision_string))
# store the latest command
lastcommand = command
currLocation.update(c.Parameters)
# Check for Tool Change:
if command == 'M6':