Improved LeadInOut; Better layer handling

This commit is contained in:
Patrick Felixberger
2020-03-17 19:13:56 +01:00
parent 2088cdfeb8
commit d586eea42e
3 changed files with 189 additions and 102 deletions

View File

@@ -58,6 +58,8 @@ def toolDepthAndOffset(width, extraDepth, tool):
toolOffset = float(tool.FlatRadius)
extraOffset = float(tool.Diameter) / 2 - width if 180 == angle else extraDepth / tan
offset = toolOffset + extraOffset
if offset < 0.0001:
offset = 0.01
return (depth, offset)

View File

@@ -72,6 +72,7 @@ class ObjectDressup:
obj.Proxy = self
obj.addProperty("App::PropertyDistance", "ExtendLeadIn", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extends LeadIn distance"))
obj.addProperty("App::PropertyDistance", "ExtendLeadOut", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extends LeadOut distance"))
obj.addProperty("App::PropertyBool", "RapidPlunge", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Perform plunges with G0"))
self.wire = None
self.rapids = None
@@ -94,6 +95,7 @@ class ObjectDressup:
obj.RadiusCenter = 'Radius'
obj.ExtendLeadIn = 0
obj.ExtendLeadOut = 0
obj.RapidPlunge = False
def execute(self, obj):
if not obj.Base:
@@ -119,6 +121,13 @@ class ObjectDressup:
if hasattr(op, 'Direction') and op.Direction == 'CW':
return 'right'
return 'left'
def getSideOfPath(self, obj):
op = PathDressup.baseOp(obj.Base)
if hasattr(op, 'Side'):
return op.Side
return ''
def normalize(self, Vector):
x = Vector.x
@@ -126,8 +135,8 @@ class ObjectDressup:
length = math.sqrt(x*x + y*y)
#print("Len: {}".format(length))
if((math.fabs(length)) > 0.0000000000001):
vx = round(x / length, 2)
vy = round(y / length, 2)
vx = round(x / length, 3)
vy = round(y / length, 3)
return FreeCAD.Vector(vx, vy, 0)
def invert(self, Vector):
@@ -152,14 +161,13 @@ class ObjectDressup:
def getLeadStart(self, obj, queue, action):
'''returns Lead In G-code.'''
results = []
# zdepth = currLocation["Z"]
op = PathDressup.baseOp(obj.Base)
tc = PathDressup.toolController(obj.Base)
horizFeed = tc.HorizFeed.Value
vertFeed = tc.VertFeed.Value
toolnummer = tc.ToolNumber
# set the correct twist command
# Set the correct twist command
if self.getDirectionOfPath(obj) == 'left':
arcdir = "G3"
else:
@@ -170,13 +178,14 @@ class ObjectDressup:
p0 = queue[0].Placement.Base
p1 = queue[1].Placement.Base
v = self.normalize(p1.sub(p0))
# PathLog.notice(" CURRENT_IN : P0 Z:{} p1 Z:{}".format(p0.z,p1.z))
# PathLog.debug(" CURRENT_IN : P0 Z:{} p1 Z:{}".format(p0.z,p1.z))
else:
p0 = queue[0].Placement.Base
p1 = queue[1].Placement.Base
# PathLog.notice(" CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} ".format(p0.x,p0.y,p1.x,p1.y))
v = self.normalize(p1.sub(p0))
# PathLog.debug(" CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} ".format(p0.x,p0.y,p1.x,p1.y))
# Calculate offset vector (will be overwritten for arcs)
if self.getDirectionOfPath(obj) == 'right':
off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0)
else:
@@ -189,33 +198,36 @@ class ObjectDressup:
vec_n = self.normalize(vec)
vec_inv = self.invert(vec_n)
vec_off = self.multiply(vec_inv, obj.ExtendLeadIn)
#print("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y))
#PathLog.debug("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y))
else:
# We have an arc move
#print("Arc X{} Y{} P {}".format(p0.x, p0.y, queue[0].Parameters))
# Calculate coordinates for middle of circle
pij = copy.deepcopy(p0)
pij.x += queue[1].Parameters['I']
pij.y += queue[1].Parameters['J']
ve = pij.sub(p0)
#print("I{} J{}, vx {} vy {}".format(pij.x, pij.y, ve.x, ve.y))
if arcdir == "G2":
vec_rot = self.rotate(ve, 90)
else:
vec_rot = self.rotate(ve, -90)
#print("vro{} vro{}".format(vec_rot.x, vec_rot.y))
# Calculate vector circle start -> circle middle
vec_circ = pij.sub(p0)
# Rotate vector to get direction for lead in
if arcdir == "G2":
vec_rot = self.rotate(vec_circ, 90)
else:
vec_rot = self.rotate(vec_circ, -90)
# Normalize and invert vector
vec_n = self.normalize(vec_rot)
v = self.invert(vec_n)
# Calculate offset of lead in
if arcdir == "G3":
off_v = FreeCAD.Vector(-v.y*R, v.x*R, 0.0)
else:
off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0)
# Multiply offset by LeadIn length
vec_off = self.multiply(vec_rot, obj.ExtendLeadIn)
#print("vnx{} vny{}, vxi {} vyi {}".format(vec_n.x, vec_n.y, v.x, v.y))
#print("vxo{} vyo{}".format(off_v.x, off_v.y))
#print("vxo{} vyo{}".format(vec_off.x, vec_off.y))
offsetvector = FreeCAD.Vector(v.x*R-vec_off.x, v.y*R-vec_off.y, 0) # IJ
if obj.RadiusCenter == 'Radius':
@@ -224,16 +236,14 @@ class ObjectDressup:
leadstart = p0.add(off_v) # Dmode
if action == 'start':
#print("Start")
extendcommand = Path.Command('G0', {"X": 0.0, "Y": 0.0, "Z": op.ClearanceHeight.Value})
results.append(extendcommand)
#extendcommand = Path.Command('G0', {"X": 0.0, "Y": 0.0, "Z": op.ClearanceHeight.Value})
#results.append(extendcommand)
extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y, "Z": op.ClearanceHeight.Value})
results.append(extendcommand)
extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y, "Z": op.SafeHeight.Value})
extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value})
results.append(extendcommand)
if action == 'layer':
#print("Layer")
if not obj.KeepToolDown:
extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value})
results.append(extendcommand)
@@ -241,7 +251,10 @@ class ObjectDressup:
extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y})
results.append(extendcommand)
extendcommand = Path.Command('G1', {"X": leadstart.x, "Y": leadstart.y, "Z": p1.z, "F": vertFeed})
if not obj.RapidPlunge:
extendcommand = Path.Command('G1', {"X": leadstart.x, "Y": leadstart.y, "Z": p1.z, "F": vertFeed})
else:
extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y, "Z": p1.z,})
results.append(extendcommand)
if obj.UseMachineCRC:
@@ -260,8 +273,11 @@ class ObjectDressup:
extendcommand = Path.Command('G1', {"X": p0.x, "Y": p0.y, "F": horizFeed})
results.append(extendcommand)
else:
PathLog.notice(" CURRENT_IN Perp")
PathLog.debug(" CURRENT_IN Perp")
currLocation.update(results[-1].Parameters)
currLocation['Z'] = p1.z
return results
def getLeadEnd(self, obj, queue, action):
@@ -298,22 +314,19 @@ class ObjectDressup:
vec_n = self.normalize(vec)
vec_inv = self.invert(vec_n)
vec_off = self.multiply(vec_inv, obj.ExtendLeadOut)
#print("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y))
#PathLog.debug("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y))
else:
# We have an arc move
#print("Arc0 X{} Y{} P {}".format(p0.x, p0.y, queue[0].Parameters))
#print("Arc1 X{} Y{} P {}".format(p1.x, p1.y, queue[1].Parameters))
pij = copy.deepcopy(p0)
pij.x += queue[1].Parameters['I']
pij.y += queue[1].Parameters['J']
ve = pij.sub(p1)
# print("I{} J{}, vx {} vy {}".format(pij.x, pij.y, ve.x, ve.y))
if arcdir == "G2":
vec_rot = self.rotate(ve, -90)
else:
vec_rot = self.rotate(ve, 90)
#print("vro{} vro{}".format(vec_rot.x, vec_rot.y))
vec_n = self.normalize(vec_rot)
v = vec_n
@@ -322,21 +335,17 @@ class ObjectDressup:
else:
off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0)
vec_off = self.multiply(self.invert(vec_rot), obj.ExtendLeadOut)
#print("vnx{} vny{}, vxi {} vyi {}".format(vec_n.x, vec_n.y, v.x, v.y))
#print("vxo{} vyo{}".format(off_v.x, off_v.y))
#print("vxo{} vyo{}".format(vec_off.x, vec_off.y))
vec_inv = self.invert(vec_rot)
vec_off = self.multiply(vec_inv, obj.ExtendLeadOut)
#print("Arc0 X{} Y{} P {}".format(p0.x, p0.y, queue[0].Parameters))
offsetvector = FreeCAD.Vector(v.x*R-vec_off.x, v.y*R-vec_off.y, 0.0)
if obj.RadiusCenter == 'Radius':
leadend = (p1.add(off_v)).add(offsetvector) # Rmode
#print("End: X {}, Y{}".format(leadend.x, leadend.y))
else:
leadend = p1.add(off_v) # Dmode
IJ = off_v # .negative()
print("IJ: X {}, Y{}".format(IJ.x, IJ.y))
#results.append(queue[1])
if obj.StyleOff == 'Arc':
if obj.ExtendLeadOut != 0:
@@ -355,83 +364,161 @@ class ObjectDressup:
return results
# def generateLeadInOutCurve(self, obj):
# global currLocation # pylint: disable=global-statement
# firstmove = Path.Command("G0", {"X": 0, "Y": 0, "Z": 0})
# currLocation.update(firstmove.Parameters)
# newpath = []
# queue = []
# action = 'start'
#
#
# for curCommand in obj.Base.Path.Commands:
# if len(queue) > 2:
# queue.pop(0)
#
# # Don't worry about non-move commands, just add to output
# if curCommand.Name not in movecommands + rapidcommands:
# newpath.append(curCommand)
# continue
#
# # rapid retract triggers exit move, else just add to output
# if curCommand.Name in rapidcommands:
#
# currLocation.update(curCommand.Parameters)
#
# if curCommand.Name in movecommands:
# queue.append(curCommand)
# if action == 'start' and len(queue) < 2:
# # Not enough data
# continue
#
# if action == 'leave':
# newpath.append(curCommand)
#
# # First lead in
# if obj.LeadIn and len(queue) >= 2 and action == 'start':
# print("Calc lead in...")
# temp = self.getLeadStart(obj, queue, action)
# newpath.extend(temp)
# newpath.append(curCommand)
# print("Append: {}, P: {}".format(curCommand.Name, curCommand.Parameters))
# action = 'leave'
# currLocation.update(curCommand.Parameters)
# continue
#
# if curCommand.z != currLocation["Z"] and action == 'leave':
# print("Calc lead out...")
# if obj.LeadOut: # fish cycle
# if len(queue) > 2:
# # Remove last cmd
# queue.pop(len(queue)-1)
#
# temp = self.getLeadEnd(obj, queue, action)
# newpath.extend(temp)
#
# action = 'layer'
# if not obj.KeepToolDown:
# newpath.append(curCommand)
#
# if action == 'layer':
# print("layer")
# while(len(queue)) > 2:
# queue.pop(0)
#
# if obj.LeadIn:
# temp = self.getLeadStart(obj, queue, action)
# newpath.extend(temp)
# #newpath.append(curCommand)
# action = 'leave'
# currLocation.update(curCommand.Parameters)
# else:
# newpath.append(curCommand)
# #print("Append: {}, P: {}".format(curCommand.Name, curCommand.Parameters))
#
# commands = newpath
# return Path.Path(commands)
def generateLeadInOutCurve(self, obj):
global currLocation # pylint: disable=global-statement
firstmove = Path.Command("G0", {"X": 0, "Y": 0, "Z": 0})
op = PathDressup.baseOp(obj.Base)
currLocation.update(firstmove.Parameters)
newpath = []
queue = []
action = 'start'
prevCmd = ''
layers = []
# Read in all commands
for curCommand in obj.Base.Path.Commands:
# replace = None
# don't worry about non-move commands, just add to output
if curCommand.Name not in movecommands + rapidcommands:
# Don't worry about non-move commands, just add to output
newpath.append(curCommand)
continue
# rapid retract triggers exit move, else just add to output
if curCommand.Name in rapidcommands:
# detect start position
if (curCommand.x is not None) or (curCommand.y is not None):
firstmove = curCommand
currLocation.update(curCommand.Parameters)
if action != 'start': # done move out
if obj.LeadOut:
temp = self.getLeadEnd(obj, queue, 'end')
newpath.extend(temp)
newpath.append(curCommand) # Z clear DONE
if curCommand.Name in movecommands:
queue.append(curCommand)
if action == 'start' and len(queue) < 2:
continue
if action == 'layer':
if len(queue) > 2:
queue.pop(0)
if obj.LeadIn:
temp = self.getLeadStart(obj, queue, action)
newpath.extend(temp)
#newpath.append(curCommand)
action = 'none'
currLocation.update(curCommand.Parameters)
else:
newpath.append(curCommand)
if curCommand.z != currLocation["Z"] and action != 'start': # vertical feeding to depth
if obj.LeadOut: # fish cycle
if len(queue) > 2:
queue.pop(len(queue)-1)
temp = self.getLeadEnd(obj, queue, action)
newpath.extend(temp)
action = 'layer'
if len(queue) > 2:
queue.pop(0)
continue
else:
newpath.append(curCommand)
if len(queue) > 2:
queue.pop(0)
if obj.LeadIn and len(queue) >= 2 and action == 'start':
temp = self.getLeadStart(obj, queue, action)
newpath.extend(temp)
newpath.append(curCommand)
action = 'none'
currLocation.update(curCommand.Parameters)
else:
newpath.append(curCommand)
currLocation.update(curCommand.Parameters)
if curCommand.Name in rapidcommands:
# We don't care about rapid moves
prevCmd = curCommand
currLocation.update(curCommand.Parameters)
continue
if curCommand.Name in movecommands:
if prevCmd.Name in rapidcommands and curCommand.Name in movecommands and len(queue) > 0:
# Layer changed: Save current layer cmds prepare next layer
layers.append(queue)
queue = []
#print("New layer: {}".format(layers))
# Save all move commands
queue.append(curCommand)
#print("Append move: {}, P: {}".format(curCommand.Name, curCommand.Parameters))
currLocation.update(curCommand.Parameters)
prevCmd = curCommand
# Add last layer
if len(queue) > 0:
layers.append(queue)
queue = []
#print("New layer: {}".format(layers))
# Go through each layer and add leadIn/Out
idx = 0
for layer in layers:
#print("Layer {}".format(idx))
if obj.LeadIn:
#print("Lead IN")
temp = self.getLeadStart(obj, layer, action)
newpath.extend(temp)
for cmd in layer:
#print("CurLoc: {}, NewCmd: {}".format(currLocation, cmd))
if currLocation['X'] == cmd.x and currLocation['Y'] == cmd.y and currLocation['Z'] == cmd.z and cmd.Name in ['G1', 'G01']:
continue
newpath.append(cmd)
if obj.LeadOut:
#print("Lead OUT")
tmp = []
tmp.append(layer[-2])
tmp.append(layer[-1])
temp = self.getLeadEnd(obj, tmp, action)
newpath.extend(temp)
if not obj.KeepToolDown or idx == len(layers)-1:
extendcommand = Path.Command('G0', {"Z": op.ClearanceHeight.Value})
newpath.append(extendcommand)
else:
action = 'layer'
idx += 1
commands = newpath
return Path.Path(commands)
class ViewProviderDressup:
def __init__(self, vobj):

View File

@@ -134,7 +134,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
if FreeCAD.GuiUp:
import FreeCADGui
FreeCADGui.ActiveDocument.getObject(tmpGrpNm).Visibility = False
return shapes
def _flattenWire(self, obj, wire, trgtDep):
@@ -297,12 +297,10 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
# Determine with which set of intersection tags the model intersects
(cmnIntArea, cmnExtArea) = self._checkTagIntersection(iTAG, eTAG, 'QRY', comFC)
if cmnExtArea > cmnIntArea:
PathLog.debug('Cutting on Ext side.')
self.cutSide = 'E'
self.cutSideTags = eTAG.Shape
tagCOM = begExt.CenterOfMass
else:
PathLog.debug('Cutting on Int side.')
self.cutSide = 'I'
self.cutSideTags = iTAG.Shape
tagCOM = begInt.CenterOfMass