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)