diff --git a/src/Mod/CAM/Gui/Resources/panels/ToolControllerEdit.ui b/src/Mod/CAM/Gui/Resources/panels/ToolControllerEdit.ui
index bbb94b24b2..44933258dd 100644
--- a/src/Mod/CAM/Gui/Resources/panels/ToolControllerEdit.ui
+++ b/src/Mod/CAM/Gui/Resources/panels/ToolControllerEdit.ui
@@ -117,14 +117,14 @@
-
-
+
- Horizontal rapid
+ Lead-in feed
-
-
+
0
@@ -146,13 +146,100 @@
-
+
+
+ Lead-out feed
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 0.000000000000000
+
+
+ 9999999.000000000000000
+
+
+ mm/s
+
+
+
+ -
+
+
+ Ramp feed
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 0.000000000000000
+
+
+ 9999999.000000000000000
+
+
+ mm/s
+
+
+
+ -
+
+
+ Horizontal rapid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 0.000000000000000
+
+
+ 9999999.000000000000000
+
+
+ mm/s
+
+
+
+ -
Vertical rapid
- -
+
-
diff --git a/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py b/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py
index d6c1fcc536..e9bc190649 100644
--- a/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py
+++ b/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py
@@ -253,6 +253,8 @@ class ObjectDressup:
self.horizFeed = self.toolController.HorizFeed.Value
self.vertFeed = self.toolController.VertFeed.Value
+ self.entranceFeed = self.toolController.LeadInFeed.Value
+ self.exitFeed = self.toolController.LeadOutFeed.Value
obj.Path = self.generateLeadInOutCurve(obj)
@@ -499,14 +501,14 @@ class ObjectDressup:
return App.Vector(math.cos(angle), math.sin(angle), 0)
# Create arc in XY plane with automatic detection G2|G3
- def createArcMove(self, obj, begin, end, offset, invert=False):
+ def createArcMove(self, obj, begin, end, offset, invert, feedRate):
param = {
"X": end.x,
"Y": end.y,
"Z": end.z,
"I": offset.x,
"J": offset.y,
- "F": self.horizFeed,
+ "F": feedRate,
}
if self.getLeadDir(obj, invert) > 0:
command = PathLanguage.MoveArcCCW(begin, "G3", param)
@@ -516,8 +518,8 @@ class ObjectDressup:
return command
# Create arc in XY plane with manually set G2|G3
- def createArcMoveN(self, obj, begin, end, offset, cmdName):
- param = {"X": end.x, "Y": end.y, "I": offset.x, "J": offset.y, "F": self.horizFeed}
+ def createArcMoveN(self, obj, begin, end, offset, cmdName, feedRate):
+ param = {"X": end.x, "Y": end.y, "I": offset.x, "J": offset.y, "F": feedRate}
if cmdName == "G2":
command = PathLanguage.MoveArcCW(begin, cmdName, param)
else:
@@ -526,8 +528,8 @@ class ObjectDressup:
return command
# Create line movement G1
- def createStraightMove(self, obj, begin, end):
- param = {"X": end.x, "Y": end.y, "Z": end.z, "F": self.horizFeed}
+ def createStraightMove(self, obj, begin, end, feedRate):
+ param = {"X": end.x, "Y": end.y, "Z": end.z, "F": feedRate}
command = PathLanguage.MoveStraight(begin, "G1", param)
return command
@@ -549,7 +551,7 @@ class ObjectDressup:
return stepAngle
# Create vertical arc with move Down by line segments
- def createArcZMoveDown(self, obj, begin, end, radius):
+ def createArcZMoveDown(self, obj, begin, end, radius, feedRate):
commands = []
angle = math.acos((radius - begin.z + end.z) / radius) # start angle
stepAngle = self.getStepAngleArcZ(obj, radius)
@@ -568,7 +570,7 @@ class ObjectDressup:
else:
# exclude error of calculations for the last iteration
iterEnd = copy.copy(end)
- param = {"X": iterEnd.x, "Y": iterEnd.y, "Z": iterEnd.z, "F": self.horizFeed}
+ param = {"X": iterEnd.x, "Y": iterEnd.y, "Z": iterEnd.z, "F": feedRate}
commands.append(PathLanguage.MoveStraight(iterBegin, "G1", param))
iterBegin = copy.copy(iterEnd)
iter += 1
@@ -576,7 +578,7 @@ class ObjectDressup:
return commands
# Create vertical arc with move Up by line segments
- def createArcZMoveUp(self, obj, begin, end, radius):
+ def createArcZMoveUp(self, obj, begin, end, radius, feedRate):
commands = []
angleMax = math.acos((radius - end.z + begin.z) / radius) # finish angle
stepAngle = self.getStepAngleArcZ(obj, radius)
@@ -596,7 +598,7 @@ class ObjectDressup:
else:
# exclude the error of calculations of the last point
iterEnd = copy.copy(end)
- param = {"X": iterEnd.x, "Y": iterEnd.y, "Z": iterEnd.z, "F": self.horizFeed}
+ param = {"X": iterEnd.x, "Y": iterEnd.y, "Z": iterEnd.z, "F": feedRate}
commands.append(PathLanguage.MoveStraight(iterBegin, "G1", param))
iterBegin = copy.copy(iterEnd)
iter += 1
@@ -654,7 +656,11 @@ class ObjectDressup:
arcBegin = begin + tangent + normal
arcCenter = begin + normalMax
arcOffset = arcCenter - arcBegin
- lead.append(self.createArcMove(obj, arcBegin, begin, arcOffset, obj.InvertIn))
+ lead.append(
+ self.createArcMove(
+ obj, arcBegin, begin, arcOffset, obj.InvertIn, self.entranceFeed
+ )
+ )
# prepend "Line" style lead-in - line in XY
# Line3d the same as Line, but increased Z start point
@@ -668,7 +674,7 @@ class ObjectDressup:
* normalLength
)
lineBegin = begin + tangent + normal
- lead.append(self.createStraightMove(obj, lineBegin, begin))
+ lead.append(self.createStraightMove(obj, lineBegin, begin, self.entranceFeed))
# prepend "LineZ" style lead-in - vertical inclined line
# Should be applied only on straight Path segment
@@ -683,7 +689,7 @@ class ObjectDressup:
tangent = -self.angleToVector(angleTangent) * tangentLength
normal = App.Vector(0, 0, normalLength)
lineBegin = begin + tangent + normal
- lead.append(self.createStraightMove(obj, lineBegin, begin))
+ lead.append(self.createStraightMove(obj, lineBegin, begin, self.entranceFeed))
# prepend "ArcZ" style lead-in - vertical Arc
# Should be applied only on straight Path segment
@@ -702,7 +708,9 @@ class ObjectDressup:
tangent = -self.angleToVector(angleTangent) * tangentLength
normal = App.Vector(0, 0, normalLength)
arcBegin = begin + tangent + normal
- lead.extend(self.createArcZMoveDown(obj, arcBegin, begin, arcRadius))
+ lead.extend(
+ self.createArcZMoveDown(obj, arcBegin, begin, arcRadius, self.entranceFeed)
+ )
# replace 'begin' position with first lead-in command
begin = lead[0].positionBegin()
@@ -742,7 +750,7 @@ class ObjectDressup:
travelToStart = self.getTravelStart(obj, begin, first, outInstrPrev)
else:
# exclude any lead-in commands
- param = {"X": begin.x, "Y": begin.y, "Z": begin.z, "F": self.horizFeed}
+ param = {"X": begin.x, "Y": begin.y, "Z": begin.z, "F": self.entranceFeed}
travelToStart = [PathLanguage.MoveStraight(None, "G01", param)]
lead = travelToStart + lead
@@ -790,7 +798,9 @@ class ObjectDressup:
* normalLength
)
arcEnd = end + tangent + normal
- lead.append(self.createArcMove(obj, end, arcEnd, normalMax, obj.InvertOut))
+ lead.append(
+ self.createArcMove(obj, end, arcEnd, normalMax, obj.InvertOut, self.exitFeed)
+ )
# append "Line" style lead-out
# Line3d the same as Line, but increased Z start point
@@ -804,7 +814,7 @@ class ObjectDressup:
* normalLength
)
lineEnd = end + tangent + normal
- lead.append(self.createStraightMove(obj, end, lineEnd))
+ lead.append(self.createStraightMove(obj, end, lineEnd, self.exitFeed))
# append "LineZ" style lead-out - vertical inclined line
# Should be apply only on straight Path segment
@@ -819,7 +829,7 @@ class ObjectDressup:
tangent = self.angleToVector(angleTangent) * tangentLength
normal = App.Vector(0, 0, normalLength)
lineEnd = end + tangent + normal
- lead.append(self.createStraightMove(obj, end, lineEnd))
+ lead.append(self.createStraightMove(obj, end, lineEnd, self.exitFeed))
# prepend "ArcZ" style lead-out - vertical Arc
# Should be apply only on straight Path segment
@@ -838,7 +848,7 @@ class ObjectDressup:
tangent = self.angleToVector(angleTangent) * tangentLength
normal = App.Vector(0, 0, normalLength)
arcEnd = end + tangent + normal
- lead.extend(self.createArcZMoveUp(obj, end, arcEnd, arcRadius))
+ lead.extend(self.createArcZMoveUp(obj, end, arcEnd, arcRadius, self.exitFeed))
if obj.StyleOut in ("Arc3d", "Line3d"):
# Up Z end point for Arc3d and Line3d
@@ -996,7 +1006,7 @@ class ObjectDressup:
n = math.hypot(v.x, v.y)
u = v / n
cutEnd = begin + u * newLength
- command = self.createStraightMove(obj, begin, cutEnd)
+ command = self.createStraightMove(obj, begin, cutEnd, self.horizFeed)
# Cut arc move from begin
elif instr.isArc():
@@ -1011,7 +1021,7 @@ class ObjectDressup:
normal = self.angleToVector(angleTangent + self.getPathDir(obj)) * normalLength
arcEnd = arcBegin + tangent + normal
cmdName = "G2" if instr.isCW() else "G3"
- command = self.createArcMoveN(obj, arcBegin, arcEnd, arcOffset, cmdName)
+ command = self.createArcMoveN(obj, arcBegin, arcEnd, arcOffset, cmdName, self.horizFeed)
return command
@@ -1025,7 +1035,7 @@ class ObjectDressup:
n = math.hypot(v.x, v.y)
u = v / n
newBegin = end - u * newLength
- command = self.createStraightMove(obj, newBegin, end)
+ command = self.createStraightMove(obj, newBegin, end, self.horizFeed)
return command
# Cut arc move from begin
@@ -1042,7 +1052,7 @@ class ObjectDressup:
arcBegin = arcEnd + tangent + normal
arcOffset = arcCenter - arcBegin
cmdName = "G2" if instr.isCW() else "G3"
- command = self.createArcMoveN(obj, arcBegin, arcEnd, arcOffset, cmdName)
+ command = self.createArcMoveN(obj, arcBegin, arcEnd, arcOffset, cmdName, self.horizFeed)
return command
return None
@@ -1188,6 +1198,8 @@ class TaskDressupLeadInOut(SimpleEditPanel):
def setupSpinBoxes(self):
self.connectWidget("InvertIn", self.form.chkInvertDirectionIn)
self.connectWidget("InvertOut", self.form.chkInvertDirectionOut)
+ self.connectWidget("PercentageRadiusIn", self.form.dspPercentageRadiusIn)
+ self.connectWidget("PercentageRadiusOut", self.form.dspPercentageRadiusOut)
self.connectWidget("StyleIn", self.form.cboStyleIn)
self.connectWidget("StyleOut", self.form.cboStyleOut)
self.radiusIn = PathGuiUtil.QuantitySpinBox(self.form.dspRadiusIn, self.obj, "RadiusIn")
diff --git a/src/Mod/CAM/Path/Dressup/Gui/RampEntry.py b/src/Mod/CAM/Path/Dressup/Gui/RampEntry.py
index 02c19c7be0..47def949bf 100644
--- a/src/Mod/CAM/Path/Dressup/Gui/RampEntry.py
+++ b/src/Mod/CAM/Path/Dressup/Gui/RampEntry.py
@@ -181,18 +181,6 @@ class ObjectDressup:
"Path",
QT_TRANSLATE_NOOP("App::Property", "Ramping Method"),
)
- obj.addProperty(
- "App::PropertyEnumeration",
- "RampFeedRate",
- "FeedRate",
- QT_TRANSLATE_NOOP("App::Property", "Which feed rate to use for ramping"),
- )
- obj.addProperty(
- "App::PropertySpeed",
- "CustomFeedRate",
- "FeedRate",
- QT_TRANSLATE_NOOP("App::Property", "Custom feed rate"),
- )
obj.addProperty(
"App::PropertyBool",
"UseStartDepth",
@@ -246,21 +234,6 @@ class ObjectDressup:
(translate("CAM_DressupRampEntry", "RampMethod3"), "RampMethod3"),
(translate("CAM_DressupRampEntry", "Helix"), "Helix"),
],
- "RampFeedRate": [
- (
- translate("CAM_DressupRampEntry", "Horizontal Feed Rate"),
- "Horizontal Feed Rate",
- ),
- (
- translate("CAM_DressupRampEntry", "Vertical Feed Rate"),
- "Vertical Feed Rate",
- ),
- (
- translate("CAM_DressupRampEntry", "Ramp Feed Rate"),
- "Ramp Feed Rate",
- ),
- (translate("CAM_DressupRampEntry", "Custom"), "Custom"),
- ],
}
if dataType == "raw":
@@ -284,7 +257,7 @@ class ObjectDressup:
return None
def onChanged(self, obj, prop):
- if prop in ["RampFeedRate", "UseStartDepth"]:
+ if prop in ["UseStartDepth"]:
self.setEditorProperties(obj)
if prop == "Path" and obj.ViewObject:
obj.ViewObject.signalChangeIcon()
@@ -296,14 +269,24 @@ class ObjectDressup:
else:
obj.setEditorMode("DressupStartDepth", 2)
- if obj.RampFeedRate == "Custom":
- obj.setEditorMode("CustomFeedRate", 0)
- else:
- obj.setEditorMode("CustomFeedRate", 2)
-
def onDocumentRestored(self, obj):
self.setEditorProperties(obj)
+ # Remove RampFeedRate + CustomFeedRate properties, but keep the values around temporarily
+ # This is required for tool controller migration: if a TC migrates with onDocumentRestored
+ # called after this, the prior ramp feed rate still needs to be accessible.
+ if hasattr(obj, "RampFeedRate"):
+ obj.Proxy.RampFeedRate = obj.RampFeedRate
+ obj.removeProperty("RampFeedRate")
+
+ if hasattr(obj, "CustomFeedRate"):
+ tmp = obj.CustomFeedRate.Value
+ for prop, exp in obj.ExpressionEngine:
+ if prop == "CustomFeedRate":
+ tmp = exp
+ obj.Proxy.CustomFeedRate = tmp
+ obj.removeProperty("CustomFeedRate")
+
def setup(self, obj):
obj.Angle = 60
obj.Method = 2
@@ -683,15 +666,7 @@ class ObjectDressup:
vertFeed = tc.VertFeed.Value
horizRapid = tc.HorizRapid.Value
vertRapid = tc.VertRapid.Value
-
- if obj.RampFeedRate == "Horizontal Feed Rate":
- rampFeed = horizFeed
- elif obj.RampFeedRate == "Vertical Feed Rate":
- rampFeed = vertFeed
- elif obj.RampFeedRate == "Ramp Feed Rate":
- rampFeed = math.sqrt(pow(vertFeed, 2) + pow(horizFeed, 2))
- else:
- rampFeed = obj.CustomFeedRate.Value
+ rampFeed = tc.RampFeed.Value
lastX = lastY = lastZ = 0
for cmd in commands:
diff --git a/src/Mod/CAM/Path/Main/Job.py b/src/Mod/CAM/Path/Main/Job.py
index 03afd88d84..8e5eb8837e 100644
--- a/src/Mod/CAM/Path/Main/Job.py
+++ b/src/Mod/CAM/Path/Main/Job.py
@@ -705,7 +705,7 @@ class ObjectJob:
"VertRapid",
"%s.%s"
% (
- self.setupSheet.expressionReference(),
+ self.obj.SetupSheet.Proxy.expressionReference(),
PathSetupSheet.Template.VertRapid,
),
)
@@ -713,7 +713,7 @@ class ObjectJob:
"HorizRapid",
"%s.%s"
% (
- self.setupSheet.expressionReference(),
+ self.obj.SetupSheet.Proxy.expressionReference(),
PathSetupSheet.Template.HorizRapid,
),
)
diff --git a/src/Mod/CAM/Path/Op/Gui/Base.py b/src/Mod/CAM/Path/Op/Gui/Base.py
index da8cb52ac5..25e4668551 100644
--- a/src/Mod/CAM/Path/Op/Gui/Base.py
+++ b/src/Mod/CAM/Path/Op/Gui/Base.py
@@ -429,22 +429,8 @@ class TaskPanelPage(object):
def copyToolController(self):
oldTc = self.tcEditor.obj
self.tcEditor.updateToolController()
- tc = PathToolController.Create(
- name=oldTc.Label, tool=oldTc.Tool, toolNumber=oldTc.ToolNumber
- )
job = self.obj.Proxy.getJob(self.obj)
- job.Proxy.addToolController(tc)
-
- tc.HorizFeed = oldTc.HorizFeed
- tc.VertFeed = oldTc.VertFeed
- tc.HorizRapid = oldTc.HorizRapid
- tc.VertRapid = oldTc.VertRapid
- tc.SpindleSpeed = oldTc.SpindleSpeed
- tc.SpindleDir = oldTc.SpindleDir
- for attr, expr in oldTc.ExpressionEngine:
- tc.setExpression(attr, expr)
-
- self.obj.ToolController = tc
+ self.obj.ToolController = PathToolController.copyTC(oldTc, job)
self.setupToolController()
def tcEditorChanged(self):
diff --git a/src/Mod/CAM/Path/Op/Profile.py b/src/Mod/CAM/Path/Op/Profile.py
index ca8ebbb333..a045372f52 100644
--- a/src/Mod/CAM/Path/Op/Profile.py
+++ b/src/Mod/CAM/Path/Op/Profile.py
@@ -313,9 +313,6 @@ class ObjectProfile(PathAreaOp.ObjectOp):
def areaOpOnDocumentRestored(self, obj):
self.propertiesReady = False
- self.initAreaOpProperties(obj, warn=True)
- self.areaOpSetDefaultValues(obj, PathUtils.findParentJob(obj))
- self.setOpEditorProperties(obj)
if not hasattr(obj, "NumPasses"):
obj.addProperty(
"App::PropertyInteger",
@@ -326,6 +323,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
"The number of passes to do. Requires a non-zero value for Stepover",
),
)
+
if not hasattr(obj, "Stepover"):
obj.addProperty(
"App::PropertyDistance",
@@ -337,6 +335,10 @@ class ObjectProfile(PathAreaOp.ObjectOp):
),
)
+ self.initAreaOpProperties(obj, warn=True)
+ self.areaOpSetDefaultValues(obj, PathUtils.findParentJob(obj))
+ self.setOpEditorProperties(obj)
+
def areaOpOnChanged(self, obj, prop):
"""areaOpOnChanged(obj, prop) ... updates certain property visibilities depending on changed properties."""
if prop in ["UseComp", "JoinType", "Base"]:
diff --git a/src/Mod/CAM/Path/Tool/Controller.py b/src/Mod/CAM/Path/Tool/Controller.py
index d76b8f9c07..ec62888287 100644
--- a/src/Mod/CAM/Path/Tool/Controller.py
+++ b/src/Mod/CAM/Path/Tool/Controller.py
@@ -49,7 +49,10 @@ class ToolControllerTemplate:
HorizFeed = "hfeed"
HorizRapid = "hrapid"
Label = "label"
+ LeadInFeed = "leadinfeed"
+ LeadOutFeed = "leadoutfeed"
Name = "name"
+ RampFeed = "rampfeed"
SpindleDir = "dir"
SpindleSpeed = "speed"
ToolNumber = "nr"
@@ -59,6 +62,77 @@ class ToolControllerTemplate:
VertRapid = "vrapid"
+def _migrateRampDressups(tc):
+ # Enumerate ramp dressups using this TC and their feed rates
+ ramps = set()
+ job_ramp_feeds = []
+ for job in tc.Document.Objects:
+ if hasattr(job, "Operations") and hasattr(job.Operations, "Group"):
+ for op in job.Operations.Group:
+ for ramp in [op] + op.OutListRecursive:
+ if ramp not in ramps and (
+ hasattr(ramp, "RampFeedRate")
+ or (hasattr(ramp, "Proxy") and hasattr(ramp.Proxy, "RampFeedRate"))
+ ):
+ rampFeedRate = (
+ ramp.RampFeedRate
+ if hasattr(ramp, "RampFeedRate")
+ else ramp.Proxy.RampFeedRate
+ )
+ if hasattr(ramp, "CustomFeedRate"):
+ customFeedRate = ramp.CustomFeedRate.Value
+ for prop, exp in ramp.ExpressionEngine:
+ if prop == "CustomFeedRate":
+ customFeedRate = exp
+ else:
+ customFeedRate = (
+ ramp.Proxy.CustomFeedRate
+ if hasattr(ramp.Proxy, "CustomFeedRate")
+ else "HorizFeed"
+ )
+
+ if op.Base.ToolController == tc:
+ ramps.add(ramp)
+ if rampFeedRate == "Horizontal Feed Rate":
+ feed = "HorizFeed"
+ elif rampFeedRate == "Vertical Feed Rate":
+ feed = "VertFeed"
+ elif rampFeedRate == "Ramp Feed Rate":
+ feed = "sqrt(HorizFeed * HorizFeed + VertFeed * VertFeed)"
+ else:
+ feed = customFeedRate
+ job_ramp_feeds.append((job, ramp, feed))
+
+ # Ensure there is a TC for each required feed, starting with this one
+ feed_to_tc = {}
+ for i, (job, ramp, feed) in enumerate(job_ramp_feeds):
+ if feed in feed_to_tc:
+ continue
+
+ if len(feed_to_tc) == 0:
+ opTc = tc
+ else:
+ opTc = copyTC(tc, job)
+ # Note: C++ doesn't try to deduplicate the Labels of objects created
+ # during document restore, so here we will reuse the (deduplicated)
+ # name as the label
+ opTc.Label = opTc.Name
+
+ feed_to_tc[feed] = opTc
+
+ if isinstance(feed, str):
+ opTc.setExpression("RampFeed", feed)
+ else:
+ opTc.setExpression("RampFeed", None)
+ opTc.RampFeed = feed
+ if opTc is not tc:
+ opTc.recompute()
+
+ # Loop over ramps and assign each one the appropriate TC
+ for _, ramp, feed in job_ramp_feeds:
+ ramp.Base.ToolController = feed_to_tc[feed]
+
+
class ToolController:
def __init__(self, obj, createTool=True):
Path.Log.track("tool: ")
@@ -106,6 +180,31 @@ class ToolController:
"Rapid",
QT_TRANSLATE_NOOP("App::Property", "Rapid rate for horizontal moves"),
)
+
+ obj.addProperty(
+ "App::PropertySpeed",
+ "RampFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for ramp moves"),
+ )
+ obj.setExpression("RampFeed", "HorizFeed")
+
+ obj.addProperty(
+ "App::PropertySpeed",
+ "LeadInFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for lead-in moves"),
+ )
+ obj.setExpression("LeadInFeed", "HorizFeed")
+
+ obj.addProperty(
+ "App::PropertySpeed",
+ "LeadOutFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for lead-out moves"),
+ )
+ obj.setExpression("LeadOutFeed", "HorizFeed")
+
obj.setEditorMode("Placement", 2)
for n in self.propertyEnumerations():
@@ -166,6 +265,40 @@ class ToolController:
obj.setEditorMode("Placement", 2)
+ needsRecompute = False
+ if not hasattr(obj, "RampFeed"):
+ obj.addProperty(
+ "App::PropertySpeed",
+ "RampFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for ramp moves"),
+ )
+ _migrateRampDressups(obj)
+ needsRecompute = True
+
+ if not hasattr(obj, "LeadInFeed"):
+ obj.addProperty(
+ "App::PropertySpeed",
+ "LeadInFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for lead-in moves"),
+ )
+ obj.setExpression("LeadInFeed", "HorizFeed")
+ needsRecompute = True
+
+ if not hasattr(obj, "LeadOutFeed"):
+ obj.addProperty(
+ "App::PropertySpeed",
+ "LeadOutFeed",
+ "Feed",
+ QT_TRANSLATE_NOOP("App::Property", "Feed rate for lead-out moves"),
+ )
+ obj.setExpression("LeadOutFeed", "HorizFeed")
+ needsRecompute = True
+
+ if needsRecompute:
+ obj.recompute()
+
def onDelete(self, obj, arg2=None):
if hasattr(obj.Tool, "InList") and len(obj.Tool.InList) == 1:
if hasattr(obj.Tool.Proxy, "onDelete"):
@@ -181,12 +314,22 @@ class ToolController:
if template.get(ToolControllerTemplate.Version):
version = int(template.get(ToolControllerTemplate.Version))
if version == 1 or version == 2:
+ # TODO figure out the meaning of this, and how to handle ramp/leadin/leadout feed rates
+ # or what else must be added to templates
if template.get(ToolControllerTemplate.Label):
obj.Label = template.get(ToolControllerTemplate.Label)
if template.get(ToolControllerTemplate.VertFeed):
obj.VertFeed = template.get(ToolControllerTemplate.VertFeed)
if template.get(ToolControllerTemplate.HorizFeed):
obj.HorizFeed = template.get(ToolControllerTemplate.HorizFeed)
+ if template.get(ToolControllerTemplate.LeadInFeed):
+ obj.LeadInFeed = template.get(ToolControllerTemplate.LeadInFeed, obj.LeadInFeed)
+ if template.get(ToolControllerTemplate.LeadOutFeed):
+ obj.LeadOutFeed = template.get(
+ ToolControllerTemplate.LeadOutFeed, obj.LeadOutFeed
+ )
+ if template.get(ToolControllerTemplate.RampFeed):
+ obj.RampFeed = template.get(ToolControllerTemplate.RampFeed, obj.RampFeed)
if template.get(ToolControllerTemplate.VertRapid):
obj.VertRapid = template.get(ToolControllerTemplate.VertRapid)
if template.get(ToolControllerTemplate.HorizRapid):
@@ -241,6 +384,9 @@ class ToolController:
attrs[ToolControllerTemplate.ToolNumber] = obj.ToolNumber
attrs[ToolControllerTemplate.VertFeed] = "%s" % (obj.VertFeed)
attrs[ToolControllerTemplate.HorizFeed] = "%s" % (obj.HorizFeed)
+ attrs[ToolControllerTemplate.LeadInFeed] = "%s" % (obj.LeadInFeed)
+ attrs[ToolControllerTemplate.LeadOutFeed] = "%s" % (obj.LeadOutFeed)
+ attrs[ToolControllerTemplate.RampFeed] = "%s" % (obj.RampFeed)
attrs[ToolControllerTemplate.VertRapid] = "%s" % (obj.VertRapid)
attrs[ToolControllerTemplate.HorizRapid] = "%s" % (obj.HorizRapid)
attrs[ToolControllerTemplate.SpindleSpeed] = obj.SpindleSpeed
@@ -327,6 +473,23 @@ def Create(
return obj
+def copyTC(tc, job):
+ newtc = Create(name=tc.Label, tool=tc.Tool, toolNumber=tc.ToolNumber)
+ job.Proxy.addToolController(newtc)
+
+ for prop in tc.PropertiesList:
+ try:
+ if prop not in ["Label", "Label2"]:
+ setattr(newtc, prop, getattr(tc, prop))
+ except RuntimeError:
+ # Ignore errors for read-only properties
+ pass
+ for attr, expr in tc.ExpressionEngine:
+ newtc.setExpression(attr, expr)
+
+ return newtc
+
+
def FromTemplate(template, assignViewProvider=True):
Path.Log.track()
diff --git a/src/Mod/CAM/Path/Tool/Gui/Controller.py b/src/Mod/CAM/Path/Tool/Gui/Controller.py
index 146897e22a..332706856c 100644
--- a/src/Mod/CAM/Path/Tool/Gui/Controller.py
+++ b/src/Mod/CAM/Path/Tool/Gui/Controller.py
@@ -218,6 +218,11 @@ class ToolControllerEditor(object):
PathGuiUtil.populateCombobox(self.controller, enumTups, comboToPropertyMap)
self.vertFeed = PathGuiUtil.QuantitySpinBox(self.controller.vertFeed, obj, "VertFeed")
self.horizFeed = PathGuiUtil.QuantitySpinBox(self.controller.horizFeed, obj, "HorizFeed")
+ self.leadInFeed = PathGuiUtil.QuantitySpinBox(self.controller.leadInFeed, obj, "LeadInFeed")
+ self.leadOutFeed = PathGuiUtil.QuantitySpinBox(
+ self.controller.leadOutFeed, obj, "LeadOutFeed"
+ )
+ self.rampFeed = PathGuiUtil.QuantitySpinBox(self.controller.rampFeed, obj, "RampFeed")
self.vertRapid = PathGuiUtil.QuantitySpinBox(self.controller.vertRapid, obj, "VertRapid")
self.horizRapid = PathGuiUtil.QuantitySpinBox(self.controller.horizRapid, obj, "HorizRapid")
@@ -260,6 +265,9 @@ class ToolControllerEditor(object):
self.controller.tcNumber,
self.horizFeed.widget,
self.horizRapid.widget,
+ self.leadInFeed.widget,
+ self.leadOutFeed.widget,
+ self.rampFeed.widget,
self.vertFeed.widget,
self.vertRapid.widget,
self.controller.spindleSpeed,
@@ -273,6 +281,9 @@ class ToolControllerEditor(object):
self.controller.tcNumber.setValue(tc.ToolNumber)
self.horizFeed.updateWidget()
self.horizRapid.updateWidget()
+ self.leadInFeed.updateWidget()
+ self.leadOutFeed.updateWidget()
+ self.rampFeed.updateWidget()
self.vertFeed.updateWidget()
self.vertRapid.updateWidget()
self.controller.spindleSpeed.setValue(tc.SpindleSpeed)
@@ -292,6 +303,9 @@ class ToolControllerEditor(object):
tc.ToolNumber = self.controller.tcNumber.value()
self.horizFeed.updateProperty()
self.vertFeed.updateProperty()
+ self.leadInFeed.updateProperty()
+ self.leadOutFeed.updateProperty()
+ self.rampFeed.updateProperty()
self.horizRapid.updateProperty()
self.vertRapid.updateProperty()
tc.SpindleSpeed = self.controller.spindleSpeed.value()
@@ -323,6 +337,9 @@ class ToolControllerEditor(object):
self.controller.tcNumber.editingFinished.connect(self.changed)
self.vertFeed.widget.textChanged.connect(self.changed)
self.horizFeed.widget.textChanged.connect(self.changed)
+ self.leadInFeed.widget.textChanged.connect(self.changed)
+ self.leadOutFeed.widget.textChanged.connect(self.changed)
+ self.rampFeed.widget.textChanged.connect(self.changed)
self.vertRapid.widget.textChanged.connect(self.changed)
self.horizRapid.widget.textChanged.connect(self.changed)
self.controller.spindleSpeed.editingFinished.connect(self.changed)