Merge pull request #10953 from jffmichi/rework_leadinoutdressup
Path: rework LeadInOutDressup
This commit is contained in:
@@ -70,6 +70,9 @@ class Instruction(object):
|
||||
def isMove(self):
|
||||
return False
|
||||
|
||||
def isRapid(self):
|
||||
return False
|
||||
|
||||
def isPlunge(self):
|
||||
"""isPlunge() ... return true if this moves up or down"""
|
||||
return self.isMove() and not Path.Geom.isRoughly(
|
||||
@@ -131,6 +134,9 @@ class MoveStraight(Instruction):
|
||||
def isMove(self):
|
||||
return True
|
||||
|
||||
def isRapid(self):
|
||||
return self.cmd in Path.Geom.CmdMoveRapid
|
||||
|
||||
def pathLength(self):
|
||||
return (self.positionEnd() - self.positionBegin()).Length
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import FreeCAD
|
||||
import Path
|
||||
import Path.Base.Generator.dogboneII as dogboneII
|
||||
import Path.Base.Language as PathLanguage
|
||||
import Path.Dressup.Utils as PathDressup
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
import math
|
||||
|
||||
@@ -271,9 +272,7 @@ class Proxy(object):
|
||||
return None
|
||||
|
||||
def toolRadius(self, obj):
|
||||
if not hasattr(obj.Base, "ToolController"):
|
||||
return self.toolRadius(obj.Base)
|
||||
return obj.Base.ToolController.Tool.Diameter.Value / 2
|
||||
return PathDressup.toolController(obj.Base).Tool.Diameter.Value / 2
|
||||
|
||||
def createBone(self, obj, move0, move1):
|
||||
kink = dogboneII.Kink(move0, move1)
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
import FreeCAD as App
|
||||
import FreeCADGui
|
||||
import Path
|
||||
import Path.Base.Language as PathLanguage
|
||||
import Path.Dressup.Utils as PathDressup
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
from Path.Geom import CmdMoveRapid, CmdMoveStraight, CmdMoveArc, wireForPath
|
||||
from Path.Geom import wireForPath
|
||||
import math
|
||||
|
||||
__doc__ = """LeadInOut Dressup USE ROLL-ON ROLL-OFF to profile"""
|
||||
|
||||
@@ -44,10 +46,6 @@ else:
|
||||
Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule())
|
||||
|
||||
|
||||
movecommands = CmdMoveStraight + CmdMoveArc
|
||||
currLocation = {}
|
||||
|
||||
|
||||
class ObjectDressup:
|
||||
def __init__(self, obj):
|
||||
lead_styles = [
|
||||
@@ -144,8 +142,8 @@ class ObjectDressup:
|
||||
return None
|
||||
|
||||
def setup(self, obj):
|
||||
obj.Length = obj.Base.ToolController.Tool.Diameter * 0.75
|
||||
obj.LengthOut = obj.Base.ToolController.Tool.Diameter * 0.75
|
||||
obj.Length = PathDressup.toolController(obj.Base).Tool.Diameter * 0.75
|
||||
obj.LengthOut = PathDressup.toolController(obj.Base).Tool.Diameter * 0.75
|
||||
obj.LeadIn = True
|
||||
obj.LeadOut = True
|
||||
obj.KeepToolDown = False
|
||||
@@ -163,6 +161,7 @@ class ObjectDressup:
|
||||
return
|
||||
if not obj.Base.Path:
|
||||
return
|
||||
|
||||
if obj.Length <= 0:
|
||||
Path.Log.error(
|
||||
translate("Path_DressupLeadInOut", "Length/Radius positive not Null")
|
||||
@@ -182,425 +181,210 @@ class ObjectDressup:
|
||||
|
||||
def getDirectionOfPath(self, obj):
|
||||
op = PathDressup.baseOp(obj.Base)
|
||||
side = op.Side if hasattr(op, "Side") else "Inside"
|
||||
direction = op.Direction if hasattr(op, "Direction") else "CCW"
|
||||
|
||||
if hasattr(op, "Side") and op.Side == "Outside":
|
||||
return (
|
||||
"left" if hasattr(op, "Direction") and op.Direction == "CW" else "right"
|
||||
)
|
||||
if side == "Outside":
|
||||
return "left" if direction == "CW" else "right"
|
||||
else:
|
||||
return (
|
||||
"right" if hasattr(op, "Direction") and op.Direction == "CW" else "left"
|
||||
)
|
||||
return "right" if direction == "CW" else "left"
|
||||
|
||||
def getSideOfPath(self, obj):
|
||||
def getArcDirection(self, obj):
|
||||
direction = self.getDirectionOfPath(obj)
|
||||
return math.pi / 2 if direction == "left" else -math.pi / 2
|
||||
|
||||
def getTravelStart(self, obj, pos, first):
|
||||
op = PathDressup.baseOp(obj.Base)
|
||||
return op.Side if hasattr(op, "Side") else ""
|
||||
vertfeed = PathDressup.toolController(obj.Base).VertFeed.Value
|
||||
travel = []
|
||||
|
||||
def getLeadStart(self, obj, queue, action):
|
||||
"""returns Lead In G-code."""
|
||||
# Modified March 2022 by lcorley to support leadin extension
|
||||
results = []
|
||||
op = PathDressup.baseOp(obj.Base)
|
||||
horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value
|
||||
vertFeed = PathDressup.toolController(obj.Base).VertFeed.Value
|
||||
# begin positions for travel and plunge moves are not used anywhere,
|
||||
# skipping them makes our life a lot easier
|
||||
|
||||
arcs_identical = False
|
||||
# move to clearance height
|
||||
if first:
|
||||
travel.append(PathLanguage.MoveStraight(
|
||||
None, "G0", {"Z": op.ClearanceHeight.Value}))
|
||||
|
||||
# Set the correct twist command
|
||||
arcdir = "G3" if self.getDirectionOfPath(obj) == "left" else "G2"
|
||||
|
||||
if queue[1].Name == "G1": # line
|
||||
p0 = queue[0].Placement.Base
|
||||
p1 = queue[1].Placement.Base
|
||||
v = App.Vector(p1.sub(p0)).normalize()
|
||||
Path.Log.debug(" CURRENT_IN Line : P0 Z:{} p1 Z:{}".format(p0.z, p1.z))
|
||||
else:
|
||||
p0 = queue[0].Placement.Base
|
||||
p1 = queue[1].Placement.Base
|
||||
Path.Log.track()
|
||||
v = App.Vector(p1.sub(p0)).normalize()
|
||||
Path.Log.debug(
|
||||
" CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} Z:{}".format(
|
||||
p0.x, p0.y, p1.x, p1.y, p1.z
|
||||
)
|
||||
)
|
||||
|
||||
# Calculate offset vector (will be overwritten for arcs)
|
||||
if self.getDirectionOfPath(obj) == "right":
|
||||
off_v = App.Vector(v.y * obj.Length.Value, -v.x * obj.Length.Value, 0.0)
|
||||
else:
|
||||
off_v = App.Vector(-v.y * obj.Length.Value, v.x * obj.Length.Value, 0.0)
|
||||
|
||||
# Check if we enter at line or arc command
|
||||
if queue[1].Name in movecommands and queue[1].Name not in CmdMoveArc:
|
||||
# We have a line move
|
||||
vec = p1.sub(p0)
|
||||
vec_n = App.Vector(vec).normalize()
|
||||
vec_inv = vec_n
|
||||
vec_inv.multiply(-1)
|
||||
vec_off = vec_inv
|
||||
vec_off.multiply(obj.ExtendLeadIn)
|
||||
Path.Log.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
|
||||
# Calculate coordinates for middle of circle
|
||||
pij = App.Vector(p0)
|
||||
pij.x += queue[1].Parameters["I"]
|
||||
pij.y += queue[1].Parameters["J"]
|
||||
|
||||
# Check if lead in and operation go in same direction (usually for inner circles)
|
||||
if arcdir == queue[1].Name:
|
||||
arcs_identical = True
|
||||
|
||||
# Calculate vector circle start -> circle middle
|
||||
vec_circ = pij.sub(p0)
|
||||
|
||||
angle = 90 if arcdir == "G2" else -90
|
||||
vec_rot = App.Rotation(App.Vector(0, 0, 1), angle).multVec(vec_circ)
|
||||
|
||||
# Normalize and invert vector
|
||||
vec_n = App.Vector(vec_rot).normalize()
|
||||
v = App.Vector(vec_n).multiply(-1)
|
||||
|
||||
# Calculate offset of lead in
|
||||
if arcdir == "G3":
|
||||
off_v = App.Vector(-v.y * obj.Length.Value, v.x * obj.Length.Value, 0.0)
|
||||
else:
|
||||
off_v = App.Vector(v.y * obj.Length.Value, -v.x * obj.Length.Value, 0.0)
|
||||
|
||||
offsetvector = App.Vector(
|
||||
v.x * obj.Length.Value, v.y * obj.Length.Value, 0
|
||||
)
|
||||
|
||||
if obj.StyleOn == "Arc":
|
||||
leadstart = (p0.add(off_v)).sub(offsetvector)
|
||||
if arcs_identical:
|
||||
t = p0.sub(leadstart)
|
||||
t = p0.add(t)
|
||||
leadstart = t
|
||||
offsetvector = offsetvector.multiply(-1)
|
||||
elif obj.StyleOn == "Tangent":
|
||||
# This is wrong. please fix
|
||||
leadstart = (p0.add(off_v)).sub(offsetvector)
|
||||
if arcs_identical:
|
||||
t = p0.sub(leadstart)
|
||||
t = p0.add(t)
|
||||
leadstart = t
|
||||
offsetvector = offsetvector.multiply(-1)
|
||||
else: # perpendicular
|
||||
leadstart = p0.add(off_v)
|
||||
|
||||
# At this point leadstart is the beginning of the leadin arc
|
||||
# and offsetvector points from leadstart to the center of the leadin arc
|
||||
# so the offsetvector is a radius of the leadin arc at its start
|
||||
# The extend line should be tangent to the leadin arc at this point, or perpendicular to the radius
|
||||
|
||||
angle = -90 if arcdir == "G2" else 90
|
||||
tangentvec = App.Rotation(App.Vector(0, 0, 1), angle).multVec(offsetvector)
|
||||
|
||||
# Normalize the tangent vector
|
||||
tangentvecNorm = App.Vector(tangentvec).normalize()
|
||||
leadlinevec = App.Vector(tangentvecNorm).multiply(obj.ExtendLeadIn)
|
||||
|
||||
# leadlinevec provides the offset from the beginning of the lead arc to the beginning of the extend line
|
||||
extendstart = leadstart.add(leadlinevec)
|
||||
|
||||
if action == "start":
|
||||
if obj.ExtendLeadIn != 0:
|
||||
# Rapid move to beginning of extend line
|
||||
extendcommand = Path.Command(
|
||||
"G0",
|
||||
{
|
||||
"X": extendstart.x,
|
||||
"Y": extendstart.y,
|
||||
"Z": op.ClearanceHeight.Value,
|
||||
},
|
||||
)
|
||||
else:
|
||||
# Rapid move to beginning of leadin arc
|
||||
extendcommand = Path.Command(
|
||||
"G0",
|
||||
{
|
||||
"X": extendstart.x,
|
||||
"Y": extendstart.y,
|
||||
"Z": op.ClearanceHeight.Value,
|
||||
},
|
||||
)
|
||||
results.append(extendcommand)
|
||||
extendcommand = Path.Command("G0", {"Z": op.SafeHeight.Value})
|
||||
results.append(extendcommand)
|
||||
|
||||
if action == "layer":
|
||||
if not obj.KeepToolDown:
|
||||
extendcommand = Path.Command("G0", {"Z": op.SafeHeight.Value})
|
||||
results.append(extendcommand)
|
||||
|
||||
extendcommand = Path.Command("G0", {"X": extendstart.x, "Y": extendstart.y})
|
||||
results.append(extendcommand)
|
||||
# move to correct xy-position
|
||||
travel.append(PathLanguage.MoveStraight(
|
||||
None, "G0", {"X": pos.x, "Y": pos.y}))
|
||||
|
||||
# move to correct z-position (either rapidly or in two steps)
|
||||
if obj.RapidPlunge:
|
||||
extendcommand = Path.Command("G0", {"Z": p1.z})
|
||||
travel.append(PathLanguage.MoveStraight(None, "G0", {"Z": pos.z}))
|
||||
else:
|
||||
extendcommand = Path.Command("G1", {"Z": p1.z, "F": vertFeed})
|
||||
if first or not obj.KeepToolDown:
|
||||
travel.append(PathLanguage.MoveStraight(
|
||||
None, "G0", {"Z": op.SafeHeight.Value}))
|
||||
travel.append(PathLanguage.MoveStraight(
|
||||
None, "G1", {"Z": pos.z, "F": vertfeed}))
|
||||
|
||||
results.append(extendcommand)
|
||||
return travel
|
||||
|
||||
if obj.StyleOn == "Arc":
|
||||
if obj.ExtendLeadIn != 0:
|
||||
# Insert move to beginning of leadin arc
|
||||
extendcommand = Path.Command(
|
||||
"G1", {"X": leadstart.x, "Y": leadstart.y, "F": horizFeed}
|
||||
)
|
||||
results.append(extendcommand)
|
||||
arcmove = Path.Command(
|
||||
arcdir,
|
||||
{
|
||||
"X": p0.x,
|
||||
"Y": p0.y,
|
||||
"Z": p0.z,
|
||||
"I": offsetvector.x,
|
||||
"J": offsetvector.y,
|
||||
"K": offsetvector.z,
|
||||
"F": horizFeed,
|
||||
},
|
||||
) # add G2/G3 move
|
||||
results.append(arcmove)
|
||||
# elif obj.StyleOn in ["Tangent", "Perpendicular"]:
|
||||
def getTravelEnd(self, obj, pos, last):
|
||||
op = PathDressup.baseOp(obj.Base)
|
||||
travel = []
|
||||
|
||||
# move to clearance height
|
||||
if last or not obj.KeepToolDown:
|
||||
travel.append(PathLanguage.MoveStraight(
|
||||
None, "G0", {"Z": op.ClearanceHeight.Value}))
|
||||
|
||||
return travel
|
||||
|
||||
def angleToVector(self, angle):
|
||||
return App.Vector(math.cos(angle), math.sin(angle), 0)
|
||||
|
||||
def createArcMove(self, obj, begin, end, c):
|
||||
horizfeed = PathDressup.toolController(obj.Base).HorizFeed.Value
|
||||
|
||||
param = {"X": end.x, "Y": end.y, "I": c.x, "J": c.y, "F": horizfeed}
|
||||
if self.getArcDirection(obj) > 0:
|
||||
return PathLanguage.MoveArcCCW(begin, "G3", param)
|
||||
else:
|
||||
extendcommand = Path.Command("G1", {"X": p0.x, "Y": p0.y, "F": horizFeed})
|
||||
results.append(extendcommand)
|
||||
return PathLanguage.MoveArcCW(begin, "G2", param)
|
||||
|
||||
currLocation.update(results[-1].Parameters)
|
||||
currLocation["Z"] = p1.z
|
||||
def createStraightMove(self, obj, begin, end):
|
||||
horizfeed = PathDressup.toolController(obj.Base).HorizFeed.Value
|
||||
|
||||
return results
|
||||
param = {"X": end.x, "Y": end.y, "F": horizfeed}
|
||||
return PathLanguage.MoveStraight(begin, "G1", param)
|
||||
|
||||
def getLeadEnd(self, obj, queue, action):
|
||||
"""returns the Gcode of LeadOut."""
|
||||
results = []
|
||||
horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value
|
||||
arcs_identical = False
|
||||
def getLeadStart(self, obj, move, first):
|
||||
lead = []
|
||||
begin = move.positionBegin()
|
||||
|
||||
# Set the correct twist command
|
||||
if self.getDirectionOfPath(obj) == "right":
|
||||
arcdir = "G2"
|
||||
else:
|
||||
arcdir = "G3"
|
||||
def prepend(instr):
|
||||
nonlocal lead
|
||||
nonlocal begin
|
||||
lead.insert(0, instr)
|
||||
begin = lead[0].positionBegin()
|
||||
|
||||
if queue[1].Name == "G1": # line
|
||||
p0 = queue[0].Placement.Base
|
||||
p1 = queue[1].Placement.Base
|
||||
v = App.Vector(p1.sub(p0)).normalize()
|
||||
else: # dealing with a circle
|
||||
p0 = queue[0].Placement.Base
|
||||
p1 = queue[1].Placement.Base
|
||||
v = App.Vector(p1.sub(p0)).normalize()
|
||||
# tangent begin move
|
||||
# <----_-----x-------------------x
|
||||
# / |
|
||||
# / | normal
|
||||
# | |
|
||||
# x v
|
||||
|
||||
if self.getDirectionOfPath(obj) == "right":
|
||||
off_v = App.Vector(
|
||||
v.y * obj.LengthOut.Value, -v.x * obj.LengthOut.Value, 0.0
|
||||
)
|
||||
else:
|
||||
off_v = App.Vector(
|
||||
-v.y * obj.LengthOut.Value, v.x * obj.LengthOut.Value, 0.0
|
||||
)
|
||||
if obj.LeadIn:
|
||||
length = obj.Length.Value
|
||||
angle = move.anglesOfTangents()[0]
|
||||
tangent = -self.angleToVector(angle) * length
|
||||
normal = self.angleToVector(
|
||||
angle + self.getArcDirection(obj)) * length
|
||||
|
||||
# Check if we leave at line or arc command
|
||||
if queue[1].Name in movecommands and queue[1].Name not in CmdMoveArc:
|
||||
# We have a line move
|
||||
vec_n = App.Vector(p1.sub(p0)).normalize()
|
||||
vec_inv = vec_n
|
||||
vec_inv.multiply(-1)
|
||||
vec_off = App.Vector(vec_inv).multiply(obj.ExtendLeadOut)
|
||||
Path.Log.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
|
||||
pij = App.Vector(p0)
|
||||
pij.x += queue[1].Parameters["I"]
|
||||
pij.y += queue[1].Parameters["J"]
|
||||
ve = pij.sub(p1)
|
||||
# prepend the selected lead-in
|
||||
if obj.StyleOn == "Arc":
|
||||
arcbegin = begin + tangent + normal
|
||||
prepend(self.createArcMove(obj, arcbegin, begin, -tangent))
|
||||
elif obj.StyleOn == "Tangent":
|
||||
prepend(self.createStraightMove(obj, begin + tangent, begin))
|
||||
else: # obj.StyleOn == "Perpendicular"
|
||||
prepend(self.createStraightMove(obj, begin + normal, begin))
|
||||
|
||||
if arcdir == queue[1].Name:
|
||||
arcs_identical = True
|
||||
extend = obj.ExtendLeadIn.Value
|
||||
if extend != 0:
|
||||
# prepend extension
|
||||
extendbegin = begin + normal / length * extend
|
||||
prepend(self.createStraightMove(obj, extendbegin, begin))
|
||||
|
||||
angle = -90 if arcdir == "G2" else 90
|
||||
vec_rot = App.Rotation(App.Vector(0, 0, 1), angle).multVec(ve)
|
||||
# prepend travel moves
|
||||
lead = self.getTravelStart(obj, begin, first) + lead
|
||||
|
||||
vec_n = App.Vector(vec_rot).normalize()
|
||||
v = vec_n
|
||||
return lead
|
||||
|
||||
if arcdir == "G3":
|
||||
off_v = App.Vector(
|
||||
-v.y * obj.LengthOut.Value, v.x * obj.LengthOut.Value, 0.0
|
||||
)
|
||||
else:
|
||||
off_v = App.Vector(
|
||||
v.y * obj.LengthOut.Value, -v.x * obj.LengthOut.Value, 0.0
|
||||
)
|
||||
def getLeadEnd(self, obj, move, last):
|
||||
lead = []
|
||||
end = move.positionEnd()
|
||||
|
||||
vec_inv = vec_rot
|
||||
vec_inv.multiply(-1)
|
||||
def append(instr):
|
||||
nonlocal lead
|
||||
nonlocal end
|
||||
lead.append(instr)
|
||||
end = lead[-1].positionEnd()
|
||||
|
||||
offsetvector = App.Vector(
|
||||
v.x * obj.LengthOut.Value, v.y * obj.LengthOut.Value, 0.0
|
||||
)
|
||||
# if obj.RadiusCenter == "Radius":
|
||||
if obj.StyleOff == "Arc":
|
||||
leadend = (p1.add(off_v)).add(offsetvector)
|
||||
if arcs_identical:
|
||||
t = p1.sub(leadend)
|
||||
t = p1.add(t)
|
||||
leadend = t
|
||||
off_v.multiply(-1)
|
||||
# move end tangent
|
||||
# x-------------------x-----_---->
|
||||
# | \
|
||||
# normal | \
|
||||
# | |
|
||||
# v x
|
||||
|
||||
elif obj.StyleOff == "Tangent":
|
||||
# This is WRONG. Please fix
|
||||
leadend = (p1.add(off_v)).add(offsetvector)
|
||||
if arcs_identical:
|
||||
t = p1.sub(leadend)
|
||||
t = p1.add(t)
|
||||
leadend = t
|
||||
off_v.multiply(-1)
|
||||
else:
|
||||
leadend = p1.add(off_v)
|
||||
if obj.LeadOut:
|
||||
length = obj.LengthOut.Value
|
||||
angle = move.anglesOfTangents()[1]
|
||||
tangent = self.angleToVector(angle) * length
|
||||
normal = self.angleToVector(
|
||||
angle + self.getArcDirection(obj)) * length
|
||||
|
||||
IJ = off_v
|
||||
# At this point leadend is the location of the end of the leadout arc
|
||||
# IJ is an offset from the beginning of the leadout arc to its center.
|
||||
# It is parallel to a tangent line at the end of the leadout arc
|
||||
# Create the normalized tangent vector
|
||||
tangentvecNorm = App.Vector(IJ).normalize()
|
||||
leadlinevec = App.Vector(tangentvecNorm).multiply(obj.ExtendLeadOut)
|
||||
# append the selected lead-out
|
||||
if obj.StyleOff == "Arc":
|
||||
arcend = end + tangent + normal
|
||||
append(self.createArcMove(obj, end, arcend, normal))
|
||||
elif obj.StyleOff == "Tangent":
|
||||
append(self.createStraightMove(obj, end, end + tangent))
|
||||
else: # obj.StyleOff == "Perpendicular"
|
||||
append(self.createStraightMove(obj, end, end + normal))
|
||||
|
||||
extendleadoutend = leadend.add(leadlinevec)
|
||||
extend = obj.ExtendLeadOut.Value
|
||||
if extend != 0:
|
||||
# append extension
|
||||
extendend = end + normal / length * extend
|
||||
append(self.createStraightMove(obj, end, extendend))
|
||||
|
||||
if obj.StyleOff == "Arc":
|
||||
arcmove = Path.Command(
|
||||
arcdir,
|
||||
{
|
||||
"X": leadend.x,
|
||||
"Y": leadend.y,
|
||||
"Z": leadend.z,
|
||||
"I": IJ.x,
|
||||
"J": IJ.y,
|
||||
"K": IJ.z,
|
||||
"F": horizFeed,
|
||||
},
|
||||
) # add G2/G3 move
|
||||
results.append(arcmove)
|
||||
if obj.ExtendLeadOut != 0:
|
||||
extendcommand = Path.Command(
|
||||
"G1",
|
||||
{"X": extendleadoutend.x, "Y": extendleadoutend.y, "F": horizFeed},
|
||||
)
|
||||
results.append(extendcommand)
|
||||
else:
|
||||
extendcommand = Path.Command(
|
||||
"G1", {"X": leadend.x, "Y": leadend.y, "F": horizFeed}
|
||||
)
|
||||
results.append(extendcommand)
|
||||
# append travel moves
|
||||
lead += self.getTravelEnd(obj, end, last)
|
||||
|
||||
return results
|
||||
return lead
|
||||
|
||||
def isCuttingMove(self, obj, instr):
|
||||
return (instr.isMove()
|
||||
and not instr.isRapid()
|
||||
and (not obj.IncludeLayers or not instr.isPlunge()))
|
||||
|
||||
def findLastCuttingMoveIndex(self, obj, source):
|
||||
for i in range(len(source) - 1, -1, -1):
|
||||
if self.isCuttingMove(obj, source[i]):
|
||||
return i
|
||||
return None
|
||||
|
||||
def generateLeadInOutCurve(self, obj):
|
||||
global currLocation
|
||||
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 = []
|
||||
source = PathLanguage.Maneuver.FromPath(
|
||||
PathUtils.getPathWithPlacement(obj.Base)).instr
|
||||
maneuver = PathLanguage.Maneuver()
|
||||
|
||||
# Read in all commands
|
||||
for curCommand in PathUtils.getPathWithPlacement(obj.Base).Commands:
|
||||
Path.Log.debug("CurCMD: {}".format(curCommand))
|
||||
if curCommand.Name not in movecommands + CmdMoveRapid:
|
||||
# Don't worry about non-move commands, just add to output
|
||||
newpath.append(curCommand)
|
||||
# Knowing weather a given instruction is the first cutting move is easy,
|
||||
# we just use a flag and set it to false afterwards. To find the last
|
||||
# cutting move we need to search the list in reverse order.
|
||||
first = True
|
||||
lastCuttingMoveIndex = self.findLastCuttingMoveIndex(obj, source)
|
||||
|
||||
for i, instr in enumerate(source):
|
||||
if not self.isCuttingMove(obj, instr):
|
||||
# non-move instructions get added verbatim
|
||||
if not instr.isMove():
|
||||
maneuver.addInstruction(instr)
|
||||
|
||||
# skip travel and plunge moves, travel moves will be added in
|
||||
# getLeadStart and getLeadEnd
|
||||
continue
|
||||
|
||||
if curCommand.Name in CmdMoveRapid:
|
||||
# We don't care about rapid moves
|
||||
prevCmd = curCommand
|
||||
currLocation.update(curCommand.Parameters)
|
||||
continue
|
||||
if first or not self.isCuttingMove(obj, source[i - 1]):
|
||||
# add lead start and travel moves
|
||||
maneuver.addInstructions(self.getLeadStart(obj, instr, first))
|
||||
first = False
|
||||
|
||||
if curCommand.Name in movecommands:
|
||||
if (
|
||||
prevCmd.Name in CmdMoveRapid
|
||||
and curCommand.Name in movecommands
|
||||
and len(queue) > 0
|
||||
):
|
||||
# Layer changed: Save current layer cmds and prepare next layer
|
||||
layers.append(queue)
|
||||
queue = []
|
||||
if (
|
||||
obj.IncludeLayers
|
||||
and curCommand.z < currLocation["Z"] and not Path.Geom.isRoughly(curCommand.z, currLocation["Z"])
|
||||
and prevCmd.Name in movecommands
|
||||
):
|
||||
# Layer change within move cmds
|
||||
Path.Log.debug(
|
||||
"Layer change in move: {}->{}".format(
|
||||
currLocation["Z"], curCommand.z
|
||||
)
|
||||
)
|
||||
layers.append(queue)
|
||||
queue = []
|
||||
# add current move
|
||||
maneuver.addInstruction(instr)
|
||||
|
||||
# Save all move commands
|
||||
# getLeadStart and getLeadEnd incorrectly treat missing axis words as being 0.
|
||||
currXYZ = { k: currLocation[k] for k in "XYZ" if k in currLocation }
|
||||
tmp = Path.Command(curCommand.Name, currXYZ | curCommand.Parameters)
|
||||
queue.append(tmp)
|
||||
last = i == lastCuttingMoveIndex
|
||||
if last or not self.isCuttingMove(obj, source[i + 1]):
|
||||
# add lead end and travel moves
|
||||
maneuver.addInstructions(self.getLeadEnd(obj, instr, last))
|
||||
|
||||
currLocation.update(curCommand.Parameters)
|
||||
prevCmd = curCommand
|
||||
|
||||
# Add last layer
|
||||
if len(queue) > 0:
|
||||
layers.append(queue)
|
||||
|
||||
# Go through each layer and add leadIn/Out
|
||||
idx = 0
|
||||
for layer in layers:
|
||||
Path.Log.debug("Layer {}".format(idx))
|
||||
|
||||
if obj.LeadIn:
|
||||
temp = self.getLeadStart(obj, layer, action)
|
||||
newpath.extend(temp)
|
||||
|
||||
for cmd in layer:
|
||||
Path.Log.debug("CurLoc: {}, NewCmd: {}!!".format(currLocation, cmd))
|
||||
newpath.append(cmd)
|
||||
|
||||
if obj.LeadOut:
|
||||
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)
|
||||
return maneuver.toPath()
|
||||
|
||||
|
||||
class TaskDressupLeadInOut(SimpleEditPanel):
|
||||
|
||||
@@ -192,8 +192,8 @@ class ObjectDressup:
|
||||
def setup(self, obj):
|
||||
obj.Angle = 60
|
||||
obj.Method = 2
|
||||
if PathDressup.baseOp(obj).StartDepth is not None:
|
||||
obj.DressupStartDepth = PathDressup.baseOp(obj).StartDepth
|
||||
if PathDressup.baseOp(obj.Base).StartDepth is not None:
|
||||
obj.DressupStartDepth = PathDressup.baseOp(obj.Base).StartDepth
|
||||
|
||||
def execute(self, obj):
|
||||
if not obj.Base:
|
||||
@@ -203,7 +203,7 @@ class ObjectDressup:
|
||||
if not obj.Base.Path:
|
||||
return
|
||||
|
||||
if hasattr(obj.Base, 'Active') and not obj.Base.Active:
|
||||
if not PathDressup.baseOp(obj.Base).Active:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
return
|
||||
|
||||
@@ -868,12 +868,9 @@ class PathData:
|
||||
return (currentLength, lastTagLength)
|
||||
|
||||
def defaultTagHeight(self):
|
||||
if (
|
||||
hasattr(self.obj, "Base")
|
||||
and hasattr(self.obj.Base, "StartDepth")
|
||||
and hasattr(self.obj.Base, "FinalDepth")
|
||||
):
|
||||
pathHeight = (self.obj.Base.StartDepth - self.obj.Base.FinalDepth).Value
|
||||
op = PathDressup.baseOp(self.obj.Base)
|
||||
if hasattr(op, "StartDepth") and hasattr(op, "FinalDepth"):
|
||||
pathHeight = (op.StartDepth - op.FinalDepth).Value
|
||||
else:
|
||||
pathHeight = self.maxZ - self.minZ
|
||||
height = HoldingTagPreferences.defaultHeight(pathHeight / 2)
|
||||
|
||||
@@ -77,7 +77,7 @@ class SimpleEditPanel:
|
||||
elif prop_type in PROP_TYPE_NUMERIC and widget_type == "QDoubleSpinBox":
|
||||
self._fc[prop_name] = widget.value, widget.setValue
|
||||
elif prop_type in PROP_TYPE_QTYES and widget_type == "QLineEdit":
|
||||
self._fc[prop_name] = widget.text, lambda v: widget.setText(str(v))
|
||||
self._fc[prop_name] = widget.text, lambda v: widget.setText(v.UserString)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unsupported connection between '{prop_type}' property and '{widget_type}' widget"
|
||||
|
||||
@@ -47,6 +47,8 @@ class MockTC(object):
|
||||
|
||||
class MockOp(object):
|
||||
def __init__(self, path, dia=2):
|
||||
self.Name = "OP"
|
||||
self.Label = "OP"
|
||||
self.Path = Path.Path(path)
|
||||
self.ToolController = MockTC(dia)
|
||||
|
||||
@@ -85,7 +87,7 @@ class MockFeaturePython(object):
|
||||
|
||||
def CreateDressup(path):
|
||||
op = MockOp(path)
|
||||
obj = MockFeaturePython("DogboneII")
|
||||
obj = MockFeaturePython("DressupDogbone")
|
||||
db = Path.Dressup.DogboneII.Proxy(obj, op)
|
||||
obj.Proxy = db
|
||||
return obj
|
||||
@@ -626,7 +628,7 @@ class TestDressupDogboneII(PathTestUtils.PathTestBase):
|
||||
|
||||
obj = self.test90()
|
||||
|
||||
obj2 = MockFeaturePython("DogboneII_")
|
||||
obj2 = MockFeaturePython("DressupDogbone001")
|
||||
db2 = Path.Dressup.DogboneII.Proxy(obj2, obj)
|
||||
obj2.Proxy = db2
|
||||
obj2.Incision = Path.Dressup.DogboneII.Incision.Fixed
|
||||
|
||||
Reference in New Issue
Block a user