[CAM] migrate ramp and lead in/out feed rates to the tool controller

This commit is contained in:
David Kaufman
2025-09-04 17:54:07 -04:00
parent f7dc85ef29
commit d1d6846af0
4 changed files with 114 additions and 84 deletions

View File

@@ -181,26 +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::PropertyInteger",
"FeedRatePercent",
"FeedRate",
QT_TRANSLATE_NOOP(
"App::Property", "Percentage modifier to apply to feed rate while ramping"
),
)
obj.addProperty(
"App::PropertySpeed",
"CustomFeedRate",
"FeedRate",
QT_TRANSLATE_NOOP("App::Property", "Custom feed rate"),
)
obj.addProperty(
"App::PropertyBool",
"UseStartDepth",
@@ -254,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":
@@ -292,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()
@@ -304,33 +269,29 @@ class ObjectDressup:
else:
obj.setEditorMode("DressupStartDepth", 2)
if obj.RampFeedRate == "Custom":
obj.setEditorMode("CustomFeedRate", 0)
if hasattr(obj, "FeedRatePercent"):
obj.setEditorMode("FeedRatePercent", 2)
else:
obj.setEditorMode("CustomFeedRate", 2)
if hasattr(obj, "FeedRatePercent"):
obj.setEditorMode("FeedRatePercent", 0)
def onDocumentRestored(self, obj):
if not hasattr(obj, "FeedRatePercent"):
obj.addProperty(
"App::PropertyInteger",
"FeedRatePercent",
"FeedRate",
QT_TRANSLATE_NOOP(
"App::Property", "Percentage modifier to apply to feed rate while ramping"
),
)
obj.FeedRatePercent = 100
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")
print("delete RampFeedRate", obj.Label)
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")
print("delete CustomFeedRate", obj.Label)
def setup(self, obj):
obj.Angle = 60
obj.Method = 2
obj.FeedRatePercent = 100
if PathDressup.baseOp(obj.Base).StartDepth is not None:
obj.DressupStartDepth = PathDressup.baseOp(obj.Base).StartDepth
@@ -707,15 +668,7 @@ class ObjectDressup:
vertFeed = tc.VertFeed.Value
horizRapid = tc.HorizRapid.Value
vertRapid = tc.VertRapid.Value
if obj.RampFeedRate == "Horizontal Feed Rate":
rampFeed = horizFeed * obj.FeedRatePercent / 100
elif obj.RampFeedRate == "Vertical Feed Rate":
rampFeed = vertFeed * obj.FeedRatePercent / 100
elif obj.RampFeedRate == "Ramp Feed Rate":
rampFeed = (math.sqrt(pow(vertFeed, 2) + pow(horizFeed, 2))) * obj.FeedRatePercent / 100
else:
rampFeed = obj.CustomFeedRate.Value
rampFeed = tc.RampFeed.Value
lastX = lastY = lastZ = 0
for cmd in commands:

View File

@@ -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,
),
)

View File

@@ -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):

View File

@@ -59,6 +59,80 @@ class ToolControllerTemplate:
VertRapid = "vrapid"
def _migrateRampDressups(tc):
# Enumerate ramp dressups using this TC and their feed rates
ramps = set()
job_ramp_feeds = []
print("search tc", tc.Name)
for job in tc.Document.Objects:
if hasattr(job, "Operations") and hasattr(job.Operations, "Group"):
print("job", job.Name)
for op in job.Operations.Group:
for ramp in [op] + op.OutListRecursive:
try:
if ramp not in ramps and (
hasattr(ramp, "RampFeedRate") or 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:
ramp.Proxy.CustomFeedRate
if op.Base.ToolController == tc:
ramps.add(ramp)
feed = "HorizFeed"
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))
print("add", ramp.Label)
except:
pass
# Ensure there is a TC for each required feed, starting with this one
print("job_ramp_feeds", job_ramp_feeds)
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 make an effort 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
opTc.recompute()
# Loop over ramps and assign each one the appropriate TC
for _, ramp, feed in job_ramp_feeds:
print("assign", ramp.Name, feed_to_tc[feed].Name)
ramp.Base.ToolController = feed_to_tc[feed]
class ToolController:
def __init__(self, obj, createTool=True):
Path.Log.track("tool: ")
@@ -199,7 +273,7 @@ class ToolController:
"Feed",
QT_TRANSLATE_NOOP("App::Property", "Feed rate for ramp moves"),
)
obj.setExpression("RampFeed", "HorizFeed")
_migrateRampDressups(obj)
needsRecompute = True
if not hasattr(obj, "LeadInFeed"):
@@ -386,6 +460,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"]:
print("set prop", prop, getattr(tc, prop))
setattr(newtc, prop, getattr(tc, prop))
except:
pass
for attr, expr in tc.ExpressionEngine:
newtc.setExpression(attr, expr)
return newtc
def FromTemplate(template, assignViewProvider=True):
Path.Log.track()