From 093152b1dcf7d0de1c2c51f33db597405d31e05b Mon Sep 17 00:00:00 2001 From: David Kaufman Date: Fri, 22 Aug 2025 14:25:56 -0400 Subject: [PATCH] [CAM] separate controls for feed rate percent entrance vs exit --- .../Resources/panels/DressUpLeadInOutEdit.ui | 37 ++++++- src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py | 100 ++++++++++++------ 2 files changed, 101 insertions(+), 36 deletions(-) diff --git a/src/Mod/CAM/Gui/Resources/panels/DressUpLeadInOutEdit.ui b/src/Mod/CAM/Gui/Resources/panels/DressUpLeadInOutEdit.ui index f6e956cfd3..39211d2045 100644 --- a/src/Mod/CAM/Gui/Resources/panels/DressUpLeadInOutEdit.ui +++ b/src/Mod/CAM/Gui/Resources/panels/DressUpLeadInOutEdit.ui @@ -177,14 +177,14 @@ - Feed Rate Percent + Entrance Feed Rate Percent - + - Horizontal feed rate during entrances and exits, as a percentage of the normal feed rate. + Feed rate to use when entering a cut, as a percentage of the normal feed rate. 0 @@ -196,7 +196,7 @@ 999999.000000000000000 - 10.000000000000000 + 5.000000000000000 @@ -204,6 +204,35 @@ + + + Exit Feed Rate Percent + + + + + + + Feed rate to use when exiting a cut, as a percentage of the normal feed rate. + + + 0 + + + 1.000000000000000 + + + 999999.000000000000000 + + + 5.000000000000000 + + + + + + + diff --git a/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py b/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py index 3cee50e06f..0f8df380e3 100644 --- a/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py +++ b/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py @@ -164,11 +164,20 @@ class ObjectDressup: ) obj.addProperty( "App::PropertyInteger", - "FeedRatePercent", + "FeedRatePercentIn", "Path", QT_TRANSLATE_NOOP( "App::Property", - "Percentage modifier to apply to feed rate while entering and exiting", + "Percentage modifier to apply to feed rate while entering the cut", + ), + ) + obj.addProperty( + "App::PropertyInteger", + "FeedRatePercentOut", + "Path", + QT_TRANSLATE_NOOP( + "App::Property", + "Percentage modifier to apply to feed rate while exiting the cut", ), ) obj.Proxy = self @@ -188,7 +197,8 @@ class ObjectDressup: obj.LeadOut = True obj.AngleIn = 90 obj.AngleOut = 90 - obj.FeedRatePercent = 100 + obj.FeedRatePercentIn = 100 + obj.FeedRatePercentOut = 100 obj.InvertIn = False obj.InvertOut = False obj.RapidPlunge = False @@ -261,8 +271,10 @@ class ObjectDressup: ) return - self.horizFeed = self.toolController.HorizFeed.Value * obj.FeedRatePercent / 100 + self.horizFeed = self.toolController.HorizFeed.Value self.vertFeed = self.toolController.VertFeed.Value + self.entranceFeed = self.horizFeed * obj.FeedRatePercentIn / 100 + self.exitFeed = self.horizFeed * obj.FeedRatePercentOut / 100 obj.Path = self.generateLeadInOutCurve(obj) @@ -429,17 +441,28 @@ class ObjectDressup: obj.setEditorMode(k + "In", 2 if obj.StyleIn in v else 0) obj.setEditorMode(k + "Out", 2 if obj.StyleOut in v else 0) - if not hasattr(obj, "FeedRatePercent"): + if not hasattr(obj, "FeedRatePercentIn"): obj.addProperty( "App::PropertyInteger", - "FeedRatePercent", + "FeedRatePercentIn", "Path", QT_TRANSLATE_NOOP( "App::Property", - "Percentage modifier to apply to feed rate while entering and exiting", + "Percentage modifier to apply to feed rate while entering the cut", ), ) - obj.FeedRatePercent = 100 + obj.FeedRatePercentIn = 100 + if not hasattr(obj, "FeedRatePercentOut"): + obj.addProperty( + "App::PropertyInteger", + "FeedRatePercentOut", + "Path", + QT_TRANSLATE_NOOP( + "App::Property", + "Percentage modifier to apply to feed rate while exiting the cut", + ), + ) + obj.FeedRatePercentOut = 100 # Get direction for lead-in/lead-out in XY plane def getLeadDir(self, obj, invert=False): @@ -521,14 +544,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) @@ -538,8 +561,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: @@ -548,8 +571,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 @@ -571,7 +594,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) @@ -590,7 +613,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 @@ -598,7 +621,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) @@ -618,7 +641,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 @@ -676,7 +699,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 @@ -690,7 +717,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 apply only on straight Path segment @@ -705,7 +732,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 apply only on straight Path segment @@ -724,7 +751,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 by first lead-in command begin = lead[0].positionBegin() @@ -764,7 +793,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 @@ -812,7 +841,11 @@ 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 @@ -826,7 +859,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 @@ -841,7 +874,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 @@ -860,7 +893,9 @@ 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 @@ -1018,7 +1053,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(): @@ -1033,7 +1068,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 @@ -1047,7 +1082,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 @@ -1064,7 +1099,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 @@ -1210,7 +1245,8 @@ class TaskDressupLeadInOut(SimpleEditPanel): def setupSpinBoxes(self): self.connectWidget("InvertIn", self.form.chkInvertDirectionIn) self.connectWidget("InvertOut", self.form.chkInvertDirectionOut) - self.connectWidget("FeedRatePercent", self.form.dspFeedRatePercent) + self.connectWidget("FeedRatePercentIn", self.form.dspFeedRatePercentIn) + self.connectWidget("FeedRatePercentOut", self.form.dspFeedRatePercentOut) self.connectWidget("PercentageRadiusIn", self.form.dspPercentageRadiusIn) self.connectWidget("PercentageRadiusOut", self.form.dspPercentageRadiusOut) self.connectWidget("StyleIn", self.form.cboStyleIn)