From aec49039ba4d7418b109708b88db6ed0b5065673 Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Fri, 29 Sep 2023 16:21:39 +0200 Subject: [PATCH 1/3] Path: rework LeadInOutDressup --- src/Mod/Path/Path/Base/Language.py | 6 + src/Mod/Path/Path/Dressup/Gui/LeadInOut.py | 554 +++++++-------------- 2 files changed, 175 insertions(+), 385 deletions(-) diff --git a/src/Mod/Path/Path/Base/Language.py b/src/Mod/Path/Path/Base/Language.py index 97832ac329..b157ebbc71 100644 --- a/src/Mod/Path/Path/Base/Language.py +++ b/src/Mod/Path/Path/Base/Language.py @@ -70,6 +70,9 @@ class Instruction(object): def isMove(self): return False + def isRapid(self): + return False + def isPlunge(self): """isPlunge() ... return true if this moves up or down""" return self.isMove() and not Path.Geom.isRoughly( @@ -131,6 +134,9 @@ class MoveStraight(Instruction): def isMove(self): return True + def isRapid(self): + return self.cmd in Path.Geom.CmdMoveRapid + def pathLength(self): return (self.positionEnd() - self.positionBegin()).Length diff --git a/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py b/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py index 4b9a2b65a1..6cc7eda235 100644 --- a/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py +++ b/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py @@ -25,9 +25,11 @@ import FreeCAD as App import FreeCADGui import Path +import Path.Base.Language as PathLanguage import Path.Dressup.Utils as PathDressup import PathScripts.PathUtils as PathUtils -from Path.Geom import CmdMoveRapid, CmdMoveStraight, CmdMoveArc, wireForPath +from Path.Geom import wireForPath +import math __doc__ = """LeadInOut Dressup USE ROLL-ON ROLL-OFF to profile""" @@ -44,10 +46,6 @@ else: Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule()) -movecommands = CmdMoveStraight + CmdMoveArc -currLocation = {} - - class ObjectDressup: def __init__(self, obj): lead_styles = [ @@ -163,6 +161,7 @@ class ObjectDressup: return if not obj.Base.Path: return + if obj.Length <= 0: Path.Log.error( translate("Path_DressupLeadInOut", "Length/Radius positive not Null") @@ -182,425 +181,210 @@ class ObjectDressup: def getDirectionOfPath(self, obj): op = PathDressup.baseOp(obj.Base) + side = op.Side if hasattr(op, "Side") else "Inside" + direction = op.Direction if hasattr(op, "Direction") else "CCW" - if hasattr(op, "Side") and op.Side == "Outside": - return ( - "left" if hasattr(op, "Direction") and op.Direction == "CW" else "right" - ) + if side == "Outside": + return "left" if direction == "CW" else "right" else: - return ( - "right" if hasattr(op, "Direction") and op.Direction == "CW" else "left" - ) + return "right" if direction == "CW" else "left" - def getSideOfPath(self, obj): + def getArcDirection(self, obj): + direction = self.getDirectionOfPath(obj) + return math.pi / 2 if direction == "left" else -math.pi / 2 + + def getTravelStart(self, obj, pos, first): op = PathDressup.baseOp(obj.Base) - return op.Side if hasattr(op, "Side") else "" + vertfeed = PathDressup.toolController(obj.Base).VertFeed.Value + travel = [] - def getLeadStart(self, obj, queue, action): - """returns Lead In G-code.""" - # Modified March 2022 by lcorley to support leadin extension - results = [] - op = PathDressup.baseOp(obj.Base) - horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value - vertFeed = PathDressup.toolController(obj.Base).VertFeed.Value + # begin positions for travel and plunge moves are not used anywhere, + # skipping them makes our life a lot easier - arcs_identical = False + # move to clearance height + if first: + travel.append(PathLanguage.MoveStraight( + None, "G0", {"Z": op.ClearanceHeight.Value})) - # Set the correct twist command - arcdir = "G3" if self.getDirectionOfPath(obj) == "left" else "G2" - - if queue[1].Name == "G1": # line - p0 = queue[0].Placement.Base - p1 = queue[1].Placement.Base - v = App.Vector(p1.sub(p0)).normalize() - Path.Log.debug(" CURRENT_IN Line : P0 Z:{} p1 Z:{}".format(p0.z, p1.z)) - else: - p0 = queue[0].Placement.Base - p1 = queue[1].Placement.Base - Path.Log.track() - v = App.Vector(p1.sub(p0)).normalize() - Path.Log.debug( - " CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} Z:{}".format( - p0.x, p0.y, p1.x, p1.y, p1.z - ) - ) - - # Calculate offset vector (will be overwritten for arcs) - if self.getDirectionOfPath(obj) == "right": - off_v = App.Vector(v.y * obj.Length.Value, -v.x * obj.Length.Value, 0.0) - else: - off_v = App.Vector(-v.y * obj.Length.Value, v.x * obj.Length.Value, 0.0) - - # Check if we enter at line or arc command - if queue[1].Name in movecommands and queue[1].Name not in CmdMoveArc: - # We have a line move - vec = p1.sub(p0) - vec_n = App.Vector(vec).normalize() - vec_inv = vec_n - vec_inv.multiply(-1) - vec_off = vec_inv - vec_off.multiply(obj.ExtendLeadIn) - Path.Log.debug( - "LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format( - queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y - ) - ) - else: - # We have an arc move - # Calculate coordinates for middle of circle - pij = App.Vector(p0) - pij.x += queue[1].Parameters["I"] - pij.y += queue[1].Parameters["J"] - - # Check if lead in and operation go in same direction (usually for inner circles) - if arcdir == queue[1].Name: - arcs_identical = True - - # Calculate vector circle start -> circle middle - vec_circ = pij.sub(p0) - - angle = 90 if arcdir == "G2" else -90 - vec_rot = App.Rotation(App.Vector(0, 0, 1), angle).multVec(vec_circ) - - # Normalize and invert vector - vec_n = App.Vector(vec_rot).normalize() - v = App.Vector(vec_n).multiply(-1) - - # Calculate offset of lead in - if arcdir == "G3": - off_v = App.Vector(-v.y * obj.Length.Value, v.x * obj.Length.Value, 0.0) - else: - off_v = App.Vector(v.y * obj.Length.Value, -v.x * obj.Length.Value, 0.0) - - offsetvector = App.Vector( - v.x * obj.Length.Value, v.y * obj.Length.Value, 0 - ) - - if obj.StyleOn == "Arc": - leadstart = (p0.add(off_v)).sub(offsetvector) - if arcs_identical: - t = p0.sub(leadstart) - t = p0.add(t) - leadstart = t - offsetvector = offsetvector.multiply(-1) - elif obj.StyleOn == "Tangent": - # This is wrong. please fix - leadstart = (p0.add(off_v)).sub(offsetvector) - if arcs_identical: - t = p0.sub(leadstart) - t = p0.add(t) - leadstart = t - offsetvector = offsetvector.multiply(-1) - else: # perpendicular - leadstart = p0.add(off_v) - - # At this point leadstart is the beginning of the leadin arc - # and offsetvector points from leadstart to the center of the leadin arc - # so the offsetvector is a radius of the leadin arc at its start - # The extend line should be tangent to the leadin arc at this point, or perpendicular to the radius - - angle = -90 if arcdir == "G2" else 90 - tangentvec = App.Rotation(App.Vector(0, 0, 1), angle).multVec(offsetvector) - - # Normalize the tangent vector - tangentvecNorm = App.Vector(tangentvec).normalize() - leadlinevec = App.Vector(tangentvecNorm).multiply(obj.ExtendLeadIn) - - # leadlinevec provides the offset from the beginning of the lead arc to the beginning of the extend line - extendstart = leadstart.add(leadlinevec) - - if action == "start": - if obj.ExtendLeadIn != 0: - # Rapid move to beginning of extend line - extendcommand = Path.Command( - "G0", - { - "X": extendstart.x, - "Y": extendstart.y, - "Z": op.ClearanceHeight.Value, - }, - ) - else: - # Rapid move to beginning of leadin arc - extendcommand = Path.Command( - "G0", - { - "X": extendstart.x, - "Y": extendstart.y, - "Z": op.ClearanceHeight.Value, - }, - ) - results.append(extendcommand) - extendcommand = Path.Command("G0", {"Z": op.SafeHeight.Value}) - results.append(extendcommand) - - if action == "layer": - if not obj.KeepToolDown: - extendcommand = Path.Command("G0", {"Z": op.SafeHeight.Value}) - results.append(extendcommand) - - extendcommand = Path.Command("G0", {"X": extendstart.x, "Y": extendstart.y}) - results.append(extendcommand) + # move to correct xy-position + travel.append(PathLanguage.MoveStraight( + None, "G0", {"X": pos.x, "Y": pos.y})) + # move to correct z-position (either rapidly or in two steps) if obj.RapidPlunge: - extendcommand = Path.Command("G0", {"Z": p1.z}) + travel.append(PathLanguage.MoveStraight(None, "G0", {"Z": pos.z})) else: - extendcommand = Path.Command("G1", {"Z": p1.z, "F": vertFeed}) + if first or not obj.KeepToolDown: + travel.append(PathLanguage.MoveStraight( + None, "G0", {"Z": op.SafeHeight.Value})) + travel.append(PathLanguage.MoveStraight( + None, "G1", {"Z": pos.z, "F": vertfeed})) - results.append(extendcommand) + return travel - if obj.StyleOn == "Arc": - if obj.ExtendLeadIn != 0: - # Insert move to beginning of leadin arc - extendcommand = Path.Command( - "G1", {"X": leadstart.x, "Y": leadstart.y, "F": horizFeed} - ) - results.append(extendcommand) - arcmove = Path.Command( - arcdir, - { - "X": p0.x, - "Y": p0.y, - "Z": p0.z, - "I": offsetvector.x, - "J": offsetvector.y, - "K": offsetvector.z, - "F": horizFeed, - }, - ) # add G2/G3 move - results.append(arcmove) - # elif obj.StyleOn in ["Tangent", "Perpendicular"]: + def getTravelEnd(self, obj, pos, last): + op = PathDressup.baseOp(obj.Base) + travel = [] + + # move to clearance height + if last or not obj.KeepToolDown: + travel.append(PathLanguage.MoveStraight( + None, "G0", {"Z": op.ClearanceHeight.Value})) + + return travel + + def angleToVector(self, angle): + return App.Vector(math.cos(angle), math.sin(angle), 0) + + def createArcMove(self, obj, begin, end, c): + horizfeed = PathDressup.toolController(obj.Base).HorizFeed.Value + + param = {"X": end.x, "Y": end.y, "I": c.x, "J": c.y, "F": horizfeed} + if self.getArcDirection(obj) > 0: + return PathLanguage.MoveArcCCW(begin, "G3", param) else: - extendcommand = Path.Command("G1", {"X": p0.x, "Y": p0.y, "F": horizFeed}) - results.append(extendcommand) + return PathLanguage.MoveArcCW(begin, "G2", param) - currLocation.update(results[-1].Parameters) - currLocation["Z"] = p1.z + def createStraightMove(self, obj, begin, end): + horizfeed = PathDressup.toolController(obj.Base).HorizFeed.Value - return results + param = {"X": end.x, "Y": end.y, "F": horizfeed} + return PathLanguage.MoveStraight(begin, "G1", param) - def getLeadEnd(self, obj, queue, action): - """returns the Gcode of LeadOut.""" - results = [] - horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value - arcs_identical = False + def getLeadStart(self, obj, move, first): + lead = [] + begin = move.positionBegin() - # Set the correct twist command - if self.getDirectionOfPath(obj) == "right": - arcdir = "G2" - else: - arcdir = "G3" + def prepend(instr): + nonlocal lead + nonlocal begin + lead.insert(0, instr) + begin = lead[0].positionBegin() - if queue[1].Name == "G1": # line - p0 = queue[0].Placement.Base - p1 = queue[1].Placement.Base - v = App.Vector(p1.sub(p0)).normalize() - else: # dealing with a circle - p0 = queue[0].Placement.Base - p1 = queue[1].Placement.Base - v = App.Vector(p1.sub(p0)).normalize() + # tangent begin move + # <----_-----x-------------------x + # / | + # / | normal + # | | + # x v - if self.getDirectionOfPath(obj) == "right": - off_v = App.Vector( - v.y * obj.LengthOut.Value, -v.x * obj.LengthOut.Value, 0.0 - ) - else: - off_v = App.Vector( - -v.y * obj.LengthOut.Value, v.x * obj.LengthOut.Value, 0.0 - ) + if obj.LeadIn: + length = obj.Length.Value + angle = move.anglesOfTangents()[0] + tangent = -self.angleToVector(angle) * length + normal = self.angleToVector( + angle + self.getArcDirection(obj)) * length - # Check if we leave at line or arc command - if queue[1].Name in movecommands and queue[1].Name not in CmdMoveArc: - # We have a line move - vec_n = App.Vector(p1.sub(p0)).normalize() - vec_inv = vec_n - vec_inv.multiply(-1) - vec_off = App.Vector(vec_inv).multiply(obj.ExtendLeadOut) - Path.Log.debug( - "LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format( - queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y - ) - ) - else: - # We have an arc move - pij = App.Vector(p0) - pij.x += queue[1].Parameters["I"] - pij.y += queue[1].Parameters["J"] - ve = pij.sub(p1) + # prepend the selected lead-in + if obj.StyleOn == "Arc": + arcbegin = begin + tangent + normal + prepend(self.createArcMove(obj, arcbegin, begin, -tangent)) + elif obj.StyleOn == "Tangent": + prepend(self.createStraightMove(obj, begin + tangent, begin)) + else: # obj.StyleOn == "Perpendicular" + prepend(self.createStraightMove(obj, begin + normal, begin)) - if arcdir == queue[1].Name: - arcs_identical = True + extend = obj.ExtendLeadIn.Value + if extend != 0: + # prepend extension + extendbegin = begin + normal / length * extend + prepend(self.createStraightMove(obj, extendbegin, begin)) - angle = -90 if arcdir == "G2" else 90 - vec_rot = App.Rotation(App.Vector(0, 0, 1), angle).multVec(ve) + # prepend travel moves + lead = self.getTravelStart(obj, begin, first) + lead - vec_n = App.Vector(vec_rot).normalize() - v = vec_n + return lead - if arcdir == "G3": - off_v = App.Vector( - -v.y * obj.LengthOut.Value, v.x * obj.LengthOut.Value, 0.0 - ) - else: - off_v = App.Vector( - v.y * obj.LengthOut.Value, -v.x * obj.LengthOut.Value, 0.0 - ) + def getLeadEnd(self, obj, move, last): + lead = [] + end = move.positionEnd() - vec_inv = vec_rot - vec_inv.multiply(-1) + def append(instr): + nonlocal lead + nonlocal end + lead.append(instr) + end = lead[-1].positionEnd() - offsetvector = App.Vector( - v.x * obj.LengthOut.Value, v.y * obj.LengthOut.Value, 0.0 - ) - # if obj.RadiusCenter == "Radius": - if obj.StyleOff == "Arc": - leadend = (p1.add(off_v)).add(offsetvector) - if arcs_identical: - t = p1.sub(leadend) - t = p1.add(t) - leadend = t - off_v.multiply(-1) + # move end tangent + # x-------------------x-----_----> + # | \ + # normal | \ + # | | + # v x - elif obj.StyleOff == "Tangent": - # This is WRONG. Please fix - leadend = (p1.add(off_v)).add(offsetvector) - if arcs_identical: - t = p1.sub(leadend) - t = p1.add(t) - leadend = t - off_v.multiply(-1) - else: - leadend = p1.add(off_v) + if obj.LeadOut: + length = obj.LengthOut.Value + angle = move.anglesOfTangents()[1] + tangent = self.angleToVector(angle) * length + normal = self.angleToVector( + angle + self.getArcDirection(obj)) * length - IJ = off_v - # At this point leadend is the location of the end of the leadout arc - # IJ is an offset from the beginning of the leadout arc to its center. - # It is parallel to a tangent line at the end of the leadout arc - # Create the normalized tangent vector - tangentvecNorm = App.Vector(IJ).normalize() - leadlinevec = App.Vector(tangentvecNorm).multiply(obj.ExtendLeadOut) + # append the selected lead-out + if obj.StyleOff == "Arc": + arcend = end + tangent + normal + append(self.createArcMove(obj, end, arcend, normal)) + elif obj.StyleOff == "Tangent": + append(self.createStraightMove(obj, end, end + tangent)) + else: # obj.StyleOff == "Perpendicular" + append(self.createStraightMove(obj, end, end + normal)) - extendleadoutend = leadend.add(leadlinevec) + extend = obj.ExtendLeadOut.Value + if extend != 0: + # append extension + extendend = end + normal / length * extend + append(self.createStraightMove(obj, end, extendend)) - if obj.StyleOff == "Arc": - arcmove = Path.Command( - arcdir, - { - "X": leadend.x, - "Y": leadend.y, - "Z": leadend.z, - "I": IJ.x, - "J": IJ.y, - "K": IJ.z, - "F": horizFeed, - }, - ) # add G2/G3 move - results.append(arcmove) - if obj.ExtendLeadOut != 0: - extendcommand = Path.Command( - "G1", - {"X": extendleadoutend.x, "Y": extendleadoutend.y, "F": horizFeed}, - ) - results.append(extendcommand) - else: - extendcommand = Path.Command( - "G1", {"X": leadend.x, "Y": leadend.y, "F": horizFeed} - ) - results.append(extendcommand) + # append travel moves + lead += self.getTravelEnd(obj, end, last) - return results + return lead + + def isCuttingMove(self, obj, instr): + return (instr.isMove() + and not instr.isRapid() + and (not obj.IncludeLayers or not instr.isPlunge())) + + def findLastCuttingMoveIndex(self, obj, source): + for i in range(len(source) - 1, -1, -1): + if self.isCuttingMove(obj, source[i]): + return i + return None def generateLeadInOutCurve(self, obj): - global currLocation - firstmove = Path.Command("G0", {"X": 0, "Y": 0, "Z": 0}) - op = PathDressup.baseOp(obj.Base) - currLocation.update(firstmove.Parameters) - newpath = [] - queue = [] - action = "start" - prevCmd = "" - layers = [] + source = PathLanguage.Maneuver.FromPath( + PathUtils.getPathWithPlacement(obj.Base)).instr + maneuver = PathLanguage.Maneuver() - # Read in all commands - for curCommand in PathUtils.getPathWithPlacement(obj.Base).Commands: - Path.Log.debug("CurCMD: {}".format(curCommand)) - if curCommand.Name not in movecommands + CmdMoveRapid: - # Don't worry about non-move commands, just add to output - newpath.append(curCommand) + # Knowing weather a given instruction is the first cutting move is easy, + # we just use a flag and set it to false afterwards. To find the last + # cutting move we need to search the list in reverse order. + first = True + lastCuttingMoveIndex = self.findLastCuttingMoveIndex(obj, source) + + for i, instr in enumerate(source): + if not self.isCuttingMove(obj, instr): + # non-move instructions get added verbatim + if not instr.isMove(): + maneuver.addInstruction(instr) + + # skip travel and plunge moves, travel moves will be added in + # getLeadStart and getLeadEnd continue - if curCommand.Name in CmdMoveRapid: - # We don't care about rapid moves - prevCmd = curCommand - currLocation.update(curCommand.Parameters) - continue + if first or not self.isCuttingMove(obj, source[i - 1]): + # add lead start and travel moves + maneuver.addInstructions(self.getLeadStart(obj, instr, first)) + first = False - if curCommand.Name in movecommands: - if ( - prevCmd.Name in CmdMoveRapid - and curCommand.Name in movecommands - and len(queue) > 0 - ): - # Layer changed: Save current layer cmds and prepare next layer - layers.append(queue) - queue = [] - if ( - obj.IncludeLayers - and curCommand.z < currLocation["Z"] and not Path.Geom.isRoughly(curCommand.z, currLocation["Z"]) - and prevCmd.Name in movecommands - ): - # Layer change within move cmds - Path.Log.debug( - "Layer change in move: {}->{}".format( - currLocation["Z"], curCommand.z - ) - ) - layers.append(queue) - queue = [] + # add current move + maneuver.addInstruction(instr) - # Save all move commands - # getLeadStart and getLeadEnd incorrectly treat missing axis words as being 0. - currXYZ = { k: currLocation[k] for k in "XYZ" if k in currLocation } - tmp = Path.Command(curCommand.Name, currXYZ | curCommand.Parameters) - queue.append(tmp) + last = i == lastCuttingMoveIndex + if last or not self.isCuttingMove(obj, source[i + 1]): + # add lead end and travel moves + maneuver.addInstructions(self.getLeadEnd(obj, instr, last)) - currLocation.update(curCommand.Parameters) - prevCmd = curCommand - - # Add last layer - if len(queue) > 0: - layers.append(queue) - - # Go through each layer and add leadIn/Out - idx = 0 - for layer in layers: - Path.Log.debug("Layer {}".format(idx)) - - if obj.LeadIn: - temp = self.getLeadStart(obj, layer, action) - newpath.extend(temp) - - for cmd in layer: - Path.Log.debug("CurLoc: {}, NewCmd: {}!!".format(currLocation, cmd)) - newpath.append(cmd) - - if obj.LeadOut: - tmp = [] - tmp.append(layer[-2]) - tmp.append(layer[-1]) - temp = self.getLeadEnd(obj, tmp, action) - newpath.extend(temp) - - if not obj.KeepToolDown or idx == len(layers) - 1: - extendcommand = Path.Command("G0", {"Z": op.ClearanceHeight.Value}) - newpath.append(extendcommand) - else: - action = "layer" - - idx += 1 - - commands = newpath - return Path.Path(commands) + return maneuver.toPath() class TaskDressupLeadInOut(SimpleEditPanel): From 43ebc1e6a31ad64754e68b26f7ea9e15b4e7051c Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Fri, 6 Oct 2023 04:16:19 +0200 Subject: [PATCH 2/3] Path: use helper functions from Utils.py instead of directly accessing obj.Base in dressups --- src/Mod/Path/Path/Dressup/DogboneII.py | 5 ++--- src/Mod/Path/Path/Dressup/Gui/LeadInOut.py | 4 ++-- src/Mod/Path/Path/Dressup/Gui/RampEntry.py | 6 +++--- src/Mod/Path/Path/Dressup/Tags.py | 9 +++------ src/Mod/Path/PathTests/TestPathDressupDogboneII.py | 6 ++++-- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Mod/Path/Path/Dressup/DogboneII.py b/src/Mod/Path/Path/Dressup/DogboneII.py index fd6568f930..df6f4957eb 100644 --- a/src/Mod/Path/Path/Dressup/DogboneII.py +++ b/src/Mod/Path/Path/Dressup/DogboneII.py @@ -25,6 +25,7 @@ import FreeCAD import Path import Path.Base.Generator.dogboneII as dogboneII import Path.Base.Language as PathLanguage +import Path.Dressup.Utils as PathDressup import PathScripts.PathUtils as PathUtils import math @@ -271,9 +272,7 @@ class Proxy(object): return None def toolRadius(self, obj): - if not hasattr(obj.Base, "ToolController"): - return self.toolRadius(obj.Base) - return obj.Base.ToolController.Tool.Diameter.Value / 2 + return PathDressup.toolController(obj.Base).Tool.Diameter.Value / 2 def createBone(self, obj, move0, move1): kink = dogboneII.Kink(move0, move1) diff --git a/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py b/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py index 6cc7eda235..dbd2ac8620 100644 --- a/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py +++ b/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py @@ -142,8 +142,8 @@ class ObjectDressup: return None def setup(self, obj): - obj.Length = obj.Base.ToolController.Tool.Diameter * 0.75 - obj.LengthOut = obj.Base.ToolController.Tool.Diameter * 0.75 + obj.Length = PathDressup.toolController(obj.Base).Tool.Diameter * 0.75 + obj.LengthOut = PathDressup.toolController(obj.Base).Tool.Diameter * 0.75 obj.LeadIn = True obj.LeadOut = True obj.KeepToolDown = False diff --git a/src/Mod/Path/Path/Dressup/Gui/RampEntry.py b/src/Mod/Path/Path/Dressup/Gui/RampEntry.py index 79b98c6363..ec79e763ce 100644 --- a/src/Mod/Path/Path/Dressup/Gui/RampEntry.py +++ b/src/Mod/Path/Path/Dressup/Gui/RampEntry.py @@ -192,8 +192,8 @@ class ObjectDressup: def setup(self, obj): obj.Angle = 60 obj.Method = 2 - if PathDressup.baseOp(obj).StartDepth is not None: - obj.DressupStartDepth = PathDressup.baseOp(obj).StartDepth + if PathDressup.baseOp(obj.Base).StartDepth is not None: + obj.DressupStartDepth = PathDressup.baseOp(obj.Base).StartDepth def execute(self, obj): if not obj.Base: @@ -203,7 +203,7 @@ class ObjectDressup: if not obj.Base.Path: return - if hasattr(obj.Base, 'Active') and not obj.Base.Active: + if not PathDressup.baseOp(obj.Base).Active: path = Path.Path("(inactive operation)") obj.Path = path return diff --git a/src/Mod/Path/Path/Dressup/Tags.py b/src/Mod/Path/Path/Dressup/Tags.py index 15e492fb2a..0bcb01639f 100644 --- a/src/Mod/Path/Path/Dressup/Tags.py +++ b/src/Mod/Path/Path/Dressup/Tags.py @@ -868,12 +868,9 @@ class PathData: return (currentLength, lastTagLength) def defaultTagHeight(self): - if ( - hasattr(self.obj, "Base") - and hasattr(self.obj.Base, "StartDepth") - and hasattr(self.obj.Base, "FinalDepth") - ): - pathHeight = (self.obj.Base.StartDepth - self.obj.Base.FinalDepth).Value + op = PathDressup.baseOp(self.obj.Base) + if hasattr(op, "StartDepth") and hasattr(op, "FinalDepth"): + pathHeight = (op.StartDepth - op.FinalDepth).Value else: pathHeight = self.maxZ - self.minZ height = HoldingTagPreferences.defaultHeight(pathHeight / 2) diff --git a/src/Mod/Path/PathTests/TestPathDressupDogboneII.py b/src/Mod/Path/PathTests/TestPathDressupDogboneII.py index 63b725cc7b..28a2478786 100644 --- a/src/Mod/Path/PathTests/TestPathDressupDogboneII.py +++ b/src/Mod/Path/PathTests/TestPathDressupDogboneII.py @@ -47,6 +47,8 @@ class MockTC(object): class MockOp(object): def __init__(self, path, dia=2): + self.Name = "OP" + self.Label = "OP" self.Path = Path.Path(path) self.ToolController = MockTC(dia) @@ -85,7 +87,7 @@ class MockFeaturePython(object): def CreateDressup(path): op = MockOp(path) - obj = MockFeaturePython("DogboneII") + obj = MockFeaturePython("DressupDogbone") db = Path.Dressup.DogboneII.Proxy(obj, op) obj.Proxy = db return obj @@ -626,7 +628,7 @@ class TestDressupDogboneII(PathTestUtils.PathTestBase): obj = self.test90() - obj2 = MockFeaturePython("DogboneII_") + obj2 = MockFeaturePython("DressupDogbone001") db2 = Path.Dressup.DogboneII.Proxy(obj2, obj) obj2.Proxy = db2 obj2.Incision = Path.Dressup.DogboneII.Incision.Fixed From ba94502a0cbbb33e21f8ae826c1af0aeb4ec05c8 Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Fri, 6 Oct 2023 05:53:19 +0200 Subject: [PATCH 3/3] Path: fix LeadInOutDressup task panel showing wrong values on certain locales --- src/Mod/Path/PathPythonGui/simple_edit_panel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Path/PathPythonGui/simple_edit_panel.py b/src/Mod/Path/PathPythonGui/simple_edit_panel.py index 0de9345bf3..b9a726851f 100644 --- a/src/Mod/Path/PathPythonGui/simple_edit_panel.py +++ b/src/Mod/Path/PathPythonGui/simple_edit_panel.py @@ -77,7 +77,7 @@ class SimpleEditPanel: elif prop_type in PROP_TYPE_NUMERIC and widget_type == "QDoubleSpinBox": self._fc[prop_name] = widget.value, widget.setValue elif prop_type in PROP_TYPE_QTYES and widget_type == "QLineEdit": - self._fc[prop_name] = widget.text, lambda v: widget.setText(str(v)) + self._fc[prop_name] = widget.text, lambda v: widget.setText(v.UserString) else: raise ValueError( f"Unsupported connection between '{prop_type}' property and '{widget_type}' widget"