Merge pull request #23285 from davidgilkaufman/feed_rate_percentage

[CAM] Feed rate percentage for ramp and lead in/out moves
This commit is contained in:
sliptonic
2025-11-14 12:07:49 -06:00
committed by GitHub
8 changed files with 331 additions and 89 deletions

View File

@@ -117,14 +117,14 @@
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<widget class="QLabel" name="label_leadin_feed">
<property name="text">
<string>Horizontal rapid</string>
<string>Lead-in feed</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::QuantitySpinBox" name="horizRapid">
<widget class="Gui::QuantitySpinBox" name="leadInFeed">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -146,13 +146,100 @@
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_leadOutFeed">
<property name="text">
<string>Lead-out feed</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::QuantitySpinBox" name="leadOutFeed">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm/s</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_rampFeed">
<property name="text">
<string>Ramp feed</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="Gui::QuantitySpinBox" name="rampFeed">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm/s</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Horizontal rapid</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="Gui::QuantitySpinBox" name="horizRapid">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm/s</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Vertical rapid</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="6" column="1">
<widget class="Gui::QuantitySpinBox" name="vertRapid">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">

View File

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

View File

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

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

@@ -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"]:

View File

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

View File

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