From 03cb6c965d8b21532b60481c82021a5b3550f027 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 24 Jan 2022 14:16:14 -0600 Subject: [PATCH 1/6] Black - Job Holding tag black Feature extension black Dressup boundary and dogbone black --- .../Path/PathScripts/PathDressupDogbone.py | 486 ++++++++++---- .../PathScripts/PathDressupHoldingTags.py | 609 +++++++++++++----- .../PathScripts/PathDressupPathBoundary.py | 147 +++-- .../PathScripts/PathDressupPathBoundaryGui.py | 90 ++- src/Mod/Path/PathScripts/PathDressupTag.py | 127 +++- src/Mod/Path/PathScripts/PathDressupTagGui.py | 125 ++-- .../PathScripts/PathDressupTagPreferences.py | 71 +- .../Path/PathScripts/PathFeatureExtensions.py | 187 ++++-- .../PathScripts/PathFeatureExtensionsGui.py | 179 +++-- src/Mod/Path/PathScripts/PathJobCmd.py | 73 ++- src/Mod/Path/PathScripts/PathJobDlg.py | 107 ++- 11 files changed, 1593 insertions(+), 608 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDressupDogbone.py b/src/Mod/Path/PathScripts/PathDressupDogbone.py index c91ef30078..1802c1a384 100644 --- a/src/Mod/Path/PathScripts/PathDressupDogbone.py +++ b/src/Mod/Path/PathScripts/PathDressupDogbone.py @@ -34,23 +34,25 @@ from PySide import QtCore # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader -DraftGeomUtils = LazyLoader('DraftGeomUtils', globals(), 'DraftGeomUtils') -Part = LazyLoader('Part', globals(), 'Part') + +DraftGeomUtils = LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils") +Part = LazyLoader("Part", globals(), "Part") LOG_MODULE = PathLog.thisModule() PathLog.setLevel(PathLog.Level.NOTICE, LOG_MODULE) -#PathLog.trackModule(LOG_MODULE) +# PathLog.trackModule(LOG_MODULE) # Qt translation handling def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) -movecommands = ['G0', 'G00', 'G1', 'G01', 'G2', 'G02', 'G3', 'G03'] -movestraight = ['G1', 'G01'] -movecw = ['G2', 'G02'] -moveccw = ['G3', 'G03'] + +movecommands = ["G0", "G00", "G1", "G01", "G2", "G02", "G3", "G03"] +movestraight = ["G1", "G01"] +movecw = ["G2", "G02"] +moveccw = ["G3", "G03"] movearc = movecw + moveccw @@ -59,7 +61,9 @@ def debugMarker(vector, label, color=None, radius=0.5): obj = FreeCAD.ActiveDocument.addObject("Part::Sphere", label) obj.Label = label obj.Radius = radius - obj.Placement = FreeCAD.Placement(vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0)) + obj.Placement = FreeCAD.Placement( + vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) + ) if color: obj.ViewObject.ShapeColor = color @@ -70,7 +74,9 @@ def debugCircle(vector, r, label, color=None): obj.Label = label obj.Radius = r obj.Height = 1 - obj.Placement = FreeCAD.Placement(vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0)) + obj.Placement = FreeCAD.Placement( + vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) + ) obj.ViewObject.Transparency = 90 if color: obj.ViewObject.ShapeColor = color @@ -79,9 +85,9 @@ def debugCircle(vector, r, label, color=None): def addAngle(a1, a2): a = a1 + a2 while a <= -math.pi: - a += 2*math.pi + a += 2 * math.pi while a > math.pi: - a -= 2*math.pi + a -= 2 * math.pi return a @@ -102,7 +108,7 @@ def getAngle(v): return a -def pointFromCommand(cmd, pt, X='X', Y='Y', Z='Z'): +def pointFromCommand(cmd, pt, X="X", Y="Y", Z="Z"): x = cmd.Parameters.get(X, pt.x) y = cmd.Parameters.get(Y, pt.y) z = cmd.Parameters.get(Z, pt.z) @@ -118,14 +124,16 @@ def edgesForCommands(cmds, startPt): if cmd.Name in movestraight: edges.append(Part.Edge(Part.LineSegment(lastPt, pt))) elif cmd.Name in movearc: - center = lastPt + pointFromCommand(cmd, FreeCAD.Vector(0, 0, 0), 'I', 'J', 'K') + center = lastPt + pointFromCommand( + cmd, FreeCAD.Vector(0, 0, 0), "I", "J", "K" + ) A = lastPt - center B = pt - center d = -B.x * A.y + B.y * A.x if d == 0: # we're dealing with half a circle here - angle = getAngle(A) + math.pi/2 + angle = getAngle(A) + math.pi / 2 if cmd.Name in movecw: angle -= math.pi else: @@ -143,19 +151,19 @@ def edgesForCommands(cmds, startPt): class Style(object): # pylint: disable=no-init - Dogbone = 'Dogbone' - Tbone_H = 'T-bone horizontal' - Tbone_V = 'T-bone vertical' - Tbone_L = 'T-bone long edge' - Tbone_S = 'T-bone short edge' + Dogbone = "Dogbone" + Tbone_H = "T-bone horizontal" + Tbone_V = "T-bone vertical" + Tbone_L = "T-bone long edge" + Tbone_S = "T-bone short edge" All = [Dogbone, Tbone_H, Tbone_V, Tbone_L, Tbone_S] class Side(object): # pylint: disable=no-init - Left = 'Left' - Right = 'Right' + Left = "Left" + Right = "Right" All = [Left, Right] @classmethod @@ -170,9 +178,9 @@ class Side(object): class Incision(object): # pylint: disable=no-init - Fixed = 'fixed' - Adaptive = 'adaptive' - Custom = 'custom' + Fixed = "fixed" + Adaptive = "adaptive" + Custom = "custom" All = [Adaptive, Fixed, Custom] @@ -194,8 +202,7 @@ class Smooth(object): # be constant in all calculated results. # Instances of Chord are generally considered immutable and all movement member # functions return new instances. -class Chord (object): - +class Chord(object): def __init__(self, start=None, end=None): if not start: start = FreeCAD.Vector() @@ -205,15 +212,22 @@ class Chord (object): self.End = end def __str__(self): - return "Chord([%g, %g, %g] -> [%g, %g, %g])" % (self.Start.x, self.Start.y, self.Start.z, self.End.x, self.End.y, self.End.z) + return "Chord([%g, %g, %g] -> [%g, %g, %g])" % ( + self.Start.x, + self.Start.y, + self.Start.z, + self.End.x, + self.End.y, + self.End.z, + ) def moveTo(self, newEnd): return Chord(self.End, newEnd) def moveToParameters(self, params): - x = params.get('X', self.End.x) - y = params.get('Y', self.End.y) - z = params.get('Z', self.End.z) + x = params.get("X", self.End.x) + y = params.get("Y", self.End.y) + z = params.get("Z", self.End.z) return self.moveTo(FreeCAD.Vector(x, y, z)) def moveBy(self, x, y, z): @@ -244,14 +258,14 @@ class Chord (object): # if the 2 vectors are identical, they head in the same direction PathLog.debug(" {}.getDirectionOfVector({})".format(A, B)) if PathGeom.pointsCoincide(A, B): - return 'Straight' - d = -A.x*B.y + A.y*B.x + return "Straight" + d = -A.x * B.y + A.y * B.x if d < 0: return Side.Left if d > 0: return Side.Right # at this point the only direction left is backwards - return 'Back' + return "Back" def getDirectionOf(self, chordOrVector): if type(chordOrVector) is Chord: @@ -278,7 +292,7 @@ class Chord (object): def commandParams(self, f): params = {"X": self.End.x, "Y": self.End.y, "Z": self.End.z} if f: - params['F'] = f + params["F"] = f return params def g1Command(self, f): @@ -287,9 +301,9 @@ class Chord (object): def arcCommand(self, cmd, center, f): params = self.commandParams(f) d = center - self.Start - params['I'] = d.x - params['J'] = d.y - params['K'] = 0 + params["I"] = d.x + params["J"] = d.y + params["K"] = 0 return Path.Command(cmd, params) def g2Command(self, center, f): @@ -302,13 +316,17 @@ class Chord (object): return not PathGeom.isRoughly(self.End.z, self.Start.z) def isANoopMove(self): - PathLog.debug("{}.isANoopMove(): {}".format(self, PathGeom.pointsCoincide(self.Start, self.End))) + PathLog.debug( + "{}.isANoopMove(): {}".format( + self, PathGeom.pointsCoincide(self.Start, self.End) + ) + ) return PathGeom.pointsCoincide(self.Start, self.End) def foldsBackOrTurns(self, chord, side): direction = chord.getDirectionOf(self) PathLog.info(" - direction = %s/%s" % (direction, side)) - return direction == 'Back' or direction == side + return direction == "Back" or direction == side def connectsTo(self, chord): return PathGeom.pointsCoincide(self.End, chord.Start) @@ -335,7 +353,7 @@ class Bone(object): if self.cAngle is None: baseAngle = self.inChord.getAngleXY() turnAngle = self.outChord.getAngle(self.inChord) - theta = addAngle(baseAngle, (turnAngle - math.pi)/2) + theta = addAngle(baseAngle, (turnAngle - math.pi) / 2) if self.obj.Side == Side.Left: theta = addAngle(theta, math.pi) self.tAngle = turnAngle @@ -345,7 +363,7 @@ class Bone(object): def distance(self, toolRadius): if self.cDist is None: self.angle() # make sure the angles are initialized - self.cDist = toolRadius / math.cos(self.tAngle/2) + self.cDist = toolRadius / math.cos(self.tAngle / 2) return self.cDist def corner(self, toolRadius): @@ -368,7 +386,10 @@ class Bone(object): # moving directly towards the corner PathLog.debug("adaptive - on target: %.2f - %.2f" % (distance, toolRadius)) return distance - toolRadius - PathLog.debug("adaptive - angles: corner=%.2f bone=%.2f diff=%.12f" % (theta/math.pi, boneAngle/math.pi, theta - boneAngle)) + PathLog.debug( + "adaptive - angles: corner=%.2f bone=%.2f diff=%.12f" + % (theta / math.pi, boneAngle / math.pi, theta - boneAngle) + ) # The bones root and end point form a triangle with the intersection of the tool path # with the toolRadius circle around the bone end point. @@ -376,7 +397,9 @@ class Bone(object): # c = distance # b = self.toolRadius # beta = fabs(boneAngle - theta) - beta = math.fabs(addAngle(boneAngle, -theta)) # pylint: disable=invalid-unary-operand-type + beta = math.fabs( + addAngle(boneAngle, -theta) + ) # pylint: disable=invalid-unary-operand-type D = (distance / toolRadius) * math.sin(beta) if D > 1: # no intersection PathLog.debug("adaptive - no intersection - no bone") @@ -395,28 +418,68 @@ class Bone(object): length2 = toolRadius * math.sin(alpha2) / math.sin(beta2) length = min(length, length2) - PathLog.debug("adaptive corner=%.2f * %.2f˚ -> bone=%.2f * %.2f˚" % (distance, theta, length, boneAngle)) + PathLog.debug( + "adaptive corner=%.2f * %.2f˚ -> bone=%.2f * %.2f˚" + % (distance, theta, length, boneAngle) + ) return length class ObjectDressup(object): - def __init__(self, obj, base): # Tool Properties - obj.addProperty("App::PropertyLink", "Base", "Base", QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The base path to modify")) - obj.addProperty("App::PropertyEnumeration", "Side", "Dressup", QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The side of path to insert bones")) + obj.addProperty( + "App::PropertyLink", + "Base", + "Base", + QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The base path to modify"), + ) + obj.addProperty( + "App::PropertyEnumeration", + "Side", + "Dressup", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupDogbone", "The side of path to insert bones" + ), + ) obj.Side = [Side.Left, Side.Right] obj.Side = Side.Right - obj.addProperty("App::PropertyEnumeration", "Style", "Dressup", QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The style of bones")) + obj.addProperty( + "App::PropertyEnumeration", + "Style", + "Dressup", + QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The style of bones"), + ) obj.Style = Style.All obj.Style = Style.Dogbone - obj.addProperty("App::PropertyIntegerList", "BoneBlacklist", "Dressup", QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "Bones that aren't dressed up")) + obj.addProperty( + "App::PropertyIntegerList", + "BoneBlacklist", + "Dressup", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupDogbone", "Bones that aren't dressed up" + ), + ) obj.BoneBlacklist = [] - obj.setEditorMode('BoneBlacklist', 2) # hide this one - obj.addProperty("App::PropertyEnumeration", "Incision", "Dressup", QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The algorithm to determine the bone length")) + obj.setEditorMode("BoneBlacklist", 2) # hide this one + obj.addProperty( + "App::PropertyEnumeration", + "Incision", + "Dressup", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupDogbone", "The algorithm to determine the bone length" + ), + ) obj.Incision = Incision.All obj.Incision = Incision.Adaptive - obj.addProperty("App::PropertyFloat", "Custom", "Dressup", QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "Dressup length if Incision == custom")) + obj.addProperty( + "App::PropertyFloat", + "Custom", + "Dressup", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupDogbone", "Dressup length if Incision == custom" + ), + ) obj.Custom = 0.0 obj.Proxy = self obj.Base = base @@ -431,7 +494,7 @@ class ObjectDressup(object): self.bones = None def onDocumentRestored(self, obj): - obj.setEditorMode('BoneBlacklist', 2) # hide this one + obj.setEditorMode("BoneBlacklist", 2) # hide this one def __getstate__(self): return None @@ -446,14 +509,29 @@ class ObjectDressup(object): # Answer true if a dogbone could be on either end of the chord, given its command def canAttachDogbone(self, cmd, chord): - return cmd.Name in movestraight and not chord.isAPlungeMove() and not chord.isANoopMove() + return ( + cmd.Name in movestraight + and not chord.isAPlungeMove() + and not chord.isANoopMove() + ) def shouldInsertDogbone(self, obj, inChord, outChord): return outChord.foldsBackOrTurns(inChord, self.theOtherSideOf(obj.Side)) def findPivotIntersection(self, pivot, pivotEdge, edge, refPt, d, color): # pylint: disable=unused-argument - PathLog.track("(%.2f, %.2f)^%.2f - [(%.2f, %.2f), (%.2f, %.2f)]" % (pivotEdge.Curve.Center.x, pivotEdge.Curve.Center.y, pivotEdge.Curve.Radius, edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y, edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y)) + PathLog.track( + "(%.2f, %.2f)^%.2f - [(%.2f, %.2f), (%.2f, %.2f)]" + % ( + pivotEdge.Curve.Center.x, + pivotEdge.Curve.Center.y, + pivotEdge.Curve.Radius, + edge.Vertexes[0].Point.x, + edge.Vertexes[0].Point.y, + edge.Vertexes[1].Point.x, + edge.Vertexes[1].Point.y, + ) + ) ppt = None pptDistance = 0 for pt in DraftGeomUtils.findIntersection(edge, pivotEdge, dts=False): @@ -469,7 +547,9 @@ class ObjectDressup(object): PathLog.debug("Taking tangent as intersect %s" % tangent) ppt = pivot + tangent else: - PathLog.debug("Taking chord start as intersect %s" % edge.Vertexes[0].Point) + PathLog.debug( + "Taking chord start as intersect %s" % edge.Vertexes[0].Point + ) ppt = edge.Vertexes[0].Point # debugMarker(ppt, "ptt.%d-%s.in" % (self.boneId, d), color, 0.2) PathLog.debug(" --> (%.2f, %.2f)" % (ppt.x, ppt.y)) @@ -479,15 +559,17 @@ class ObjectDressup(object): param = edge.Curve.parameter(point) return edge.FirstParameter <= param <= edge.LastParameter - def smoothChordCommands(self, bone, inChord, outChord, edge, wire, corner, smooth, color=None): + def smoothChordCommands( + self, bone, inChord, outChord, edge, wire, corner, smooth, color=None + ): if smooth == 0: PathLog.info(" No smoothing requested") return [bone.lastCommand, outChord.g1Command(bone.F)] - d = 'in' + d = "in" refPoint = inChord.Start if smooth == Smooth.Out: - d = 'out' + d = "out" refPoint = outChord.End if DraftGeomUtils.areColinear(inChord.asEdge(), outChord.asEdge()): @@ -497,15 +579,36 @@ class ObjectDressup(object): pivot = None pivotDistance = 0 - PathLog.info("smooth: (%.2f, %.2f)-(%.2f, %.2f)" % (edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y, edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y)) + PathLog.info( + "smooth: (%.2f, %.2f)-(%.2f, %.2f)" + % ( + edge.Vertexes[0].Point.x, + edge.Vertexes[0].Point.y, + edge.Vertexes[1].Point.x, + edge.Vertexes[1].Point.y, + ) + ) for e in wire.Edges: self.dbg.append(e) if type(e.Curve) == Part.LineSegment or type(e.Curve) == Part.Line: - PathLog.debug(" (%.2f, %.2f)-(%.2f, %.2f)" % (e.Vertexes[0].Point.x, e.Vertexes[0].Point.y, e.Vertexes[1].Point.x, e.Vertexes[1].Point.y)) + PathLog.debug( + " (%.2f, %.2f)-(%.2f, %.2f)" + % ( + e.Vertexes[0].Point.x, + e.Vertexes[0].Point.y, + e.Vertexes[1].Point.x, + e.Vertexes[1].Point.y, + ) + ) else: - PathLog.debug(" (%.2f, %.2f)^%.2f" % (e.Curve.Center.x, e.Curve.Center.y, e.Curve.Radius)) + PathLog.debug( + " (%.2f, %.2f)^%.2f" + % (e.Curve.Center.x, e.Curve.Center.y, e.Curve.Radius) + ) for pt in DraftGeomUtils.findIntersection(edge, e, True, findAll=True): - if not PathGeom.pointsCoincide(pt, corner) and self.pointIsOnEdge(pt, e): + if not PathGeom.pointsCoincide(pt, corner) and self.pointIsOnEdge( + pt, e + ): # debugMarker(pt, "candidate-%d-%s" % (self.boneId, d), color, 0.05) PathLog.debug(" -> candidate") distance = (pt - refPoint).Length @@ -518,9 +621,15 @@ class ObjectDressup(object): if pivot: # debugCircle(pivot, self.toolRadius, "pivot.%d-%s" % (self.boneId, d), color) - pivotEdge = Part.Edge(Part.Circle(pivot, FreeCAD.Vector(0, 0, 1), self.toolRadius)) - t1 = self.findPivotIntersection(pivot, pivotEdge, inChord.asEdge(), inChord.End, d, color) - t2 = self.findPivotIntersection(pivot, pivotEdge, outChord.asEdge(), inChord.End, d, color) + pivotEdge = Part.Edge( + Part.Circle(pivot, FreeCAD.Vector(0, 0, 1), self.toolRadius) + ) + t1 = self.findPivotIntersection( + pivot, pivotEdge, inChord.asEdge(), inChord.End, d, color + ) + t2 = self.findPivotIntersection( + pivot, pivotEdge, outChord.asEdge(), inChord.End, d, color + ) commands = [] if not PathGeom.pointsCoincide(t1, inChord.Start): @@ -530,7 +639,10 @@ class ObjectDressup(object): PathLog.debug(" add g3 command") commands.append(Chord(t1, t2).g3Command(pivot, bone.F)) else: - PathLog.debug(" add g2 command center=(%.2f, %.2f) -> from (%2f, %.2f) to (%.2f, %.2f" % (pivot.x, pivot.y, t1.x, t1.y, t2.x, t2.y)) + PathLog.debug( + " add g2 command center=(%.2f, %.2f) -> from (%2f, %.2f) to (%.2f, %.2f" + % (pivot.x, pivot.y, t1.x, t1.y, t2.x, t2.y) + ) commands.append(Chord(t1, t2).g2Command(pivot, bone.F)) if not PathGeom.pointsCoincide(t2, outChord.End): PathLog.debug(" add lead out") @@ -575,7 +687,12 @@ class ObjectDressup(object): bone.tip = boneInChord.End if bone.smooth == 0: - return [bone.lastCommand, boneInChord.g1Command(bone.F), boneOutChord.g1Command(bone.F), bone.outChord.g1Command(bone.F)] + return [ + bone.lastCommand, + boneInChord.g1Command(bone.F), + boneOutChord.g1Command(bone.F), + bone.outChord.g1Command(bone.F), + ] # reconstruct the corner and convert to an edge offset = corner - bone.inChord.End @@ -587,7 +704,7 @@ class ObjectDressup(object): # construct a shape representing the cut made by the bone vt0 = FreeCAD.Vector(0, self.toolRadius, 0) - vt1 = FreeCAD.Vector(length, self.toolRadius, 0) + vt1 = FreeCAD.Vector(length, self.toolRadius, 0) vb0 = FreeCAD.Vector(0, -self.toolRadius, 0) vb1 = FreeCAD.Vector(length, -self.toolRadius, 0) vm2 = FreeCAD.Vector(length + self.toolRadius, 0, 0) @@ -601,12 +718,32 @@ class ObjectDressup(object): boneArc = Part.Arc(vt1, vm2, vb1) # boneArc = Part.Circle(FreeCAD.Vector(length, 0, 0), FreeCAD.Vector(0,0,1), self.toolRadius) boneWire = Part.Shape([boneTop, boneArc, boneBot, boneLid]) - boneWire.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), boneAngle * 180 / math.pi) + boneWire.rotate( + FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), boneAngle * 180 / math.pi + ) boneWire.translate(bone.inChord.End) self.boneShapes = [cornerShape, boneWire] - bone.inCommands = self.smoothChordCommands(bone, bone.inChord, boneInChord, Part.Edge(iLine), boneWire, corner, bone.smooth & Smooth.In, (1., 0., 0.)) - bone.outCommands = self.smoothChordCommands(bone, boneOutChord, bone.outChord, Part.Edge(oLine), boneWire, corner, bone.smooth & Smooth.Out, (0., 1., 0.)) + bone.inCommands = self.smoothChordCommands( + bone, + bone.inChord, + boneInChord, + Part.Edge(iLine), + boneWire, + corner, + bone.smooth & Smooth.In, + (1.0, 0.0, 0.0), + ) + bone.outCommands = self.smoothChordCommands( + bone, + boneOutChord, + bone.outChord, + Part.Edge(oLine), + boneWire, + corner, + bone.smooth & Smooth.Out, + (0.0, 1.0, 0.0), + ) return bone.inCommands + bone.outCommands def dogbone(self, bone): @@ -617,13 +754,13 @@ class ObjectDressup(object): def tboneHorizontal(self, bone): angle = bone.angle() boneAngle = 0 - if math.fabs(angle) > math.pi/2: + if math.fabs(angle) > math.pi / 2: boneAngle = math.pi return self.inOutBoneCommands(bone, boneAngle, self.toolRadius) def tboneVertical(self, bone): angle = bone.angle() - boneAngle = math.pi/2 + boneAngle = math.pi / 2 if PathGeom.isRoughly(angle, math.pi) or angle < 0: boneAngle = -boneAngle return self.inOutBoneCommands(bone, boneAngle, self.toolRadius) @@ -635,14 +772,22 @@ class ObjectDressup(object): boneAngle = bone.outChord.getAngleXY() if Side.Right == bone.outChord.getDirectionOf(bone.inChord): - boneAngle = boneAngle - math.pi/2 + boneAngle = boneAngle - math.pi / 2 else: - boneAngle = boneAngle + math.pi/2 + boneAngle = boneAngle + math.pi / 2 - onInString = 'out' + onInString = "out" if onIn: - onInString = 'in' - PathLog.debug("tboneEdge boneAngle[%s]=%.2f (in=%.2f, out=%.2f)" % (onInString, boneAngle/math.pi, bone.inChord.getAngleXY()/math.pi, bone.outChord.getAngleXY()/math.pi)) + onInString = "in" + PathLog.debug( + "tboneEdge boneAngle[%s]=%.2f (in=%.2f, out=%.2f)" + % ( + onInString, + boneAngle / math.pi, + bone.inChord.getAngleXY() / math.pi, + bone.outChord.getAngleXY() / math.pi, + ) + ) return self.inOutBoneCommands(bone, boneAngle, self.toolRadius) def tboneLongEdge(self, bone): @@ -661,7 +806,7 @@ class ObjectDressup(object): elif bone.location() in self.locationBlacklist: bone.obj.BoneBlacklist.append(bone.boneId) blacklisted = True - elif hasattr(bone.obj.Base, 'BoneBlacklist'): + elif hasattr(bone.obj.Base, "BoneBlacklist"): parentConsumed = bone.boneId not in bone.obj.Base.BoneBlacklist blacklisted = parentConsumed if blacklisted: @@ -685,7 +830,10 @@ class ObjectDressup(object): return [bone.lastCommand, bone.outChord.g1Command(bone.F)] def insertBone(self, bone): - PathLog.debug(">----------------------------------- %d --------------------------------------" % bone.boneId) + PathLog.debug( + ">----------------------------------- %d --------------------------------------" + % bone.boneId + ) self.boneShapes = [] blacklisted, inaccessible = self.boneIsBlacklisted(bone) enabled = not blacklisted @@ -701,7 +849,10 @@ class ObjectDressup(object): bone.commands = commands self.shapes[bone.boneId] = self.boneShapes - PathLog.debug("<----------------------------------- %d --------------------------------------" % bone.boneId) + PathLog.debug( + "<----------------------------------- %d --------------------------------------" + % bone.boneId + ) return commands def removePathCrossing(self, commands, bone1, bone2): @@ -709,24 +860,26 @@ class ObjectDressup(object): bones = bone2.commands if True and hasattr(bone1, "outCommands") and hasattr(bone2, "inCommands"): inEdges = edgesForCommands(bone1.outCommands, bone1.tip) - outEdges = edgesForCommands(bone2.inCommands, bone2.inChord.Start) + outEdges = edgesForCommands(bone2.inCommands, bone2.inChord.Start) for i in range(len(inEdges)): e1 = inEdges[i] - for j in range(len(outEdges)-1, -1, -1): + for j in range(len(outEdges) - 1, -1, -1): e2 = outEdges[j] cutoff = DraftGeomUtils.findIntersection(e1, e2) for pt in cutoff: # debugCircle(e1.Curve.Center, e1.Curve.Radius, "bone.%d-1" % (self.boneId), (1.,0.,0.)) # debugCircle(e2.Curve.Center, e2.Curve.Radius, "bone.%d-2" % (self.boneId), (0.,1.,0.)) - if PathGeom.pointsCoincide(pt, e1.valueAt(e1.LastParameter)) or PathGeom.pointsCoincide(pt, e2.valueAt(e2.FirstParameter)): + if PathGeom.pointsCoincide( + pt, e1.valueAt(e1.LastParameter) + ) or PathGeom.pointsCoincide(pt, e2.valueAt(e2.FirstParameter)): continue # debugMarker(pt, "it", (0.0, 1.0, 1.0)) # 1. remove all redundant commands - commands = commands[:-(len(inEdges) - i)] + commands = commands[: -(len(inEdges) - i)] # 2., correct where c1 ends c1 = bone1.outCommands[i] c1Params = c1.Parameters - c1Params.update({'X': pt.x, 'Y': pt.y, 'Z': pt.z}) + c1Params.update({"X": pt.x, "Y": pt.y, "Z": pt.z}) c1 = Path.Command(c1.Name, c1Params) commands.append(c1) # 3. change where c2 starts, this depends on the command itself @@ -735,10 +888,12 @@ class ObjectDressup(object): center = e2.Curve.Center offset = center - pt c2Params = c2.Parameters - c2Params.update({'I': offset.x, 'J': offset.y, 'K': offset.z}) + c2Params.update( + {"I": offset.x, "J": offset.y, "K": offset.z} + ) c2 = Path.Command(c2.Name, c2Params) bones = [c2] - bones.extend(bone2.commands[j+1:]) + bones.extend(bone2.commands[j + 1 :]) else: bones = bone2.commands[j:] # there can only be the one ... @@ -758,11 +913,13 @@ class ObjectDressup(object): self.setup(obj, False) - commands = [] # the dressed commands - lastChord = Chord() # the last chord - lastCommand = None # the command that generated the last chord - lastBone = None # track last bone for optimizations - oddsAndEnds = [] # track chords that are connected to plunges - in case they form a loop + commands = [] # the dressed commands + lastChord = Chord() # the last chord + lastCommand = None # the command that generated the last chord + lastBone = None # track last bone for optimizations + oddsAndEnds = ( + [] + ) # track chords that are connected to plunges - in case they form a loop boneId = 1 self.bones = [] @@ -782,32 +939,60 @@ class ObjectDressup(object): thisChord = lastChord.moveToParameters(thisCommand.Parameters) thisIsACandidate = self.canAttachDogbone(thisCommand, thisChord) - if thisIsACandidate and lastCommand and self.shouldInsertDogbone(obj, lastChord, thisChord): + if ( + thisIsACandidate + and lastCommand + and self.shouldInsertDogbone(obj, lastChord, thisChord) + ): PathLog.info(" Found bone corner: {}".format(lastChord.End)) - bone = Bone(boneId, obj, lastCommand, lastChord, thisChord, Smooth.InAndOut, thisCommand.Parameters.get('F')) + bone = Bone( + boneId, + obj, + lastCommand, + lastChord, + thisChord, + Smooth.InAndOut, + thisCommand.Parameters.get("F"), + ) bones = self.insertBone(bone) boneId += 1 if lastBone: PathLog.info(" removing potential path crossing") # debugMarker(thisChord.Start, "it", (1.0, 0.0, 1.0)) - commands, bones = self.removePathCrossing(commands, lastBone, bone) + commands, bones = self.removePathCrossing( + commands, lastBone, bone + ) commands.extend(bones[:-1]) lastCommand = bones[-1] lastBone = bone elif lastCommand and thisChord.isAPlungeMove(): PathLog.info(" Looking for connection in odds and ends") haveNewLastCommand = False - for chord in (chord for chord in oddsAndEnds if lastChord.connectsTo(chord)): + for chord in ( + chord for chord in oddsAndEnds if lastChord.connectsTo(chord) + ): if self.shouldInsertDogbone(obj, lastChord, chord): PathLog.info(" and there is one") - PathLog.debug(" odd/end={} last={}".format(chord, lastChord)) - bone = Bone(boneId, obj, lastCommand, lastChord, chord, Smooth.In, lastCommand.Parameters.get('F')) + PathLog.debug( + " odd/end={} last={}".format(chord, lastChord) + ) + bone = Bone( + boneId, + obj, + lastCommand, + lastChord, + chord, + Smooth.In, + lastCommand.Parameters.get("F"), + ) bones = self.insertBone(bone) boneId += 1 if lastBone: PathLog.info(" removing potential path crossing") # debugMarker(chord.Start, "it", (0.0, 1.0, 1.0)) - commands, bones = self.removePathCrossing(commands, lastBone, bone) + commands, bones = self.removePathCrossing( + commands, lastBone, bone + ) commands.extend(bones[:-1]) lastCommand = bones[-1] haveNewLastCommand = True @@ -839,7 +1024,7 @@ class ObjectDressup(object): lastChord = thisChord else: - if thisCommand.Name[0] != '(': + if thisCommand.Name[0] != "(": PathLog.info(" Clean slate") if lastCommand: commands.append(lastCommand) @@ -861,12 +1046,12 @@ class ObjectDressup(object): PathLog.info("Default side = right") # otherwise dogbones are opposite of the base path's side side = Side.Right - if hasattr(obj.Base, 'Side') and obj.Base.Side == 'Inside': + if hasattr(obj.Base, "Side") and obj.Base.Side == "Inside": PathLog.info("inside -> side = left") side = Side.Left else: PathLog.info("not inside -> side stays right") - if hasattr(obj.Base, 'Direction') and obj.Base.Direction == 'CCW': + if hasattr(obj.Base, "Direction") and obj.Base.Direction == "CCW": PathLog.info("CCW -> switch sides") side = Side.oppositeOf(side) else: @@ -890,7 +1075,7 @@ class ObjectDressup(object): def boneStateList(self, obj): state = {} # If the receiver was loaded from file, then it never generated the bone list. - if not hasattr(self, 'bones'): + if not hasattr(self, "bones"): self.execute(obj) for (nr, loc, enabled, inaccessible) in self.bones: item = state.get((loc[0], loc[1])) @@ -901,14 +1086,14 @@ class ObjectDressup(object): state[(loc[0], loc[1])] = (enabled, inaccessible, [nr], [loc[2]]) return state -class Marker(object): +class Marker(object): def __init__(self, pt, r, h): if PathGeom.isRoughly(h, 0): h = 0.1 self.pt = pt - self.r = r - self.h = h + self.r = r + self.h = h self.sep = coin.SoSeparator() self.pos = coin.SoTranslation() self.pos.translation = (pt.x, pt.y, pt.z + h / 2) @@ -943,8 +1128,8 @@ class Marker(object): def color(self, id): if id == 1: - return coin.SbColor(.9, .9, .5) - return coin.SbColor(.9, .5, .9) + return coin.SbColor(0.9, 0.9, 0.5) + return coin.SbColor(0.9, 0.5, 0.9) class TaskPanel(object): @@ -957,7 +1142,9 @@ class TaskPanel(object): self.obj = obj self.form = FreeCADGui.PySideUic.loadUi(":/panels/DogboneEdit.ui") self.s = None - FreeCAD.ActiveDocument.openTransaction(translate("Path_DressupDogbone", "Edit Dogbone Dress-up")) + FreeCAD.ActiveDocument.openTransaction( + translate("Path_DressupDogbone", "Edit Dogbone Dress-up") + ) self.height = 10 self.markers = [] @@ -999,8 +1186,10 @@ class TaskPanel(object): def updateBoneList(self): itemList = [] - for loc, (enabled, inaccessible, ids, zs) in PathUtil.keyValueIter(self.obj.Proxy.boneStateList(self.obj)): - lbl = '(%.2f, %.2f): %s' % (loc[0], loc[1], ','.join(str(id) for id in ids)) + for loc, (enabled, inaccessible, ids, zs) in PathUtil.keyValueIter( + self.obj.Proxy.boneStateList(self.obj) + ): + lbl = "(%.2f, %.2f): %s" % (loc[0], loc[1], ",".join(str(id) for id in ids)) item = QtGui.QListWidgetItem(lbl) if enabled: item.setCheckState(QtCore.Qt.CheckState.Checked) @@ -1008,7 +1197,10 @@ class TaskPanel(object): item.setCheckState(QtCore.Qt.CheckState.Unchecked) flags = QtCore.Qt.ItemFlag.ItemIsSelectable if not inaccessible: - flags |= QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsUserCheckable + flags |= ( + QtCore.Qt.ItemFlag.ItemIsEnabled + | QtCore.Qt.ItemFlag.ItemIsUserCheckable + ) item.setFlags(flags) item.setData(self.DataIds, ids) item.setData(self.DataKey, ids[0]) @@ -1020,7 +1212,13 @@ class TaskPanel(object): self.form.bones.addItem(item) loc = item.data(self.DataLoc) r = max(self.obj.Proxy.length, 1) - markers.append(Marker(FreeCAD.Vector(loc[0], loc[1], min(zs)), r, max(1, max(zs) - min(zs)))) + markers.append( + Marker( + FreeCAD.Vector(loc[0], loc[1], min(zs)), + r, + max(1, max(zs) - min(zs)), + ) + ) for m in self.markers: self.viewProvider.switch.removeChild(m.sep) for m in markers: @@ -1035,9 +1233,9 @@ class TaskPanel(object): if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG: for obj in FreeCAD.ActiveDocument.Objects: - if obj.Name.startswith('Shape'): + if obj.Name.startswith("Shape"): FreeCAD.ActiveDocument.removeObject(obj.Name) - PathLog.info('object name %s' % self.obj.Name) + PathLog.info("object name %s" % self.obj.Name) if hasattr(self.obj.Proxy, "shapes"): PathLog.info("showing shapes attribute") for shapes in self.obj.Proxy.shapes.values(): @@ -1091,23 +1289,27 @@ class TaskPanel(object): for i, m in enumerate(self.markers): m.setSelected(i == index) + class SelObserver(object): def __init__(self): import PathScripts.PathSelection as PST + PST.eselect() def __del__(self): import PathScripts.PathSelection as PST + PST.clear() def addSelection(self, doc, obj, sub, pnt): # pylint: disable=unused-argument - FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')') + FreeCADGui.doCommand( + "Gui.Selection.addSelection(FreeCAD.ActiveDocument." + obj + ")" + ) FreeCADGui.updateGui() class ViewProviderDressup(object): - def __init__(self, vobj): self.vobj = vobj self.obj = None @@ -1148,7 +1350,7 @@ class ViewProviderDressup(object): return None def onDelete(self, arg1=None, arg2=None): - '''this makes sure that the base operation is added back to the project and visible''' + """this makes sure that the base operation is added back to the project and visible""" # pylint: disable=unused-argument if arg1.Object and arg1.Object.Base: FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name).Visibility = True @@ -1159,11 +1361,11 @@ class ViewProviderDressup(object): return True -def Create(base, name='DogboneDressup'): - ''' +def Create(base, name="DogboneDressup"): + """ Create(obj, name='DogboneDressup') ... dresses the given PathProfile/PathContour object with dogbones. - ''' - obj = FreeCAD.ActiveDocument.addObject('Path::FeaturePython', name) + """ + obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) dbo = ObjectDressup(obj, base) job = PathUtils.findParentJob(base) job.Proxy.addOperation(obj, base) @@ -1180,9 +1382,16 @@ class CommandDressupDogbone(object): # pylint: disable=no-init def GetResources(self): - return {'Pixmap': 'Path_Dressup', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "Dogbone Dress-up"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "Creates a Dogbone Dress-up object from a selected path")} + return { + "Pixmap": "Path_Dressup", + "MenuText": QtCore.QT_TRANSLATE_NOOP( + "Path_DressupDogbone", "Dogbone Dress-up" + ), + "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "Path_DressupDogbone", + "Creates a Dogbone Dress-up object from a selected path", + ), + } def IsActive(self): if FreeCAD.ActiveDocument is not None: @@ -1196,17 +1405,27 @@ class CommandDressupDogbone(object): # check that the selection contains exactly what we want selection = FreeCADGui.Selection.getSelection() if len(selection) != 1: - FreeCAD.Console.PrintError(translate("Path_DressupDogbone", "Please select one path object")+"\n") + FreeCAD.Console.PrintError( + translate("Path_DressupDogbone", "Please select one path object") + "\n" + ) return baseObject = selection[0] if not baseObject.isDerivedFrom("Path::Feature"): - FreeCAD.Console.PrintError(translate("Path_DressupDogbone", "The selected object is not a path")+"\n") + FreeCAD.Console.PrintError( + translate("Path_DressupDogbone", "The selected object is not a path") + + "\n" + ) return # everything ok! - FreeCAD.ActiveDocument.openTransaction(translate("Path_DressupDogbone", "Create Dogbone Dress-up")) - FreeCADGui.addModule('PathScripts.PathDressupDogbone') - FreeCADGui.doCommand("PathScripts.PathDressupDogbone.Create(FreeCAD.ActiveDocument.%s)" % baseObject.Name) + FreeCAD.ActiveDocument.openTransaction( + translate("Path_DressupDogbone", "Create Dogbone Dress-up") + ) + FreeCADGui.addModule("PathScripts.PathDressupDogbone") + FreeCADGui.doCommand( + "PathScripts.PathDressupDogbone.Create(FreeCAD.ActiveDocument.%s)" + % baseObject.Name + ) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() @@ -1215,6 +1434,7 @@ if FreeCAD.GuiUp: import FreeCADGui from PySide import QtGui from pivy import coin - FreeCADGui.addCommand('Path_DressupDogbone', CommandDressupDogbone()) + + FreeCADGui.addCommand("Path_DressupDogbone", CommandDressupDogbone()) FreeCAD.Console.PrintLog("Loading DressupDogbone... done\n") diff --git a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py index 3f36d43d05..66e5061183 100644 --- a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py +++ b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py @@ -36,10 +36,11 @@ from PySide import QtCore # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader -Part = LazyLoader('Part', globals(), 'Part') + +Part = LazyLoader("Part", globals(), "Part") PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -#PathLog.trackModule() +# PathLog.trackModule() failures = [] @@ -53,10 +54,28 @@ def debugEdge(edge, prefix, force=False): pf = edge.valueAt(edge.FirstParameter) pl = edge.valueAt(edge.LastParameter) if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment: - print("%s %s((%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f))" % (prefix, type(edge.Curve), pf.x, pf.y, pf.z, pl.x, pl.y, pl.z)) + print( + "%s %s((%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f))" + % (prefix, type(edge.Curve), pf.x, pf.y, pf.z, pl.x, pl.y, pl.z) + ) else: - pm = edge.valueAt((edge.FirstParameter+edge.LastParameter)/2) - print("%s %s((%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f))" % (prefix, type(edge.Curve), pf.x, pf.y, pf.z, pm.x, pm.y, pm.z, pl.x, pl.y, pl.z)) + pm = edge.valueAt((edge.FirstParameter + edge.LastParameter) / 2) + print( + "%s %s((%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f))" + % ( + prefix, + type(edge.Curve), + pf.x, + pf.y, + pf.z, + pm.x, + pm.y, + pm.z, + pl.x, + pl.y, + pl.z, + ) + ) def debugMarker(vector, label, color=None, radius=0.5): @@ -64,7 +83,9 @@ def debugMarker(vector, label, color=None, radius=0.5): obj = FreeCAD.ActiveDocument.addObject("Part::Sphere", label) obj.Label = label obj.Radius = radius - obj.Placement = FreeCAD.Placement(vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0)) + obj.Placement = FreeCAD.Placement( + vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) + ) if color: obj.ViewObject.ShapeColor = color @@ -75,7 +96,9 @@ def debugCylinder(vector, r, height, label, color=None): obj.Label = label obj.Radius = r obj.Height = height - obj.Placement = FreeCAD.Placement(vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0)) + obj.Placement = FreeCAD.Placement( + vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) + ) obj.ViewObject.Transparency = 90 if color: obj.ViewObject.ShapeColor = color @@ -88,7 +111,9 @@ def debugCone(vector, r1, r2, height, label, color=None): obj.Radius1 = r1 obj.Radius2 = r2 obj.Height = height - obj.Placement = FreeCAD.Placement(vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0)) + obj.Placement = FreeCAD.Placement( + vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) + ) obj.ViewObject.Transparency = 90 if color: obj.ViewObject.ShapeColor = color @@ -96,7 +121,10 @@ def debugCone(vector, r1, r2, height, label, color=None): class Tag: def __init__(self, nr, x, y, width, height, angle, radius, enabled=True): - PathLog.track("%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d" % (x, y, width, height, angle, radius, enabled)) + PathLog.track( + "%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d" + % (x, y, width, height, angle, radius, enabled) + ) self.nr = nr self.x = x self.y = y @@ -104,7 +132,11 @@ class Tag: self.height = math.fabs(height) self.actualHeight = self.height self.angle = math.fabs(angle) - self.radius = radius if FreeCAD.Units.Quantity == type(radius) else FreeCAD.Units.Quantity(radius, FreeCAD.Units.Length) + self.radius = ( + radius + if FreeCAD.Units.Quantity == type(radius) + else FreeCAD.Units.Quantity(radius, FreeCAD.Units.Length) + ) self.enabled = enabled self.isSquare = False @@ -151,7 +183,7 @@ class Tag: # with top r2 = r1 - dr s = height / math.sin(rad) - radius = min(r2, s) * math.tan((math.pi - rad)/2) * 0.95 + radius = min(r2, s) * math.tan((math.pi - rad) / 2) * 0.95 else: # triangular r2 = 0 @@ -164,7 +196,9 @@ class Tag: # degenerated case - no tag PathLog.debug("Part.makeSphere(%f / 10000)" % (r1)) self.solid = Part.makeSphere(r1 / 10000) - if not PathGeom.isRoughly(0, R): # testing is easier if the solid is not rotated + if not PathGeom.isRoughly( + 0, R + ): # testing is easier if the solid is not rotated angle = -PathGeom.getAngle(self.originAt(0)) * 180 / math.pi PathLog.debug("solid.rotate(%f)" % angle) self.solid.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), angle) @@ -178,14 +212,27 @@ class Tag: self.solid = self.solid.makeFillet(radius, [self.solid.Edges[0]]) def filterIntersections(self, pts, face): - if type(face.Surface) == Part.Cone or type(face.Surface) == Part.Cylinder or type(face.Surface) == Part.Toroid: + if ( + type(face.Surface) == Part.Cone + or type(face.Surface) == Part.Cylinder + or type(face.Surface) == Part.Toroid + ): PathLog.track("it's a cone/cylinder, checking z") - return list([pt for pt in pts if pt.z >= self.bottom() and pt.z <= self.top()]) + return list( + [pt for pt in pts if pt.z >= self.bottom() and pt.z <= self.top()] + ) if type(face.Surface) == Part.Plane: PathLog.track("it's a plane, checking R") c = face.Edges[0].Curve - if (type(c) == Part.Circle): - return list([pt for pt in pts if (pt - c.Center).Length <= c.Radius or PathGeom.isRoughly((pt - c.Center).Length, c.Radius)]) + if type(c) == Part.Circle: + return list( + [ + pt + for pt in pts + if (pt - c.Center).Length <= c.Radius + or PathGeom.isRoughly((pt - c.Center).Length, c.Radius) + ] + ) PathLog.error("==== we got a %s" % face.Surface) def isPointOnEdge(self, pt, edge): @@ -194,7 +241,9 @@ class Tag: return True if edge.LastParameter <= param <= edge.FirstParameter: return True - if PathGeom.isRoughly(edge.FirstParameter, param) or PathGeom.isRoughly(edge.LastParameter, param): + if PathGeom.isRoughly(edge.FirstParameter, param) or PathGeom.isRoughly( + edge.LastParameter, param + ): return True # print("-------- X %.2f <= %.2f <=%.2f (%.2f, %.2f, %.2f) %.2f:%.2f" % (edge.FirstParameter, param, edge.LastParameter, pt.x, pt.y, pt.z, edge.Curve.parameter(edge.valueAt(edge.FirstParameter)), edge.Curve.parameter(edge.valueAt(edge.LastParameter)))) # p1 = edge.Vertexes[0] @@ -209,7 +258,11 @@ class Tag: vertexes = edge.common(solid).Vertexes if vertexes: pt = sorted(vertexes, key=lambda v: (v.Point - refPt).Length)[0].Point - debugEdge(edge, "intersects (%.2f, %.2f, %.2f) -> (%.2f, %.2f, %.2f)" % (refPt.x, refPt.y, refPt.z, pt.x, pt.y, pt.z)) + debugEdge( + edge, + "intersects (%.2f, %.2f, %.2f) -> (%.2f, %.2f, %.2f)" + % (refPt.x, refPt.y, refPt.z, pt.x, pt.y, pt.z), + ) return pt return None @@ -220,10 +273,12 @@ class Tag: if self.enabled: zFirst = edge.valueAt(edge.FirstParameter).z - zLast = edge.valueAt(edge.LastParameter).z + zLast = edge.valueAt(edge.LastParameter).z zMax = self.top() if isDefinitelySmaller(zFirst, zMax) or isDefinitelySmaller(zLast, zMax): - return self.nextIntersectionClosestTo(edge, self.solid, edge.valueAt(param)) + return self.nextIntersectionClosestTo( + edge, self.solid, edge.valueAt(param) + ) return None def bbEdges(self): @@ -240,7 +295,7 @@ class Tag: class MapWireToTag: def __init__(self, edge, tag, i, segm, maxZ, hSpeed, vSpeed): - debugEdge(edge, 'MapWireToTag(%.2f, %.2f, %.2f)' % (i.x, i.y, i.z)) + debugEdge(edge, "MapWireToTag(%.2f, %.2f, %.2f)" % (i.x, i.y, i.z)) self.tag = tag self.segm = segm self.maxZ = maxZ @@ -249,22 +304,28 @@ class MapWireToTag: if PathGeom.pointsCoincide(edge.valueAt(edge.FirstParameter), i): tail = edge self.commands = [] - debugEdge(tail, '.........=') + debugEdge(tail, ".........=") elif PathGeom.pointsCoincide(edge.valueAt(edge.LastParameter), i): - debugEdge(edge, '++++++++ .') - self.commands = PathGeom.cmdsForEdge(edge, segm=segm, hSpeed = self.hSpeed, vSpeed = self.vSpeed) + debugEdge(edge, "++++++++ .") + self.commands = PathGeom.cmdsForEdge( + edge, segm=segm, hSpeed=self.hSpeed, vSpeed=self.vSpeed + ) tail = None else: e, tail = PathGeom.splitEdgeAt(edge, i) - debugEdge(e, '++++++++ .') - self.commands = PathGeom.cmdsForEdge(e, segm=segm, hSpeed = self.hSpeed, vSpeed = self.vSpeed) - debugEdge(tail, '.........-') + debugEdge(e, "++++++++ .") + self.commands = PathGeom.cmdsForEdge( + e, segm=segm, hSpeed=self.hSpeed, vSpeed=self.vSpeed + ) + debugEdge(tail, ".........-") self.initialEdge = edge self.tail = tail self.edges = [] self.entry = i if tail: - PathLog.debug("MapWireToTag(%s - %s)" % (i, tail.valueAt(tail.FirstParameter))) + PathLog.debug( + "MapWireToTag(%s - %s)" % (i, tail.valueAt(tail.FirstParameter)) + ) else: PathLog.debug("MapWireToTag(%s - )" % i) self.complete = False @@ -283,7 +344,7 @@ class MapWireToTag: self.realExit = None def addEdge(self, edge): - debugEdge(edge, '..........') + debugEdge(edge, "..........") self.edges.append(edge) def needToFlipEdge(self, edge, p): @@ -311,7 +372,7 @@ class MapWireToTag: if not edges: return edges for e in edges: - debugEdge(e, ' ') + debugEdge(e, " ") PathLog.debug(":") self.edgesCleanup = [copy.copy(edges)] @@ -325,13 +386,19 @@ class MapWireToTag: p2 = e.valueAt(e.LastParameter) self.edgePoints.append(p1) self.edgePoints.append(p2) - if self.tag.solid.isInside(p1, PathGeom.Tolerance, False) or self.tag.solid.isInside(p2, PathGeom.Tolerance, False): + if self.tag.solid.isInside( + p1, PathGeom.Tolerance, False + ) or self.tag.solid.isInside(p2, PathGeom.Tolerance, False): edges.remove(e) - debugEdge(e, '......... X0', False) + debugEdge(e, "......... X0", False) else: - if PathGeom.pointsCoincide(p1, self.entry) or PathGeom.pointsCoincide(p2, self.entry): + if PathGeom.pointsCoincide(p1, self.entry) or PathGeom.pointsCoincide( + p2, self.entry + ): self.entryEdges.append(e) - if PathGeom.pointsCoincide(p1, self.exit) or PathGeom.pointsCoincide(p2, self.exit): + if PathGeom.pointsCoincide(p1, self.exit) or PathGeom.pointsCoincide( + p2, self.exit + ): self.exitEdges.append(e) self.edgesCleanup.append(copy.copy(edges)) @@ -339,15 +406,23 @@ class MapWireToTag: # we need to add in the missing segment and collect the new entry/exit edges. if not self.entryEdges: PathLog.debug("fill entryEdges ...") - self.realEntry = sorted(self.edgePoints, key=lambda p: (p - self.entry).Length)[0] - self.entryEdges = list([e for e in edges if PathGeom.edgeConnectsTo(e, self.realEntry)]) + self.realEntry = sorted( + self.edgePoints, key=lambda p: (p - self.entry).Length + )[0] + self.entryEdges = list( + [e for e in edges if PathGeom.edgeConnectsTo(e, self.realEntry)] + ) edges.append(Part.Edge(Part.LineSegment(self.entry, self.realEntry))) else: self.realEntry = None if not self.exitEdges: PathLog.debug("fill exitEdges ...") - self.realExit = sorted(self.edgePoints, key=lambda p: (p - self.exit).Length)[0] - self.exitEdges = list([e for e in edges if PathGeom.edgeConnectsTo(e, self.realExit)]) + self.realExit = sorted( + self.edgePoints, key=lambda p: (p - self.exit).Length + )[0] + self.exitEdges = list( + [e for e in edges if PathGeom.edgeConnectsTo(e, self.realExit)] + ) edges.append(Part.Edge(Part.LineSegment(self.realExit, self.exit))) else: self.realExit = None @@ -355,31 +430,41 @@ class MapWireToTag: # if there are 2 edges attached to entry/exit, throw away the one that is "lower" if len(self.entryEdges) > 1: - debugEdge(self.entryEdges[0], ' entry[0]', False) - debugEdge(self.entryEdges[1], ' entry[1]', False) + debugEdge(self.entryEdges[0], " entry[0]", False) + debugEdge(self.entryEdges[1], " entry[1]", False) if self.entryEdges[0].BoundBox.ZMax < self.entryEdges[1].BoundBox.ZMax: edges.remove(self.entryEdges[0]) - debugEdge(e, '......... X1', False) + debugEdge(e, "......... X1", False) else: edges.remove(self.entryEdges[1]) - debugEdge(e, '......... X2', False) + debugEdge(e, "......... X2", False) if len(self.exitEdges) > 1: - debugEdge(self.exitEdges[0], ' exit[0]', False) - debugEdge(self.exitEdges[1], ' exit[1]', False) + debugEdge(self.exitEdges[0], " exit[0]", False) + debugEdge(self.exitEdges[1], " exit[1]", False) if self.exitEdges[0].BoundBox.ZMax < self.exitEdges[1].BoundBox.ZMax: if self.exitEdges[0] in edges: edges.remove(self.exitEdges[0]) - debugEdge(e, '......... X3', False) + debugEdge(e, "......... X3", False) else: if self.exitEdges[1] in edges: edges.remove(self.exitEdges[1]) - debugEdge(e, '......... X4', False) + debugEdge(e, "......... X4", False) self.edgesCleanup.append(copy.copy(edges)) return edges def orderAndFlipEdges(self, inputEdges): - PathLog.track("entry(%.2f, %.2f, %.2f), exit(%.2f, %.2f, %.2f)" % (self.entry.x, self.entry.y, self.entry.z, self.exit.x, self.exit.y, self.exit.z)) + PathLog.track( + "entry(%.2f, %.2f, %.2f), exit(%.2f, %.2f, %.2f)" + % ( + self.entry.x, + self.entry.y, + self.entry.z, + self.exit.x, + self.exit.y, + self.exit.z, + ) + ) self.edgesOrder = [] outputEdges = [] p0 = self.entry @@ -406,7 +491,9 @@ class MapWireToTag: cnt = 0 for p in reversed(e.discretize(Deflection=0.01)): if not p0 is None: - outputEdges.append((Part.Edge(Part.LineSegment(p0, p)), True)) + outputEdges.append( + (Part.Edge(Part.LineSegment(p0, p)), True) + ) cnt = cnt + 1 p0 = p PathLog.info("replaced edge with %d straight segments" % cnt) @@ -421,18 +508,21 @@ class MapWireToTag: if lastP == p0: self.edgesOrder.append(outputEdges) self.edgesOrder.append(edges) - PathLog.debug('input edges:') + PathLog.debug("input edges:") for e in inputEdges: - debugEdge(e, ' ', False) - PathLog.debug('ordered edges:') + debugEdge(e, " ", False) + PathLog.debug("ordered edges:") for e, flip in outputEdges: - debugEdge(e, ' %c ' % ('<' if flip else '>'), False) - PathLog.debug('remaining edges:') + debugEdge(e, " %c " % ("<" if flip else ">"), False) + PathLog.debug("remaining edges:") for e in edges: - debugEdge(e, ' ', False) + debugEdge(e, " ", False) raise ValueError("No connection to %s" % (p0)) elif lastP: - PathLog.debug("xxxxxx (%.2f, %.2f, %.2f) (%.2f, %.2f, %.2f)" % (p0.x, p0.y, p0.z, lastP.x, lastP.y, lastP.z)) + PathLog.debug( + "xxxxxx (%.2f, %.2f, %.2f) (%.2f, %.2f, %.2f)" + % (p0.x, p0.y, p0.z, lastP.x, lastP.y, lastP.z) + ) else: PathLog.debug("xxxxxx (%.2f, %.2f, %.2f) -" % (p0.x, p0.y, p0.z)) lastP = p0 @@ -449,15 +539,24 @@ class MapWireToTag: wire = Part.Wire(self.initialEdge) else: edge = self.edges[0] - if PathGeom.pointsCoincide(edge.valueAt(edge.FirstParameter), self.finalEdge.valueAt(self.finalEdge.FirstParameter)): + if PathGeom.pointsCoincide( + edge.valueAt(edge.FirstParameter), + self.finalEdge.valueAt(self.finalEdge.FirstParameter), + ): wire = Part.Wire(self.finalEdge) - elif hasattr(self, 'initialEdge') and PathGeom.pointsCoincide(edge.valueAt(edge.FirstParameter), self.initialEdge.valueAt(self.initialEdge.FirstParameter)): + elif hasattr(self, "initialEdge") and PathGeom.pointsCoincide( + edge.valueAt(edge.FirstParameter), + self.initialEdge.valueAt(self.initialEdge.FirstParameter), + ): wire = Part.Wire(self.initialEdge) else: wire = Part.Wire(edge) for edge in self.edges[1:]: - if PathGeom.pointsCoincide(edge.valueAt(edge.FirstParameter), self.finalEdge.valueAt(self.finalEdge.FirstParameter)): + if PathGeom.pointsCoincide( + edge.valueAt(edge.FirstParameter), + self.finalEdge.valueAt(self.finalEdge.FirstParameter), + ): wire.add(self.finalEdge) else: wire.add(edge) @@ -469,37 +568,61 @@ class MapWireToTag: return shell def commandsForEdges(self): - global failures # pylint: disable=global-statement + global failures # pylint: disable=global-statement if self.edges: try: shape = self.shell().common(self.tag.solid) commands = [] rapid = None for e, flip in self.orderAndFlipEdges(self.cleanupEdges(shape.Edges)): - debugEdge(e, '++++++++ %s' % ('<' if flip else '>'), False) + debugEdge(e, "++++++++ %s" % ("<" if flip else ">"), False) p1 = e.valueAt(e.FirstParameter) p2 = e.valueAt(e.LastParameter) - if self.tag.isSquare and (PathGeom.isRoughly(p1.z, self.maxZ) or p1.z > self.maxZ) and (PathGeom.isRoughly(p2.z, self.maxZ) or p2.z > self.maxZ): + if ( + self.tag.isSquare + and (PathGeom.isRoughly(p1.z, self.maxZ) or p1.z > self.maxZ) + and (PathGeom.isRoughly(p2.z, self.maxZ) or p2.z > self.maxZ) + ): rapid = p1 if flip else p2 else: if rapid: - commands.append(Path.Command('G0', {'X': rapid.x, 'Y': rapid.y, 'Z': rapid.z})) + commands.append( + Path.Command( + "G0", {"X": rapid.x, "Y": rapid.y, "Z": rapid.z} + ) + ) rapid = None - commands.extend(PathGeom.cmdsForEdge(e, False, False, self.segm, hSpeed = self.hSpeed, vSpeed = self.vSpeed)) + commands.extend( + PathGeom.cmdsForEdge( + e, + False, + False, + self.segm, + hSpeed=self.hSpeed, + vSpeed=self.vSpeed, + ) + ) if rapid: - commands.append(Path.Command('G0', {'X': rapid.x, 'Y': rapid.y, 'Z': rapid.z})) + commands.append( + Path.Command("G0", {"X": rapid.x, "Y": rapid.y, "Z": rapid.z}) + ) # rapid = None # commented out per LGTM suggestion return commands - except Exception as e: # pylint: disable=broad-except - PathLog.error("Exception during processing tag @(%.2f, %.2f) (%s) - disabling the tag" % (self.tag.x, self.tag.y, e.args[0])) - #if sys.version_info.major < 3: + except Exception as e: # pylint: disable=broad-except + PathLog.error( + "Exception during processing tag @(%.2f, %.2f) (%s) - disabling the tag" + % (self.tag.x, self.tag.y, e.args[0]) + ) + # if sys.version_info.major < 3: # traceback.print_exc(e) - #else: + # else: # traceback.print_exc() self.tag.enabled = False commands = [] for e in self.edges: - commands.extend(PathGeom.cmdsForEdge(e, hSpeed = self.hSpeed, vSpeed = self.vSpeed)) + commands.extend( + PathGeom.cmdsForEdge(e, hSpeed=self.hSpeed, vSpeed=self.vSpeed) + ) failures.append(self) return commands return [] @@ -507,22 +630,24 @@ class MapWireToTag: def add(self, edge): self.tail = None self.finalEdge = edge - if self.tag.solid.isInside(edge.valueAt(edge.LastParameter), PathGeom.Tolerance, True): - PathLog.track('solid.isInside') + if self.tag.solid.isInside( + edge.valueAt(edge.LastParameter), PathGeom.Tolerance, True + ): + PathLog.track("solid.isInside") self.addEdge(edge) else: i = self.tag.intersects(edge, edge.LastParameter) if not i: self.offendingEdge = edge - debugEdge(edge, 'offending Edge:', False) + debugEdge(edge, "offending Edge:", False) o = self.tag.originAt(self.tag.z) - PathLog.debug('originAt: (%.2f, %.2f, %.2f)' % (o.x, o.y, o.z)) + PathLog.debug("originAt: (%.2f, %.2f, %.2f)" % (o.x, o.y, o.z)) i = edge.valueAt(edge.FirstParameter) if PathGeom.pointsCoincide(i, edge.valueAt(edge.FirstParameter)): - PathLog.track('tail') + PathLog.track("tail") self.tail = edge else: - PathLog.track('split') + PathLog.track("split") e, tail = PathGeom.splitEdgeAt(edge, i) self.addEdge(e) self.tail = tail @@ -545,7 +670,14 @@ class _RapidEdges: for r in self.rapid: r0 = r.Vertexes[0] r1 = r.Vertexes[1] - if PathGeom.isRoughly(r0.X, v0.X) and PathGeom.isRoughly(r0.Y, v0.Y) and PathGeom.isRoughly(r0.Z, v0.Z) and PathGeom.isRoughly(r1.X, v1.X) and PathGeom.isRoughly(r1.Y, v1.Y) and PathGeom.isRoughly(r1.Z, v1.Z): + if ( + PathGeom.isRoughly(r0.X, v0.X) + and PathGeom.isRoughly(r0.Y, v0.Y) + and PathGeom.isRoughly(r0.Z, v0.Z) + and PathGeom.isRoughly(r1.X, v1.X) + and PathGeom.isRoughly(r1.Y, v1.Y) + and PathGeom.isRoughly(r1.Z, v1.Z) + ): return True return False @@ -566,16 +698,21 @@ class PathData: (minZ, maxZ) = self.findZLimits(edges) self.minZ = minZ self.maxZ = maxZ - bottom = [e for e in edges if PathGeom.isRoughly(e.Vertexes[0].Point.z, minZ) and PathGeom.isRoughly(e.Vertexes[1].Point.z, minZ)] + bottom = [ + e + for e in edges + if PathGeom.isRoughly(e.Vertexes[0].Point.z, minZ) + and PathGeom.isRoughly(e.Vertexes[1].Point.z, minZ) + ] self.bottomEdges = bottom try: wire = Part.Wire(bottom) if wire.isClosed(): return wire - except Exception: # pylint: disable=broad-except - #if sys.version_info.major < 3: + except Exception: # pylint: disable=broad-except + # if sys.version_info.major < 3: # traceback.print_exc(e) - #else: + # else: # traceback.print_exc() return None @@ -600,7 +737,9 @@ class PathData: edges = sorted(self.bottomEdges, key=lambda e: e.Length) return (edges[0], edges[-1]) - def generateTags(self, obj, count, width=None, height=None, angle=None, radius=None, spacing=None): + def generateTags( + self, obj, count, width=None, height=None, angle=None, radius=None, spacing=None + ): # pylint: disable=unused-argument PathLog.track(count, width, height, angle, spacing) # for e in self.baseWire.Edges: @@ -611,9 +750,9 @@ class PathData: else: tagDistance = self.baseWire.Length / (count if count else 4) - W = width if width else self.defaultTagWidth() + W = width if width else self.defaultTagWidth() H = height if height else self.defaultTagHeight() - A = angle if angle else self.defaultTagAngle() + A = angle if angle else self.defaultTagAngle() R = radius if radius else self.defaultTagRadius() # start assigning tags on the longest segment @@ -621,7 +760,7 @@ class PathData: startIndex = 0 for i in range(0, len(self.baseWire.Edges)): edge = self.baseWire.Edges[i] - PathLog.debug(' %d: %.2f' % (i, edge.Length)) + PathLog.debug(" %d: %.2f" % (i, edge.Length)) if PathGeom.isRoughly(edge.Length, longestEdge.Length): startIndex = i break @@ -634,10 +773,23 @@ class PathData: lastTagLength = (startEdge.Length + (startCount - 1) * tagDistance) / 2 currentLength = startEdge.Length - minLength = min(2. * W, longestEdge.Length) + minLength = min(2.0 * W, longestEdge.Length) - PathLog.debug("length=%.2f shortestEdge=%.2f(%.2f) longestEdge=%.2f(%.2f) minLength=%.2f" % (self.baseWire.Length, shortestEdge.Length, shortestEdge.Length/self.baseWire.Length, longestEdge.Length, longestEdge.Length / self.baseWire.Length, minLength)) - PathLog.debug(" start: index=%-2d count=%d (length=%.2f, distance=%.2f)" % (startIndex, startCount, startEdge.Length, tagDistance)) + PathLog.debug( + "length=%.2f shortestEdge=%.2f(%.2f) longestEdge=%.2f(%.2f) minLength=%.2f" + % ( + self.baseWire.Length, + shortestEdge.Length, + shortestEdge.Length / self.baseWire.Length, + longestEdge.Length, + longestEdge.Length / self.baseWire.Length, + minLength, + ) + ) + PathLog.debug( + " start: index=%-2d count=%d (length=%.2f, distance=%.2f)" + % (startIndex, startCount, startEdge.Length, tagDistance) + ) PathLog.debug(" -> lastTagLength=%.2f)" % lastTagLength) PathLog.debug(" -> currentLength=%.2f)" % currentLength) @@ -645,10 +797,14 @@ class PathData: for i in range(startIndex + 1, len(self.baseWire.Edges)): edge = self.baseWire.Edges[i] - (currentLength, lastTagLength) = self.processEdge(i, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict) + (currentLength, lastTagLength) = self.processEdge( + i, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict + ) for i in range(0, startIndex): edge = self.baseWire.Edges[i] - (currentLength, lastTagLength) = self.processEdge(i, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict) + (currentLength, lastTagLength) = self.processEdge( + i, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict + ) tags = [] @@ -660,16 +816,19 @@ class PathData: if 0 != count: distance = (edge.LastParameter - edge.FirstParameter) / count for j in range(0, count): - tag = edge.Curve.value((j+0.5) * distance) + tag = edge.Curve.value((j + 0.5) * distance) tags.append(Tag(j, tag.x, tag.y, W, H, A, R, True)) return tags def copyTags(self, obj, fromObj, width, height, angle, radius, production=True): - print("copyTags(%s, %s, %.2f, %.2f, %.2f, %.2f" % (obj.Label, fromObj.Label, width, height, angle, radius)) - W = width if width else self.defaultTagWidth() + print( + "copyTags(%s, %s, %.2f, %.2f, %.2f, %.2f" + % (obj.Label, fromObj.Label, width, height, angle, radius) + ) + W = width if width else self.defaultTagWidth() H = height if height else self.defaultTagHeight() - A = angle if angle else self.defaultTagAngle() + A = angle if angle else self.defaultTagAngle() R = radius if radius else self.defaultTagRadius() tags = [] @@ -677,22 +836,39 @@ class PathData: for i, pos in enumerate(fromObj.Positions): print("tag[%d]" % i) if not i in fromObj.Disabled: - dist = self.baseWire.distToShape(Part.Vertex(FreeCAD.Vector(pos.x, pos.y, self.minZ))) + dist = self.baseWire.distToShape( + Part.Vertex(FreeCAD.Vector(pos.x, pos.y, self.minZ)) + ) if production or dist[0] < W: # russ4262:: `production` variable was a `True` declaration, forcing True branch to be processed always # The application of the `production` argument/variable is to appease LGTM - print("tag[%d/%d]: (%.2f, %.2f, %.2f)" % (i, j, pos.x, pos.y, self.minZ)) + print( + "tag[%d/%d]: (%.2f, %.2f, %.2f)" + % (i, j, pos.x, pos.y, self.minZ) + ) at = dist[1][0][0] - tags.append(Tag(j, at.x, at.y, W, H, A, R, True)) + tags.append(Tag(j, at.x, at.y, W, H, A, R, True)) j += 1 else: - PathLog.warning("Tag[%d] (%.2f, %.2f, %.2f) is too far away to copy: %.2f (%.2f)" % (i, pos.x, pos.y, self.minZ, dist[0], W)) + PathLog.warning( + "Tag[%d] (%.2f, %.2f, %.2f) is too far away to copy: %.2f (%.2f)" + % (i, pos.x, pos.y, self.minZ, dist[0], W) + ) else: PathLog.info("tag[%d]: not enabled, skipping" % i) print("copied %d tags" % len(tags)) return tags - def processEdge(self, index, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict): + def processEdge( + self, + index, + edge, + currentLength, + lastTagLength, + tagDistance, + minLength, + edgeDict, + ): tagCount = 0 currentLength += edge.Length if edge.Length >= minLength: @@ -708,7 +884,11 @@ 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'): + 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 else: pathHeight = self.maxZ - self.minZ @@ -730,13 +910,27 @@ class PathData: def sortedTags(self, tags): ordered = [] for edge in self.bottomEdges: - ts = [t for t in tags if PathGeom.isRoughly(0, Part.Vertex(t.originAt(self.minZ)).distToShape(edge)[0], 0.1)] - for t in sorted(ts, key=lambda t, edge=edge: (t.originAt(self.minZ) - edge.valueAt(edge.FirstParameter)).Length): + ts = [ + t + for t in tags + if PathGeom.isRoughly( + 0, Part.Vertex(t.originAt(self.minZ)).distToShape(edge)[0], 0.1 + ) + ] + for t in sorted( + ts, + key=lambda t, edge=edge: ( + t.originAt(self.minZ) - edge.valueAt(edge.FirstParameter) + ).Length, + ): tags.remove(t) ordered.append(t) # disable all tags that are not on the base wire. for tag in tags: - PathLog.info("Tag #%d (%.2f, %.2f, %.2f) not on base wire - disabling\n" % (len(ordered), tag.x, tag.y, self.minZ)) + PathLog.info( + "Tag #%d (%.2f, %.2f, %.2f) not on base wire - disabling\n" + % (len(ordered), tag.x, tag.y, self.minZ) + ) tag.enabled = False ordered.append(tag) return ordered @@ -756,17 +950,65 @@ class PathData: class ObjectTagDressup: - def __init__(self, obj, base): - obj.addProperty("App::PropertyLink", "Base", "Base", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "The base path to modify")) - obj.addProperty("App::PropertyLength", "Width", "Tag", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Width of tags.")) - obj.addProperty("App::PropertyLength", "Height", "Tag", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Height of tags.")) - obj.addProperty("App::PropertyAngle", "Angle", "Tag", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Angle of tag plunge and ascent.")) - obj.addProperty("App::PropertyLength", "Radius", "Tag", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Radius of the fillet for the tag.")) - obj.addProperty("App::PropertyVectorList", "Positions", "Tag", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Locations of inserted holding tags")) - obj.addProperty("App::PropertyIntegerList", "Disabled", "Tag", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "IDs of disabled holding tags")) - obj.addProperty("App::PropertyInteger", "SegmentationFactor", "Tag", QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Factor determining the # of segments used to approximate rounded tags.")) + obj.addProperty( + "App::PropertyLink", + "Base", + "Base", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "The base path to modify"), + ) + obj.addProperty( + "App::PropertyLength", + "Width", + "Tag", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Width of tags."), + ) + obj.addProperty( + "App::PropertyLength", + "Height", + "Tag", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Height of tags."), + ) + obj.addProperty( + "App::PropertyAngle", + "Angle", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", "Angle of tag plunge and ascent." + ), + ) + obj.addProperty( + "App::PropertyLength", + "Radius", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", "Radius of the fillet for the tag." + ), + ) + obj.addProperty( + "App::PropertyVectorList", + "Positions", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", "Locations of inserted holding tags" + ), + ) + obj.addProperty( + "App::PropertyIntegerList", + "Disabled", + "Tag", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "IDs of disabled holding tags"), + ) + obj.addProperty( + "App::PropertyInteger", + "SegmentationFactor", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", + "Factor determining the # of segments used to approximate rounded tags.", + ), + ) # for pylint ... self.obj = obj @@ -802,7 +1044,15 @@ class ObjectTagDressup: def generateTags(self, obj, count): if self.supportsTagGeneration(obj): if self.pathData: - self.tags = self.pathData.generateTags(obj, count, obj.Width.Value, obj.Height.Value, obj.Angle, obj.Radius.Value, None) + self.tags = self.pathData.generateTags( + obj, + count, + obj.Width.Value, + obj.Height.Value, + obj.Angle, + obj.Radius.Value, + None, + ) obj.Positions = [tag.originAt(self.pathData.minZ) for tag in self.tags] obj.Disabled = [] return False @@ -817,13 +1067,15 @@ class ObjectTagDressup: return False def copyTags(self, obj, fromObj): - obj.Width = fromObj.Width + obj.Width = fromObj.Width obj.Height = fromObj.Height - obj.Angle = fromObj.Angle + obj.Angle = fromObj.Angle obj.Radius = fromObj.Radius obj.SegmentationFactor = fromObj.SegmentationFactor - self.tags = self.pathData.copyTags(obj, fromObj, obj.Width.Value, obj.Height.Value, obj.Angle, obj.Radius.Value) + self.tags = self.pathData.copyTags( + obj, fromObj, obj.Width.Value, obj.Height.Value, obj.Angle, obj.Radius.Value + ) obj.Positions = [tag.originAt(self.pathData.minZ) for tag in self.tags] obj.Disabled = [] return False @@ -850,7 +1102,7 @@ class ObjectTagDressup: edge = None segm = 50 - if hasattr(obj, 'SegmentationFactor'): + if hasattr(obj, "SegmentationFactor"): segm = obj.SegmentationFactor if segm <= 0: segm = 50 @@ -866,10 +1118,14 @@ class ObjectTagDressup: vertRapid = tc.VertRapid.Value while edge or lastEdge < len(pathData.edges): - PathLog.debug("------- lastEdge = %d/%d.%d/%d" % (lastEdge, lastTag, t, len(tags))) + PathLog.debug( + "------- lastEdge = %d/%d.%d/%d" % (lastEdge, lastTag, t, len(tags)) + ) if not edge: edge = pathData.edges[lastEdge] - debugEdge(edge, "======= new edge: %d/%d" % (lastEdge, len(pathData.edges))) + debugEdge( + edge, "======= new edge: %d/%d" % (lastEdge, len(pathData.edges)) + ) lastEdge += 1 # sameTag = None @@ -887,23 +1143,46 @@ class ObjectTagDressup: t += 1 i = tags[tIndex].intersects(edge, edge.FirstParameter) if i and self.isValidTagStartIntersection(edge, i): - mapper = MapWireToTag(edge, tags[tIndex], i, segm, pathData.maxZ, hSpeed = horizFeed, vSpeed = vertFeed) + mapper = MapWireToTag( + edge, + tags[tIndex], + i, + segm, + pathData.maxZ, + hSpeed=horizFeed, + vSpeed=vertFeed, + ) self.mappers.append(mapper) edge = mapper.tail if not mapper and t >= len(tags): # gone through all tags, consume edge and move on if edge: - debugEdge(edge, '++++++++') + debugEdge(edge, "++++++++") if pathData.rapid.isRapid(edge): v = edge.Vertexes[1] - if not commands and PathGeom.isRoughly(0, v.X) and PathGeom.isRoughly(0, v.Y) and not PathGeom.isRoughly(0, v.Z): + if ( + not commands + and PathGeom.isRoughly(0, v.X) + and PathGeom.isRoughly(0, v.Y) + and not PathGeom.isRoughly(0, v.Z) + ): # The very first move is just to move to ClearanceHeight - commands.append(Path.Command('G0', {'Z': v.Z, 'F': horizRapid})) + commands.append( + Path.Command("G0", {"Z": v.Z, "F": horizRapid}) + ) else: - commands.append(Path.Command('G0', {'X': v.X, 'Y': v.Y, 'Z': v.Z, 'F': vertRapid})) + commands.append( + Path.Command( + "G0", {"X": v.X, "Y": v.Y, "Z": v.Z, "F": vertRapid} + ) + ) else: - commands.extend(PathGeom.cmdsForEdge(edge, segm=segm, hSpeed = horizFeed, vSpeed = vertFeed)) + commands.extend( + PathGeom.cmdsForEdge( + edge, segm=segm, hSpeed=horizFeed, vSpeed=vertFeed + ) + ) edge = None t = 0 @@ -915,7 +1194,16 @@ class ObjectTagDressup: def createTagsPositionDisabled(self, obj, positionsIn, disabledIn): rawTags = [] for i, pos in enumerate(positionsIn): - tag = Tag(i, pos.x, pos.y, obj.Width.Value, obj.Height.Value, obj.Angle, obj.Radius, not i in disabledIn) + tag = Tag( + i, + pos.x, + pos.y, + obj.Width.Value, + obj.Height.Value, + obj.Angle, + obj.Radius, + not i in disabledIn, + ) tag.createSolidsAt(self.pathData.minZ, self.toolRadius) rawTags.append(tag) # disable all tags that intersect with their previous tag @@ -927,15 +1215,21 @@ class ObjectTagDressup: if tag.enabled: if prev: if prev.solid.common(tag.solid).Faces: - PathLog.info("Tag #%d intersects with previous tag - disabling\n" % i) + PathLog.info( + "Tag #%d intersects with previous tag - disabling\n" % i + ) PathLog.debug("this tag = %d [%s]" % (i, tag.solid.BoundBox)) tag.enabled = False elif self.pathData.edges: e = self.pathData.edges[0] p0 = e.valueAt(e.FirstParameter) p1 = e.valueAt(e.LastParameter) - if tag.solid.isInside(p0, PathGeom.Tolerance, True) or tag.solid.isInside(p1, PathGeom.Tolerance, True): - PathLog.info("Tag #%d intersects with starting point - disabling\n" % i) + if tag.solid.isInside( + p0, PathGeom.Tolerance, True + ) or tag.solid.isInside(p1, PathGeom.Tolerance, True): + PathLog.info( + "Tag #%d intersects with starting point - disabling\n" % i + ) tag.enabled = False if tag.enabled: @@ -973,9 +1267,13 @@ class ObjectTagDressup: self.tags = [] if hasattr(obj, "Positions"): - self.tags, positions, disabled = self.createTagsPositionDisabled(obj, obj.Positions, obj.Disabled) + self.tags, positions, disabled = self.createTagsPositionDisabled( + obj, obj.Positions, obj.Disabled + ) if obj.Disabled != disabled: - PathLog.debug("Updating properties.... %s vs. %s" % (obj.Disabled, disabled)) + PathLog.debug( + "Updating properties.... %s vs. %s" % (obj.Disabled, disabled) + ) obj.Positions = positions obj.Disabled = disabled @@ -986,11 +1284,13 @@ class ObjectTagDressup: try: self.processTags(obj) - except Exception as e: # pylint: disable=broad-except - PathLog.error("processing tags failed clearing all tags ... '%s'" % (e.args[0])) - #if sys.version_info.major < 3: + except Exception as e: # pylint: disable=broad-except + PathLog.error( + "processing tags failed clearing all tags ... '%s'" % (e.args[0]) + ) + # if sys.version_info.major < 3: # traceback.print_exc(e) - #else: + # else: # traceback.print_exc() obj.Path = obj.Base.Path @@ -1007,14 +1307,16 @@ class ObjectTagDressup: @waiting_effects def processTags(self, obj): - global failures # pylint: disable=global-statement + global failures # pylint: disable=global-statement failures = [] tagID = 0 if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG: for tag in self.tags: tagID += 1 if tag.enabled: - PathLog.debug("x=%s, y=%s, z=%s" % (tag.x, tag.y, self.pathData.minZ)) + PathLog.debug( + "x=%s, y=%s, z=%s" % (tag.x, tag.y, self.pathData.minZ) + ) # debugMarker(FreeCAD.Vector(tag.x, tag.y, self.pathData.minZ), "tag-%02d" % tagID , (1.0, 0.0, 1.0), 0.5) # if not PathGeom.isRoughly(90, tag.angle): # debugCone(tag.originAt(self.pathData.minZ), tag.r1, tag.r2, tag.actualHeight, "tag-%02d" % tagID) @@ -1029,10 +1331,16 @@ class ObjectTagDressup: try: pathData = PathData(obj) except ValueError: - PathLog.error(translate("Path_DressupTag", "Cannot insert holding tags for this path - please select a Profile path")+"\n") - #if sys.version_info.major < 3: + PathLog.error( + translate( + "Path_DressupTag", + "Cannot insert holding tags for this path - please select a Profile path", + ) + + "\n" + ) + # if sys.version_info.major < 3: # traceback.print_exc(e) - #else: + # else: # traceback.print_exc() return None @@ -1058,7 +1366,11 @@ class ObjectTagDressup: positions.append(FreeCAD.Vector(x, y, 0)) if not enabled: disabled.append(i) - self.tags, self.obj.Positions, self.obj.Disabled = self.createTagsPositionDisabled(self.obj, positions, disabled) + ( + self.tags, + self.obj.Positions, + self.obj.Disabled, + ) = self.createTagsPositionDisabled(self.obj, positions, disabled) self.processTags(self.obj) def pointIsOnPath(self, obj, point): @@ -1072,16 +1384,18 @@ class ObjectTagDressup: return self.pathData.pointAtBottom(point) -def Create(baseObject, name='DressupTag'): - ''' +def Create(baseObject, name="DressupTag"): + """ Create(basePath, name='DressupTag') ... create tag dressup object for the given base path. - ''' - if not baseObject.isDerivedFrom('Path::Feature'): - PathLog.error(translate('Path_DressupTag', 'The selected object is not a path')+'\n') + """ + if not baseObject.isDerivedFrom("Path::Feature"): + PathLog.error( + translate("Path_DressupTag", "The selected object is not a path") + "\n" + ) return None - if baseObject.isDerivedFrom('Path::FeatureCompoundPython'): - PathLog.error(translate('Path_DressupTag', 'Please select a Profile object')) + if baseObject.isDerivedFrom("Path::FeatureCompoundPython"): + PathLog.error(translate("Path_DressupTag", "Please select a Profile object")) return None obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) @@ -1091,4 +1405,5 @@ def Create(baseObject, name='DressupTag'): dbo.setup(obj, True) return obj + PathLog.notice("Loading Path_DressupTag... done\n") diff --git a/src/Mod/Path/PathScripts/PathDressupPathBoundary.py b/src/Mod/Path/PathScripts/PathDressupPathBoundary.py index 68eda29544..6a2c737924 100644 --- a/src/Mod/Path/PathScripts/PathDressupPathBoundary.py +++ b/src/Mod/Path/PathScripts/PathDressupPathBoundary.py @@ -43,17 +43,39 @@ def translate(context, text, disambig=None): def _vstr(v): if v: return "(%.2f, %.2f, %.2f)" % (v.x, v.y, v.z) - return '-' + return "-" class DressupPathBoundary(object): - def __init__(self, obj, base, job): - obj.addProperty("App::PropertyLink", "Base", "Base", QtCore.QT_TRANSLATE_NOOP("Path_DressupPathBoundary", "The base path to modify")) + obj.addProperty( + "App::PropertyLink", + "Base", + "Base", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupPathBoundary", "The base path to modify" + ), + ) obj.Base = base - obj.addProperty("App::PropertyLink", "Stock", "Boundary", QtCore.QT_TRANSLATE_NOOP("Path_DressupPathBoundary", "Solid object to be used to limit the generated Path.")) + obj.addProperty( + "App::PropertyLink", + "Stock", + "Boundary", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupPathBoundary", + "Solid object to be used to limit the generated Path.", + ), + ) obj.Stock = PathStock.CreateFromBase(job) - obj.addProperty("App::PropertyBool", "Inside", "Boundary", QtCore.QT_TRANSLATE_NOOP("Path_DressupPathBoundary", "Determines if Boundary describes an inclusion or exclusion mask.")) + obj.addProperty( + "App::PropertyBool", + "Inside", + "Boundary", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupPathBoundary", + "Determines if Boundary describes an inclusion or exclusion mask.", + ), + ) obj.Inside = True self.obj = obj @@ -85,6 +107,8 @@ class DressupPathBoundary(object): def execute(self, obj): pb = PathBoundary(obj.Base, obj.Stock.Shape, obj.Inside) obj.Path = pb.execute() + + # Eclass @@ -114,15 +138,19 @@ class PathBoundary: if begin.z < self.clearanceHeight: cmds.append(self.strG0ZclearanceHeight) if end: - cmds.append(Path.Command('G0', {'X': end.x, 'Y': end.y})) + cmds.append(Path.Command("G0", {"X": end.x, "Y": end.y})) if end.z < self.clearanceHeight: - cmds.append(Path.Command('G0', {'Z': max(self.safeHeight, end.z)})) + cmds.append(Path.Command("G0", {"Z": max(self.safeHeight, end.z)})) if end.z < self.safeHeight: - cmds.append(Path.Command('G1', {'Z': end.z, 'F': verticalFeed})) + cmds.append(Path.Command("G1", {"Z": end.z, "F": verticalFeed})) return cmds def execute(self): - if not self.baseOp or not self.baseOp.isDerivedFrom('Path::Feature') or not self.baseOp.Path: + if ( + not self.baseOp + or not self.baseOp.isDerivedFrom("Path::Feature") + or not self.baseOp.Path + ): return None if len(self.baseOp.Path.Commands) == 0: @@ -131,23 +159,27 @@ class PathBoundary: tc = PathDressup.toolController(self.baseOp) - self.safeHeight = float(PathUtil.opProperty(self.baseOp, 'SafeHeight')) - self.clearanceHeight = float(PathUtil.opProperty(self.baseOp, 'ClearanceHeight')) - self.strG1ZsafeHeight = Path.Command('G1', {'Z': self.safeHeight, 'F': tc.VertFeed.Value}) - self.strG0ZclearanceHeight = Path.Command('G0', {'Z': self.clearanceHeight}) + self.safeHeight = float(PathUtil.opProperty(self.baseOp, "SafeHeight")) + self.clearanceHeight = float( + PathUtil.opProperty(self.baseOp, "ClearanceHeight") + ) + self.strG1ZsafeHeight = Path.Command( + "G1", {"Z": self.safeHeight, "F": tc.VertFeed.Value} + ) + self.strG0ZclearanceHeight = Path.Command("G0", {"Z": self.clearanceHeight}) cmd = self.baseOp.Path.Commands[0] - pos = cmd.Placement.Base # bogus m/c position to create first edge + pos = cmd.Placement.Base # bogus m/c position to create first edge bogusX = True bogusY = True commands = [cmd] lastExit = None for cmd in self.baseOp.Path.Commands[1:]: if cmd.Name in PathGeom.CmdMoveAll: - if bogusX == True : - bogusX = ( 'X' not in cmd.Parameters ) - if bogusY : - bogusY = ( 'Y' not in cmd.Parameters ) + if bogusX == True: + bogusX = "X" not in cmd.Parameters + if bogusY: + bogusY = "Y" not in cmd.Parameters edge = PathGeom.edgeForCmd(cmd, pos) if edge: inside = edge.common(self.boundary).Edges @@ -159,22 +191,30 @@ class PathBoundary: # it's really a shame that one cannot trust the sequence and/or # orientation of edges if 1 == len(inside) and 0 == len(outside): - PathLog.track(_vstr(pos), _vstr(lastExit), ' + ', cmd) + PathLog.track(_vstr(pos), _vstr(lastExit), " + ", cmd) # cmd fully included by boundary if lastExit: - if not ( bogusX or bogusY ) : # don't insert false paths based on bogus m/c position - commands.extend(self.boundaryCommands(lastExit, pos, tc.VertFeed.Value)) + if not ( + bogusX or bogusY + ): # don't insert false paths based on bogus m/c position + commands.extend( + self.boundaryCommands( + lastExit, pos, tc.VertFeed.Value + ) + ) lastExit = None commands.append(cmd) pos = PathGeom.commandEndPoint(cmd, pos) elif 0 == len(inside) and 1 == len(outside): - PathLog.track(_vstr(pos), _vstr(lastExit), ' - ', cmd) + PathLog.track(_vstr(pos), _vstr(lastExit), " - ", cmd) # cmd fully excluded by boundary if not lastExit: lastExit = pos pos = PathGeom.commandEndPoint(cmd, pos) else: - PathLog.track(_vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd) + PathLog.track( + _vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd + ) # cmd pierces boundary while inside or outside: ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)] @@ -187,35 +227,58 @@ class PathBoundary: # inside edges are taken at this point (see swap of inside/outside # above - so we can just connect the dots ... if lastExit: - if not ( bogusX or bogusY ) : commands.extend(self.boundaryCommands(lastExit, pos, tc.VertFeed.Value)) + if not (bogusX or bogusY): + commands.extend( + self.boundaryCommands( + lastExit, pos, tc.VertFeed.Value + ) + ) lastExit = None PathLog.track(e, flip) - if not ( bogusX or bogusY ) : # don't insert false paths based on bogus m/c position - commands.extend(PathGeom.cmdsForEdge(e, flip, False, 50, tc.HorizFeed.Value, tc.VertFeed.Value)) + if not ( + bogusX or bogusY + ): # don't insert false paths based on bogus m/c position + commands.extend( + PathGeom.cmdsForEdge( + e, + flip, + False, + 50, + tc.HorizFeed.Value, + tc.VertFeed.Value, + ) + ) inside.remove(e) pos = newPos lastExit = newPos else: - oe = [e for e in outside if PathGeom.edgeConnectsTo(e, pos)] + oe = [ + e + for e in outside + if PathGeom.edgeConnectsTo(e, pos) + ] PathLog.track(oe) if oe: e = oe[0] ptL = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, ptL) - newPos = e.valueAt(e.FirstParameter) if flip else ptL + newPos = ( + e.valueAt(e.FirstParameter) if flip else ptL + ) # outside edges are never taken at this point (see swap of # inside/outside above) - so just move along ... outside.remove(e) pos = newPos else: - PathLog.error('huh?') + PathLog.error("huh?") import Part - Part.show(Part.Vertex(pos), 'pos') + + Part.show(Part.Vertex(pos), "pos") for e in inside: - Part.show(e, 'ei') + Part.show(e, "ei") for e in outside: - Part.show(e, 'eo') - raise Exception('This is not supposed to happen') + Part.show(e, "eo") + raise Exception("This is not supposed to happen") # Eif # Eif # Ewhile @@ -223,7 +286,7 @@ class PathBoundary: # pos = PathGeom.commandEndPoint(cmd, pos) # Eif else: - PathLog.track('no-move', cmd) + PathLog.track("no-move", cmd) commands.append(cmd) if lastExit: commands.extend(self.boundaryCommands(lastExit, None, tc.VertFeed.Value)) @@ -231,16 +294,22 @@ class PathBoundary: PathLog.track(commands) return Path.Path(commands) + + # Eclass -def Create(base, name='DressupPathBoundary'): - '''Create(base, name='DressupPathBoundary') ... creates a dressup limiting base's Path to a boundary.''' - if not base.isDerivedFrom('Path::Feature'): - PathLog.error(translate('Path_DressupPathBoundary', 'The selected object is not a path')+'\n') +def Create(base, name="DressupPathBoundary"): + """Create(base, name='DressupPathBoundary') ... creates a dressup limiting base's Path to a boundary.""" + + if not base.isDerivedFrom("Path::Feature"): + PathLog.error( + translate("Path_DressupPathBoundary", "The selected object is not a path") + + "\n" + ) return None - obj = FreeCAD.ActiveDocument.addObject('Path::FeaturePython', name) + obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) job = PathUtils.findParentJob(base) obj.Proxy = DressupPathBoundary(obj, base, job) job.Proxy.addOperation(obj, base, True) diff --git a/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py b/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py index 6152c51433..c76f9e2042 100644 --- a/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py +++ b/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py @@ -22,26 +22,26 @@ import FreeCAD import FreeCADGui -import PathGui as PGui # ensure Path/Gui/Resources are loaded +import PathGui as PGui # ensure Path/Gui/Resources are loaded import PathScripts.PathDressupPathBoundary as PathDressupPathBoundary import PathScripts.PathLog as PathLog from PySide import QtGui, QtCore PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -#PathLog.trackModule() +# PathLog.trackModule() # Qt translation handling def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) -class TaskPanel(object): +class TaskPanel(object): def __init__(self, obj, viewProvider): self.obj = obj self.viewProvider = viewProvider - self.form = FreeCADGui.PySideUic.loadUi(':/panels/DressupPathBoundary.ui') + self.form = FreeCADGui.PySideUic.loadUi(":/panels/DressupPathBoundary.ui") if obj.Stock: self.visibilityBoundary = obj.Stock.ViewObject.Visibility obj.Stock.ViewObject.Visibility = True @@ -58,7 +58,11 @@ class TaskPanel(object): self.stockEdit = None def getStandardButtons(self): - return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel) + return int( + QtGui.QDialogButtonBox.Ok + | QtGui.QDialogButtonBox.Apply + | QtGui.QDialogButtonBox.Cancel + ) def modifyStandardButtons(self, buttonBox): self.buttonBox = buttonBox @@ -113,32 +117,42 @@ class TaskPanel(object): def setupFromBaseEdit(): PathLog.track(index, force) if force or not self.stockFromBase: - self.stockFromBase = PathJobGui.StockFromBaseBoundBoxEdit(self.obj, self.form, force) + self.stockFromBase = PathJobGui.StockFromBaseBoundBoxEdit( + self.obj, self.form, force + ) self.stockEdit = self.stockFromBase def setupCreateBoxEdit(): PathLog.track(index, force) if force or not self.stockCreateBox: - self.stockCreateBox = PathJobGui.StockCreateBoxEdit(self.obj, self.form, force) + self.stockCreateBox = PathJobGui.StockCreateBoxEdit( + self.obj, self.form, force + ) self.stockEdit = self.stockCreateBox def setupCreateCylinderEdit(): PathLog.track(index, force) if force or not self.stockCreateCylinder: - self.stockCreateCylinder = PathJobGui.StockCreateCylinderEdit(self.obj, self.form, force) + self.stockCreateCylinder = PathJobGui.StockCreateCylinderEdit( + self.obj, self.form, force + ) self.stockEdit = self.stockCreateCylinder def setupFromExisting(): PathLog.track(index, force) if force or not self.stockFromExisting: - self.stockFromExisting = PathJobGui.StockFromExistingEdit(self.obj, self.form, force) + self.stockFromExisting = PathJobGui.StockFromExistingEdit( + self.obj, self.form, force + ) if self.stockFromExisting.candidates(self.obj): self.stockEdit = self.stockFromExisting return True return False if index == -1: - if self.obj.Stock is None or PathJobGui.StockFromBaseBoundBoxEdit.IsStock(self.obj): + if self.obj.Stock is None or PathJobGui.StockFromBaseBoundBoxEdit.IsStock( + self.obj + ): setupFromBaseEdit() elif PathJobGui.StockCreateBoxEdit.IsStock(self.obj): setupCreateBoxEdit() @@ -147,7 +161,10 @@ class TaskPanel(object): elif PathJobGui.StockFromExistingEdit.IsStock(self.obj): setupFromExisting() else: - PathLog.error(translate('PathJob', "Unsupported stock object %s") % self.obj.Stock.Label) + PathLog.error( + translate("PathJob", "Unsupported stock object %s") + % self.obj.Stock.Label + ) else: if index == PathJobGui.StockFromBaseBoundBoxEdit.Index: setupFromBaseEdit() @@ -160,7 +177,10 @@ class TaskPanel(object): setupFromBaseEdit() index = -1 else: - PathLog.error(translate('PathJob', "Unsupported stock type %s (%d)") % (self.form.stock.currentText(), index)) + PathLog.error( + translate("PathJob", "Unsupported stock type %s (%d)") + % (self.form.stock.currentText(), index) + ) self.stockEdit.activate(self.obj, index == -1) def setupUi(self): @@ -183,16 +203,15 @@ class TaskPanel(object): class DressupPathBoundaryViewProvider(object): - def __init__(self, vobj): self.attach(vobj) def __getstate__(self): return None + def __setstate__(self, state): return None - def attach(self, vobj): self.vobj = vobj self.obj = vobj.Object @@ -225,8 +244,10 @@ class DressupPathBoundaryViewProvider(object): self.panel = None -def Create(base, name='DressupPathBoundary'): - FreeCAD.ActiveDocument.openTransaction(translate('Path_DressupPathBoundary', 'Create a Boundary dressup')) +def Create(base, name="DressupPathBoundary"): + FreeCAD.ActiveDocument.openTransaction( + translate("Path_DressupPathBoundary", "Create a Boundary dressup") + ) obj = PathDressupPathBoundary.Create(base, name) obj.ViewObject.Proxy = DressupPathBoundaryViewProvider(obj.ViewObject) obj.Base.ViewObject.Visibility = False @@ -235,18 +256,26 @@ def Create(base, name='DressupPathBoundary'): obj.ViewObject.Document.setEdit(obj.ViewObject, 0) return obj + class CommandPathDressupPathBoundary: # pylint: disable=no-init def GetResources(self): - return {'Pixmap': 'Path_Dressup', - 'MenuText': QtCore.QT_TRANSLATE_NOOP('Path_DressupPathBoundary', 'Boundary Dress-up'), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP('Path_DressupPathBoundary', 'Creates a Path Boundary Dress-up object from a selected path')} + return { + "Pixmap": "Path_Dressup", + "MenuText": QtCore.QT_TRANSLATE_NOOP( + "Path_DressupPathBoundary", "Boundary Dress-up" + ), + "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "Path_DressupPathBoundary", + "Creates a Path Boundary Dress-up object from a selected path", + ), + } def IsActive(self): if FreeCAD.ActiveDocument is not None: for o in FreeCAD.ActiveDocument.Objects: - if o.Name[:3] == 'Job': + if o.Name[:3] == "Job": return True return False @@ -254,19 +283,28 @@ class CommandPathDressupPathBoundary: # check that the selection contains exactly what we want selection = FreeCADGui.Selection.getSelection() if len(selection) != 1: - PathLog.error(translate('Path_DressupPathBoundary', 'Please select one path object')+'\n') + PathLog.error( + translate("Path_DressupPathBoundary", "Please select one path object") + + "\n" + ) return baseObject = selection[0] # everything ok! - FreeCAD.ActiveDocument.openTransaction(translate('Path_DressupPathBoundary', 'Create Path Boundary Dress-up')) - FreeCADGui.addModule('PathScripts.PathDressupPathBoundaryGui') - FreeCADGui.doCommand("PathScripts.PathDressupPathBoundaryGui.Create(App.ActiveDocument.%s)" % baseObject.Name) + FreeCAD.ActiveDocument.openTransaction( + translate("Path_DressupPathBoundary", "Create Path Boundary Dress-up") + ) + FreeCADGui.addModule("PathScripts.PathDressupPathBoundaryGui") + FreeCADGui.doCommand( + "PathScripts.PathDressupPathBoundaryGui.Create(App.ActiveDocument.%s)" + % baseObject.Name + ) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() + if FreeCAD.GuiUp: # register the FreeCAD command - FreeCADGui.addCommand('Path_DressupPathBoundary', CommandPathDressupPathBoundary()) + FreeCADGui.addCommand("Path_DressupPathBoundary", CommandPathDressupPathBoundary()) -PathLog.notice('Loading PathDressupPathBoundaryGui... done\n') +PathLog.notice("Loading PathDressupPathBoundaryGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathDressupTag.py b/src/Mod/Path/PathScripts/PathDressupTag.py index 30e2243a52..763b8d55ba 100644 --- a/src/Mod/Path/PathScripts/PathDressupTag.py +++ b/src/Mod/Path/PathScripts/PathDressupTag.py @@ -29,22 +29,25 @@ import math # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader -DraftGeomUtils = LazyLoader('DraftGeomUtils', globals(), 'DraftGeomUtils') -Part = LazyLoader('Part', globals(), 'Part') + +DraftGeomUtils = LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils") +Part = LazyLoader("Part", globals(), "Part") from PathScripts.PathDressupTagPreferences import HoldingTagPreferences from PySide import QtCore PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -#PathLog.trackModule() +# PathLog.trackModule() # Qt translation handling def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) + MaxInt = 99999999999999 + class TagSolid: def __init__(self, proxy, z, R): self.proxy = proxy @@ -76,7 +79,7 @@ class TagSolid: # with top r2 = r1 - dr s = height / math.sin(rad) - radius = min(r2, s) * math.tan((math.pi - rad)/2) * 0.95 + radius = min(r2, s) * math.tan((math.pi - rad) / 2) * 0.95 else: # triangular r2 = 0 @@ -98,7 +101,9 @@ class TagSolid: # lastly determine the center of the model, we want to make sure the seam of # the tag solid points away (in the hopes it doesn't coincide with a path) - self.baseCenter = FreeCAD.Vector((proxy.ptMin.x+proxy.ptMax.x)/2, (proxy.ptMin.y+proxy.ptMax.y)/2, 0) + self.baseCenter = FreeCAD.Vector( + (proxy.ptMin.x + proxy.ptMax.x) / 2, (proxy.ptMin.y + proxy.ptMax.y) / 2, 0 + ) def cloneAt(self, pos): clone = self.solid.copy() @@ -111,17 +116,65 @@ class TagSolid: class ObjectDressup: - def __init__(self, obj, base): - obj.addProperty('App::PropertyLink', 'Base', 'Base', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'The base path to modify')) - obj.addProperty('App::PropertyLength', 'Width', 'Tag', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Width of tags.')) - obj.addProperty('App::PropertyLength', 'Height', 'Tag', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Height of tags.')) - obj.addProperty('App::PropertyAngle', 'Angle', 'Tag', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Angle of tag plunge and ascent.')) - obj.addProperty('App::PropertyLength', 'Radius', 'Tag', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Radius of the fillet for the tag.')) - obj.addProperty('App::PropertyVectorList', 'Positions', 'Tag', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Locations of inserted holding tags')) - obj.addProperty('App::PropertyIntegerList', 'Disabled', 'Tag', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'IDs of disabled holding tags')) - obj.addProperty('App::PropertyInteger', 'SegmentationFactor', 'Tag', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Factor determining the # of segments used to approximate rounded tags.')) + obj.addProperty( + "App::PropertyLink", + "Base", + "Base", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "The base path to modify"), + ) + obj.addProperty( + "App::PropertyLength", + "Width", + "Tag", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Width of tags."), + ) + obj.addProperty( + "App::PropertyLength", + "Height", + "Tag", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Height of tags."), + ) + obj.addProperty( + "App::PropertyAngle", + "Angle", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", "Angle of tag plunge and ascent." + ), + ) + obj.addProperty( + "App::PropertyLength", + "Radius", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", "Radius of the fillet for the tag." + ), + ) + obj.addProperty( + "App::PropertyVectorList", + "Positions", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", "Locations of inserted holding tags" + ), + ) + obj.addProperty( + "App::PropertyIntegerList", + "Disabled", + "Tag", + QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "IDs of disabled holding tags"), + ) + obj.addProperty( + "App::PropertyInteger", + "SegmentationFactor", + "Tag", + QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", + "Factor determining the # of segments used to approximate rounded tags.", + ), + ) obj.Proxy = self obj.Base = base @@ -152,16 +205,20 @@ class ObjectDressup: def execute(self, obj): PathLog.track() if not obj.Base: - PathLog.error(translate('Path_DressupTag', 'No Base object found.')) + PathLog.error(translate("Path_DressupTag", "No Base object found.")) return - if not obj.Base.isDerivedFrom('Path::Feature'): - PathLog.error(translate('Path_DressupTag', 'Base is not a Path::Feature object.')) + if not obj.Base.isDerivedFrom("Path::Feature"): + PathLog.error( + translate("Path_DressupTag", "Base is not a Path::Feature object.") + ) return if not obj.Base.Path: - PathLog.error(translate('Path_DressupTag', 'Base doesn\'t have a Path to dress-up.')) + PathLog.error( + translate("Path_DressupTag", "Base doesn't have a Path to dress-up.") + ) return if not obj.Base.Path.Commands: - PathLog.error(translate('Path_DressupTag', 'Base Path is empty.')) + PathLog.error(translate("Path_DressupTag", "Base Path is empty.")) return self.obj = obj @@ -190,14 +247,19 @@ class ObjectDressup: maxZ = max(pt.z, maxZ) minZ = min(pt.z, minZ) lastPt = pt - PathLog.debug("bb = (%.2f, %.2f, %.2f) ... (%.2f, %.2f, %.2f)" % (minX, minY, minZ, maxX, maxY, maxZ)) + PathLog.debug( + "bb = (%.2f, %.2f, %.2f) ... (%.2f, %.2f, %.2f)" + % (minX, minY, minZ, maxX, maxY, maxZ) + ) self.ptMin = FreeCAD.Vector(minX, minY, minZ) self.ptMax = FreeCAD.Vector(maxX, maxY, maxZ) self.masterSolid = TagSolid(self, minZ, self.toolRadius()) self.solids = [self.masterSolid.cloneAt(pos) for pos in self.obj.Positions] self.tagSolid = Part.Compound(self.solids) - self.wire, rapid = PathGeom.wireForPath(obj.Base.Path) # pylint: disable=unused-variable + self.wire, rapid = PathGeom.wireForPath( + obj.Base.Path + ) # pylint: disable=unused-variable self.edges = self.wire.Edges maxTagZ = minZ + obj.Height.Value @@ -210,7 +272,7 @@ class ObjectDressup: for cmd in obj.Base.Path.Commands: if cmd in PathGeom.CmdMove: - if lastZ <= maxTagZ or cmd.Parameters.get('Z', lastZ) <= maxTagZ: + if lastZ <= maxTagZ or cmd.Parameters.get("Z", lastZ) <= maxTagZ: pass else: commands.append(cmd) @@ -226,7 +288,7 @@ class ObjectDressup: def addTagsToDocument(self): for i, solid in enumerate(self.solids): - obj = FreeCAD.ActiveDocument.addObject('Part::Compound', "tag_%02d" % i) + obj = FreeCAD.ActiveDocument.addObject("Part::Compound", "tag_%02d" % i) obj.Shape = solid def supportsTagGeneration(self, obj): @@ -241,16 +303,18 @@ class ObjectDressup: return False -def Create(baseObject, name='DressupTag'): - ''' +def Create(baseObject, name="DressupTag"): + """ Create(basePath, name = 'DressupTag') ... create tag dressup object for the given base path. - ''' - if not baseObject.isDerivedFrom('Path::Feature'): - PathLog.error(translate('Path_DressupTag', 'The selected object is not a path')+'\n') + """ + if not baseObject.isDerivedFrom("Path::Feature"): + PathLog.error( + translate("Path_DressupTag", "The selected object is not a path") + "\n" + ) return None - if baseObject.isDerivedFrom('Path::FeatureCompoundPython'): - PathLog.error(translate('Path_DressupTag', 'Please select a Profile object')) + if baseObject.isDerivedFrom("Path::FeatureCompoundPython"): + PathLog.error(translate("Path_DressupTag", "Please select a Profile object")) return None obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) @@ -260,4 +324,5 @@ def Create(baseObject, name='DressupTag'): dbo.assignDefaultValues() return obj -PathLog.notice('Loading Path_DressupTag... done\n') + +PathLog.notice("Loading Path_DressupTag... done\n") diff --git a/src/Mod/Path/PathScripts/PathDressupTagGui.py b/src/Mod/Path/PathScripts/PathDressupTagGui.py index be312176a1..ce181d306c 100644 --- a/src/Mod/Path/PathScripts/PathDressupTagGui.py +++ b/src/Mod/Path/PathScripts/PathDressupTagGui.py @@ -22,7 +22,7 @@ import FreeCAD import FreeCADGui -import PathGui as PGui # ensure Path/Gui/Resources are loaded +import PathGui as PGui # ensure Path/Gui/Resources are loaded import PathScripts.PathGeom as PathGeom import PathScripts.PathGetPoint as PathGetPoint import PathScripts.PathDressupHoldingTags as PathDressupTag @@ -60,7 +60,9 @@ class PathDressupTagTaskPanel: self.getPoint = PathGetPoint.TaskPanel(self.form.removeEditAddGroup, True) self.jvo = PathUtils.findParentJob(obj).ViewObject if jvoVisibility is None: - FreeCAD.ActiveDocument.openTransaction(translate("PathDressup_HoldingTags", "Edit HoldingTags Dress-up")) + FreeCAD.ActiveDocument.openTransaction( + translate("PathDressup_HoldingTags", "Edit HoldingTags Dress-up") + ) self.jvoVisible = self.jvo.isVisible() if self.jvoVisible: self.jvo.hide() @@ -76,7 +78,11 @@ class PathDressupTagTaskPanel: self.editItem = None def getStandardButtons(self): - return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel) + return int( + QtGui.QDialogButtonBox.Ok + | QtGui.QDialogButtonBox.Apply + | QtGui.QDialogButtonBox.Cancel + ) def clicked(self, button): if button == QtGui.QDialogButtonBox.Apply: @@ -201,7 +207,9 @@ class PathDressupTagTaskPanel: self.Disabled = self.obj.Disabled self.updateTagsView() else: - PathLog.error(translate('Path_DressupTag', 'Cannot copy tags - internal error')+'\n') + PathLog.error( + translate("Path_DressupTag", "Cannot copy tags - internal error") + "\n" + ) def updateModel(self): self.getFields() @@ -273,10 +281,16 @@ class PathDressupTagTaskPanel: def setFields(self): self.updateTagsView() self.form.sbCount.setValue(len(self.Positions)) - self.form.ifHeight.setText(FreeCAD.Units.Quantity(self.obj.Height, FreeCAD.Units.Length).UserString) - self.form.ifWidth.setText(FreeCAD.Units.Quantity(self.obj.Width, FreeCAD.Units.Length).UserString) + self.form.ifHeight.setText( + FreeCAD.Units.Quantity(self.obj.Height, FreeCAD.Units.Length).UserString + ) + self.form.ifWidth.setText( + FreeCAD.Units.Quantity(self.obj.Width, FreeCAD.Units.Length).UserString + ) self.form.dsbAngle.setValue(self.obj.Angle) - self.form.ifRadius.setText(FreeCAD.Units.Quantity(self.obj.Radius, FreeCAD.Units.Length).UserString) + self.form.ifRadius.setText( + FreeCAD.Units.Quantity(self.obj.Radius, FreeCAD.Units.Length).UserString + ) def setupUi(self): self.Positions = self.obj.Positions @@ -292,7 +306,9 @@ class PathDressupTagTaskPanel: self.form.cbTagGeneration.setEnabled(False) enableCopy = False - for tags in sorted([o.Label for o in FreeCAD.ActiveDocument.Objects if 'DressupTag' in o.Name]): + for tags in sorted( + [o.Label for o in FreeCAD.ActiveDocument.Objects if "DressupTag" in o.Name] + ): if tags != self.obj.Label: enableCopy = True self.form.cbSource.addItem(tags) @@ -319,8 +335,8 @@ class HoldingTagMarker: self.pos = coin.SoTranslation() self.pos.translation = (point.x, point.y, point.z) self.sphere = coin.SoSphere() - self.scale = coin.SoType.fromName('SoShapeScale').createInstance() - self.scale.setPart('shape', self.sphere) + self.scale = coin.SoType.fromName("SoShapeScale").createInstance() + self.scale.setPart("shape", self.sphere) self.scale.scaleFactor.setValue(7) self.material = coin.SoMaterial() self.sep.addChild(self.pos) @@ -337,15 +353,18 @@ class HoldingTagMarker: def setEnabled(self, enabled): self.enabled = enabled if enabled: - self.material.diffuseColor = self.color[0] if not self.selected else self.color[2] + self.material.diffuseColor = ( + self.color[0] if not self.selected else self.color[2] + ) self.material.transparency = 0.0 else: - self.material.diffuseColor = self.color[1] if not self.selected else self.color[2] + self.material.diffuseColor = ( + self.color[1] if not self.selected else self.color[2] + ) self.material.transparency = 0.6 class PathDressupTagViewProvider: - def __init__(self, vobj): PathLog.track() self.vobj = vobj @@ -376,15 +395,25 @@ class PathDressupTagViewProvider: def setupColors(self): def colorForColorValue(val): - v = [((val >> n) & 0xff) / 255. for n in [24, 16, 8, 0]] + v = [((val >> n) & 0xFF) / 255.0 for n in [24, 16, 8, 0]] return coin.SbColor(v[0], v[1], v[2]) pref = PathPreferences.preferences() # R G B A - npc = pref.GetUnsigned('DefaultPathMarkerColor', ((85*256 + 255)*256 + 0) * 256 + 255) - hpc = pref.GetUnsigned('DefaultHighlightPathColor', ((255*256 + 125)*256 + 0)*256 + 255) - dpc = pref.GetUnsigned('DefaultDisabledPathColor', ((205*256 + 205)*256 + 205)*256 + 154) - self.colors = [colorForColorValue(npc), colorForColorValue(dpc), colorForColorValue(hpc)] + npc = pref.GetUnsigned( + "DefaultPathMarkerColor", ((85 * 256 + 255) * 256 + 0) * 256 + 255 + ) + hpc = pref.GetUnsigned( + "DefaultHighlightPathColor", ((255 * 256 + 125) * 256 + 0) * 256 + 255 + ) + dpc = pref.GetUnsigned( + "DefaultDisabledPathColor", ((205 * 256 + 205) * 256 + 205) * 256 + 154 + ) + self.colors = [ + colorForColorValue(npc), + colorForColorValue(dpc), + colorForColorValue(hpc), + ] def attach(self, vobj): PathLog.track() @@ -398,7 +427,9 @@ class PathDressupTagViewProvider: if self.obj and self.obj.Base: for i in self.obj.Base.InList: - if hasattr(i, 'Group') and self.obj.Base.Name in [o.Name for o in i.Group]: + if hasattr(i, "Group") and self.obj.Base.Name in [ + o.Name for o in i.Group + ]: i.Group = [o for o in i.Group if o.Name != self.obj.Base.Name] if self.obj.Base.ViewObject: self.obj.Base.ViewObject.Visibility = False @@ -416,7 +447,7 @@ class PathDressupTagViewProvider: return [self.obj.Base] def onDelete(self, arg1=None, arg2=None): - '''this makes sure that the base operation is added back to the job and visible''' + """this makes sure that the base operation is added back to the job and visible""" # pylint: disable=unused-argument PathLog.track() if self.obj.Base and self.obj.Base.ViewObject: @@ -436,7 +467,9 @@ class PathDressupTagViewProvider: self.switch.removeChild(tag.sep) tags = [] for i, p in enumerate(positions): - tag = HoldingTagMarker(self.obj.Proxy.pointAtBottom(self.obj, p), self.colors) + tag = HoldingTagMarker( + self.obj.Proxy.pointAtBottom(self.obj, p), self.colors + ) tag.setEnabled(not i in disabled) tags.append(tag) self.switch.addChild(tag.sep) @@ -444,7 +477,7 @@ class PathDressupTagViewProvider: def updateData(self, obj, propName): PathLog.track(propName) - if 'Disabled' == propName: + if "Disabled" == propName: self.updatePositions(obj.Positions, obj.Disabled) def onModelChanged(self): @@ -468,7 +501,7 @@ class PathDressupTagViewProvider: def unsetEdit(self, vobj, mode): # pylint: disable=unused-argument - if hasattr(self, 'panel') and self.panel: + if hasattr(self, "panel") and self.panel: self.panel.abort() def setupTaskPanel(self, panel): @@ -500,7 +533,9 @@ class PathDressupTagViewProvider: z = self.tags[0].point.z p = FreeCAD.Vector(x, y, z) for i, tag in enumerate(self.tags): - if PathGeom.pointsCoincide(p, tag.point, tag.sphere.radius.getValue() * 1.3): + if PathGeom.pointsCoincide( + p, tag.point, tag.sphere.radius.getValue() * 1.3 + ): return i return -1 @@ -519,12 +554,14 @@ class PathDressupTagViewProvider: FreeCADGui.updateGui() -def Create(baseObject, name='DressupTag'): - ''' +def Create(baseObject, name="DressupTag"): + """ Create(basePath, name = 'DressupTag') ... create tag dressup object for the given base path. Use this command only iff the UI is up - for batch processing see PathDressupTag.Create - ''' - FreeCAD.ActiveDocument.openTransaction(translate("Path_DressupTag", "Create a Tag dressup")) + """ + FreeCAD.ActiveDocument.openTransaction( + translate("Path_DressupTag", "Create a Tag dressup") + ) obj = PathDressupTag.Create(baseObject, name) obj.ViewObject.Proxy = PathDressupTagViewProvider(obj.ViewObject) FreeCAD.ActiveDocument.commitTransaction() @@ -536,14 +573,18 @@ class CommandPathDressupTag: # pylint: disable=no-init def GetResources(self): - return {'Pixmap': 'Path_Dressup', - 'MenuText': QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Tag Dress-up'), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Creates a Tag Dress-up object from a selected path')} + return { + "Pixmap": "Path_Dressup", + "MenuText": QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Tag Dress-up"), + "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "Path_DressupTag", "Creates a Tag Dress-up object from a selected path" + ), + } def IsActive(self): if FreeCAD.ActiveDocument is not None: for o in FreeCAD.ActiveDocument.Objects: - if o.Name[:3] == 'Job': + if o.Name[:3] == "Job": return True return False @@ -551,19 +592,27 @@ class CommandPathDressupTag: # check that the selection contains exactly what we want selection = FreeCADGui.Selection.getSelection() if len(selection) != 1: - PathLog.error(translate('Path_DressupTag', 'Please select one path object')+'\n') + PathLog.error( + translate("Path_DressupTag", "Please select one path object") + "\n" + ) return baseObject = selection[0] # everything ok! - FreeCAD.ActiveDocument.openTransaction(translate('Path_DressupTag', 'Create Tag Dress-up')) - FreeCADGui.addModule('PathScripts.PathDressupTagGui') - FreeCADGui.doCommand("PathScripts.PathDressupTagGui.Create(App.ActiveDocument.%s)" % baseObject.Name) + FreeCAD.ActiveDocument.openTransaction( + translate("Path_DressupTag", "Create Tag Dress-up") + ) + FreeCADGui.addModule("PathScripts.PathDressupTagGui") + FreeCADGui.doCommand( + "PathScripts.PathDressupTagGui.Create(App.ActiveDocument.%s)" + % baseObject.Name + ) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() + if FreeCAD.GuiUp: # register the FreeCAD command - FreeCADGui.addCommand('Path_DressupTag', CommandPathDressupTag()) + FreeCADGui.addCommand("Path_DressupTag", CommandPathDressupTag()) -PathLog.notice('Loading PathDressupTagGui... done\n') +PathLog.notice("Loading PathDressupTagGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathDressupTagPreferences.py b/src/Mod/Path/PathScripts/PathDressupTagPreferences.py index 99bb0888d4..6d171fd8ba 100644 --- a/src/Mod/Path/PathScripts/PathDressupTagPreferences.py +++ b/src/Mod/Path/PathScripts/PathDressupTagPreferences.py @@ -33,67 +33,102 @@ def translate(context, text, disambig=None): class HoldingTagPreferences: - DefaultHoldingTagWidth = 'DefaultHoldingTagWidth' - DefaultHoldingTagHeight = 'DefaultHoldingTagHeight' - DefaultHoldingTagAngle = 'DefaultHoldingTagAngle' - DefaultHoldingTagRadius = 'DefaultHoldingTagRadius' - DefaultHoldingTagCount = 'DefaultHoldingTagCount' + DefaultHoldingTagWidth = "DefaultHoldingTagWidth" + DefaultHoldingTagHeight = "DefaultHoldingTagHeight" + DefaultHoldingTagAngle = "DefaultHoldingTagAngle" + DefaultHoldingTagRadius = "DefaultHoldingTagRadius" + DefaultHoldingTagCount = "DefaultHoldingTagCount" @classmethod def defaultWidth(cls, ifNotSet): - value = PathPreferences.preferences().GetFloat(cls.DefaultHoldingTagWidth, ifNotSet) + value = PathPreferences.preferences().GetFloat( + cls.DefaultHoldingTagWidth, ifNotSet + ) if value == 0.0: return ifNotSet return value @classmethod def defaultHeight(cls, ifNotSet): - value = PathPreferences.preferences().GetFloat(cls.DefaultHoldingTagHeight, ifNotSet) + value = PathPreferences.preferences().GetFloat( + cls.DefaultHoldingTagHeight, ifNotSet + ) if value == 0.0: return ifNotSet return value @classmethod def defaultAngle(cls, ifNotSet=45.0): - value = PathPreferences.preferences().GetFloat(cls.DefaultHoldingTagAngle, ifNotSet) + value = PathPreferences.preferences().GetFloat( + cls.DefaultHoldingTagAngle, ifNotSet + ) if value < 10.0: return ifNotSet return value @classmethod def defaultCount(cls, ifNotSet=4): - value = PathPreferences.preferences().GetUnsigned(cls.DefaultHoldingTagCount, ifNotSet) + value = PathPreferences.preferences().GetUnsigned( + cls.DefaultHoldingTagCount, ifNotSet + ) if value < 2: return float(ifNotSet) return float(value) @classmethod def defaultRadius(cls, ifNotSet=0.0): - return PathPreferences.preferences().GetFloat(cls.DefaultHoldingTagRadius, ifNotSet) + return PathPreferences.preferences().GetFloat( + cls.DefaultHoldingTagRadius, ifNotSet + ) def __init__(self): if FreeCAD.GuiUp: import FreeCADGui - self.form = FreeCADGui.PySideUic.loadUi(":/preferences/PathDressupHoldingTags.ui") - self.label = translate("Path_DressupTag", 'Holding Tag') + + self.form = FreeCADGui.PySideUic.loadUi( + ":/preferences/PathDressupHoldingTags.ui" + ) + self.label = translate("Path_DressupTag", "Holding Tag") def loadSettings(self): - self.form.ifWidth.setText(FreeCAD.Units.Quantity(self.defaultWidth(0), FreeCAD.Units.Length).UserString) - self.form.ifHeight.setText(FreeCAD.Units.Quantity(self.defaultHeight(0), FreeCAD.Units.Length).UserString) + self.form.ifWidth.setText( + FreeCAD.Units.Quantity( + self.defaultWidth(0), FreeCAD.Units.Length + ).UserString + ) + self.form.ifHeight.setText( + FreeCAD.Units.Quantity( + self.defaultHeight(0), FreeCAD.Units.Length + ).UserString + ) self.form.dsbAngle.setValue(self.defaultAngle()) - self.form.ifRadius.setText(FreeCAD.Units.Quantity(self.defaultRadius(), FreeCAD.Units.Length).UserString) + self.form.ifRadius.setText( + FreeCAD.Units.Quantity( + self.defaultRadius(), FreeCAD.Units.Length + ).UserString + ) self.form.sbCount.setValue(self.defaultCount()) def saveSettings(self): pref = PathPreferences.preferences() - pref.SetFloat(self.DefaultHoldingTagWidth, FreeCAD.Units.Quantity(self.form.ifWidth.text()).Value) - pref.SetFloat(self.DefaultHoldingTagHeight, FreeCAD.Units.Quantity(self.form.ifHeight.text()).Value) + pref.SetFloat( + self.DefaultHoldingTagWidth, + FreeCAD.Units.Quantity(self.form.ifWidth.text()).Value, + ) + pref.SetFloat( + self.DefaultHoldingTagHeight, + FreeCAD.Units.Quantity(self.form.ifHeight.text()).Value, + ) pref.SetFloat(self.DefaultHoldingTagAngle, self.form.dsbAngle.value()) - pref.SetFloat(self.DefaultHoldingTagRadius, FreeCAD.Units.Quantity(self.form.ifRadius.text())) + pref.SetFloat( + self.DefaultHoldingTagRadius, + FreeCAD.Units.Quantity(self.form.ifRadius.text()), + ) pref.SetUnsigned(self.DefaultHoldingTagCount, self.form.sbCount.value()) @classmethod def preferencesPage(cls): return HoldingTagPreferences() + PathPreferencesPathDressup.RegisterDressup(HoldingTagPreferences) diff --git a/src/Mod/Path/PathScripts/PathFeatureExtensions.py b/src/Mod/Path/PathScripts/PathFeatureExtensions.py index d3b7ead79c..dc0d9cf23f 100644 --- a/src/Mod/Path/PathScripts/PathFeatureExtensions.py +++ b/src/Mod/Path/PathScripts/PathFeatureExtensions.py @@ -28,7 +28,8 @@ import math # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader -PathUtils = LazyLoader('PathScripts.PathUtils', globals(), 'PathScripts.PathUtils') + +PathUtils = LazyLoader("PathScripts.PathUtils", globals(), "PathScripts.PathUtils") from PySide import QtCore @@ -47,7 +48,7 @@ def translate(context, text, disambig=None): def endPoints(edgeOrWire): - '''endPoints(edgeOrWire) ... return the first and last point of the wire or the edge, assuming the argument is not a closed wire.''' + """endPoints(edgeOrWire) ... return the first and last point of the wire or the edge, assuming the argument is not a closed wire.""" if Part.Wire == type(edgeOrWire): # edges = edgeOrWire.Edges pts = [e.valueAt(e.FirstParameter) for e in edgeOrWire.Edges] @@ -69,7 +70,7 @@ def endPoints(edgeOrWire): def includesPoint(p, pts): - '''includesPoint(p, pts) ... answer True if the collection of pts includes the point p''' + """includesPoint(p, pts) ... answer True if the collection of pts includes the point p""" for pt in pts: if PathGeom.pointsCoincide(p, pt): return True @@ -78,11 +79,13 @@ def includesPoint(p, pts): def selectOffsetWire(feature, wires): - '''selectOffsetWire(feature, wires) ... returns the Wire in wires which is does not intersect with feature''' + """selectOffsetWire(feature, wires) ... returns the Wire in wires which is does not intersect with feature""" closest = None for w in wires: dist = feature.distToShape(w)[0] - if closest is None or dist > closest[0]: # pylint: disable=unsubscriptable-object + if ( + closest is None or dist > closest[0] + ): # pylint: disable=unsubscriptable-object closest = (dist, w) if closest is not None: @@ -92,19 +95,23 @@ def selectOffsetWire(feature, wires): def extendWire(feature, wire, length): - '''extendWire(wire, length) ... return a closed Wire which extends wire by length''' + """extendWire(wire, length) ... return a closed Wire which extends wire by length""" PathLog.track(length) if not length or length == 0: return None - + try: off2D = wire.makeOffset2D(length) except FreeCAD.Base.FreeCADError as ee: return None endPts = endPoints(wire) # Assumes wire is NOT closed if endPts: - edges = [e for e in off2D.Edges if Part.Circle != type(e.Curve) or not includesPoint(e.Curve.Center, endPts)] + edges = [ + e + for e in off2D.Edges + if Part.Circle != type(e.Curve) or not includesPoint(e.Curve.Center, endPts) + ] wires = [Part.Wire(e) for e in Part.sortEdges(edges)] offset = selectOffsetWire(feature, wires) ePts = endPoints(offset) @@ -127,12 +134,14 @@ def extendWire(feature, wire, length): def createExtension(obj, extObj, extFeature, extSub): - return Extension(obj, - extObj, - extFeature, - extSub, - obj.ExtensionLengthDefault, - Extension.DirectionNormal) + return Extension( + obj, + extObj, + extFeature, + extSub, + obj.ExtensionLengthDefault, + Extension.DirectionNormal, + ) def readObjExtensionFeature(obj): @@ -142,7 +151,7 @@ def readObjExtensionFeature(obj): for extObj, features in obj.ExtensionFeature: for sub in features: - extFeature, extSub = sub.split(':') + extFeature, extSub = sub.split(":") extensions.append((extObj.Name, extFeature, extSub)) return extensions @@ -154,7 +163,7 @@ def getExtensions(obj): for extObj, features in obj.ExtensionFeature: for sub in features: - extFeature, extSub = sub.split(':') + extFeature, extSub = sub.split(":") extensions.append(createExtension(obj, extObj, extFeature, extSub)) i = i + 1 return extensions @@ -167,11 +176,14 @@ def setExtensions(obj, extensions): class Extension(object): DirectionNormal = 0 - DirectionX = 1 - DirectionY = 2 + DirectionX = 1 + DirectionY = 2 def __init__(self, op, obj, feature, sub, length, direction): - PathLog.debug("Extension(%s, %s, %s, %.2f, %s" % (obj.Label, feature, sub, length, direction)) + PathLog.debug( + "Extension(%s, %s, %s, %.2f, %s" + % (obj.Label, feature, sub, length, direction) + ) self.op = op self.obj = obj self.feature = feature @@ -197,8 +209,16 @@ class Extension(object): off = self.length.Value * direction e2.translate(off) e2 = PathGeom.flipEdge(e2) - e1 = Part.Edge(Part.LineSegment(e0.valueAt(e0.LastParameter), e2.valueAt(e2.FirstParameter))) - e3 = Part.Edge(Part.LineSegment(e2.valueAt(e2.LastParameter), e0.valueAt(e0.FirstParameter))) + e1 = Part.Edge( + Part.LineSegment( + e0.valueAt(e0.LastParameter), e2.valueAt(e2.FirstParameter) + ) + ) + e3 = Part.Edge( + Part.LineSegment( + e2.valueAt(e2.LastParameter), e0.valueAt(e0.FirstParameter) + ) + ) wire = Part.Wire([e0, e1, e2, e3]) self.wire = wire return wire @@ -206,8 +226,8 @@ class Extension(object): return extendWire(feature, Part.Wire([e0]), self.length.Value) def _getEdgeNumbers(self): - if 'Wire' in self.sub: - numbers = [nr for nr in self.sub[5:-1].split(',')] + if "Wire" in self.sub: + numbers = [nr for nr in self.sub[5:-1].split(",")] else: numbers = [self.sub[4:]] @@ -235,7 +255,7 @@ class Extension(object): e0 = wire.Edges[0] midparam = e0.FirstParameter + 0.5 * (e0.LastParameter - e0.FirstParameter) tangent = e0.tangentAt(midparam) - PathLog.track('tangent', tangent, self.feature, self.sub) + PathLog.track("tangent", tangent, self.feature, self.sub) normal = tangent.cross(FreeCAD.Vector(0, 0, 1)) if PathGeom.pointsCoincide(normal, FreeCAD.Vector(0, 0, 0)): return None @@ -243,21 +263,21 @@ class Extension(object): return self._getDirectedNormal(e0.valueAt(midparam), normal.normalize()) def getExtensionFaces(self, extensionWire): - '''getExtensionFace(extensionWire)... + """getExtensionFace(extensionWire)... A public helper method to retrieve the requested extension as a face, rather than a wire because some extensions require a face shape for definition that allows for two wires for boundary definition. - ''' + """ if self.extFaces: return self.extFaces - + return [Part.Face(extensionWire)] def getWire(self): - '''getWire()... Public method to retrieve the extension area, pertaining to the feature + """getWire()... Public method to retrieve the extension area, pertaining to the feature and sub element provided at class instantiation, as a closed wire. If no closed wire - is possible, a `None` value is returned.''' + is possible, a `None` value is returned.""" if self.sub[:6] == "Avoid_": feature = self.obj.Shape.getElement(self.feature) @@ -281,9 +301,9 @@ class Extension(object): return self._getRegularWire() def _getRegularWire(self): - '''_getRegularWire()... Private method to retrieve the extension area, pertaining to the feature + """_getRegularWire()... Private method to retrieve the extension area, pertaining to the feature and sub element provided at class instantiation, as a closed wire. If no closed wire - is possible, a `None` value is returned.''' + is possible, a `None` value is returned.""" PathLog.track() length = self.length.Value @@ -314,11 +334,23 @@ class Extension(object): # assuming the offset produces a valid circle - go for it if r > 0: - e3 = Part.makeCircle(r, circle.Center, circle.Axis, edge.FirstParameter * 180 / math.pi, edge.LastParameter * 180 / math.pi) + e3 = Part.makeCircle( + r, + circle.Center, + circle.Axis, + edge.FirstParameter * 180 / math.pi, + edge.LastParameter * 180 / math.pi, + ) if endPoints(edge): # need to construct the arc slice - e0 = Part.makeLine(edge.valueAt(edge.FirstParameter), e3.valueAt(e3.FirstParameter)) - e2 = Part.makeLine(edge.valueAt(edge.LastParameter), e3.valueAt(e3.LastParameter)) + e0 = Part.makeLine( + edge.valueAt(edge.FirstParameter), + e3.valueAt(e3.FirstParameter), + ) + e2 = Part.makeLine( + edge.valueAt(edge.LastParameter), + e3.valueAt(e3.LastParameter), + ) return Part.Wire([e0, edge, e2, e3]) extWire = Part.Wire([e3]) @@ -358,7 +390,7 @@ class Extension(object): off2D = sub.makeOffset2D(length) except FreeCAD.Base.FreeCADError as ee: return None - + if isOutside: self.extFaces = [Part.Face(off2D).cut(featFace)] else: @@ -369,9 +401,9 @@ class Extension(object): return extendWire(feature, sub, length) def _getOutlineWire(self): - '''_getOutlineWire()... Private method to retrieve an extended outline extension area, + """_getOutlineWire()... Private method to retrieve an extended outline extension area, pertaining to the feature and sub element provided at class instantiation, as a closed wire. - If no closed wire is possible, a `None` value is returned.''' + If no closed wire is possible, a `None` value is returned.""" PathLog.track() baseShape = self.obj.Shape @@ -411,10 +443,10 @@ class Extension(object): return None def _getWaterlineWire(self): - '''_getWaterlineWire()... Private method to retrieve a waterline extension area, + """_getWaterlineWire()... Private method to retrieve a waterline extension area, pertaining to the feature and sub element provided at class instantiation, as a closed wire. Only waterline faces touching source face are returned as part of the waterline extension area. - If no closed wire is possible, a `None` value is returned.''' + If no closed wire is possible, a `None` value is returned.""" PathLog.track() msg = translate("PathFeatureExtensions", "Waterline error") @@ -451,9 +483,9 @@ class Extension(object): return None def _makeCircularExtFace(self, edge, extWire): - '''_makeCircularExtensionFace(edge, extWire)... + """_makeCircularExtensionFace(edge, extWire)... Create proper circular extension face shape. Incoming edge is expected to be a circle. - ''' + """ # Add original outer wire to cut faces if necessary edgeFace = Part.Face(Part.Wire([edge])) edgeFace.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - edgeFace.BoundBox.ZMin)) @@ -467,37 +499,60 @@ class Extension(object): extensionFace.translate(FreeCAD.Vector(0.0, 0.0, edge.BoundBox.ZMin)) return extensionFace + + # Eclass def initialize_properties(obj): """initialize_properties(obj)... Adds feature properties to object argument""" - if not hasattr(obj, 'ExtensionLengthDefault'): - obj.addProperty('App::PropertyDistance', 'ExtensionLengthDefault', 'Extension', QtCore.QT_TRANSLATE_NOOP('PathPocketShape', 'Default length of extensions.')) - if not hasattr(obj, 'ExtensionFeature'): - obj.addProperty('App::PropertyLinkSubListGlobal', 'ExtensionFeature', 'Extension', QtCore.QT_TRANSLATE_NOOP('PathPocketShape', 'List of features to extend.')) - if not hasattr(obj, 'ExtensionCorners'): - obj.addProperty('App::PropertyBool', 'ExtensionCorners', 'Extension', QtCore.QT_TRANSLATE_NOOP('PathPocketShape', 'When enabled connected extension edges are combined to wires.')) + if not hasattr(obj, "ExtensionLengthDefault"): + obj.addProperty( + "App::PropertyDistance", + "ExtensionLengthDefault", + "Extension", + QtCore.QT_TRANSLATE_NOOP( + "PathPocketShape", "Default length of extensions." + ), + ) + if not hasattr(obj, "ExtensionFeature"): + obj.addProperty( + "App::PropertyLinkSubListGlobal", + "ExtensionFeature", + "Extension", + QtCore.QT_TRANSLATE_NOOP("PathPocketShape", "List of features to extend."), + ) + if not hasattr(obj, "ExtensionCorners"): + obj.addProperty( + "App::PropertyBool", + "ExtensionCorners", + "Extension", + QtCore.QT_TRANSLATE_NOOP( + "PathPocketShape", + "When enabled connected extension edges are combined to wires.", + ), + ) obj.ExtensionCorners = True - obj.setEditorMode('ExtensionFeature', 2) + obj.setEditorMode("ExtensionFeature", 2) def set_default_property_values(obj, job): """set_default_property_values(obj, job) ... set default values for feature properties""" obj.ExtensionCorners = True - obj.setExpression('ExtensionLengthDefault', 'OpToolDiameter / 2.0') + obj.setExpression("ExtensionLengthDefault", "OpToolDiameter / 2.0") def SetupProperties(): """SetupProperties()... Returns list of feature property names""" - setup = ['ExtensionLengthDefault', 'ExtensionFeature', - 'ExtensionCorners'] + setup = ["ExtensionLengthDefault", "ExtensionFeature", "ExtensionCorners"] return setup # Extend outline face generation function -def getExtendOutlineFace(base_shape, face, extension, remHoles=False, offset_tolerance=1e-4): +def getExtendOutlineFace( + base_shape, face, extension, remHoles=False, offset_tolerance=1e-4 +): """getExtendOutlineFace(obj, base_shape, face, extension, remHoles) ... Creates an extended face for the pocket, taking into consideration lateral collision with the greater base shape. @@ -513,11 +568,9 @@ def getExtendOutlineFace(base_shape, face, extension, remHoles=False, offset_tol """ # Make offset face per user-specified extension distance so as to allow full clearing of face where possible. - offset_face = PathUtils.getOffsetArea(face, - extension, - removeHoles=remHoles, - plane=face, - tolerance=offset_tolerance) + offset_face = PathUtils.getOffsetArea( + face, extension, removeHoles=remHoles, plane=face, tolerance=offset_tolerance + ) if not offset_face: PathLog.error("Failed to offset a selected face.") return None @@ -540,9 +593,11 @@ def getExtendOutlineFace(base_shape, face, extension, remHoles=False, offset_tol for f in available.Faces: bbx = f.BoundBox zNorm = abs(f.normalAt(0.0, 0.0).z) - if (PathGeom.isRoughly(zNorm, 1.0) and - PathGeom.isRoughly(bbx.ZMax - bbx.ZMin, 0.0) and - PathGeom.isRoughly(bbx.ZMin, face.BoundBox.ZMin)): + if ( + PathGeom.isRoughly(zNorm, 1.0) + and PathGeom.isRoughly(bbx.ZMax - bbx.ZMin, 0.0) + and PathGeom.isRoughly(bbx.ZMin, face.BoundBox.ZMin) + ): if bbx.ZMin < zmin: bottom_faces.append(f) @@ -561,6 +616,7 @@ def getExtendOutlineFace(base_shape, face, extension, remHoles=False, offset_tol PathLog.error("No bottom face for extend outline.") return None + # Waterline extension face generation function def getWaterlineFace(base_shape, face): """getWaterlineFace(base_shape, face) ... @@ -580,8 +636,11 @@ def getWaterlineFace(base_shape, face): step_down=math.floor(faceHeight - baseBB.ZMin + 2.0), z_finish_step=0.0, final_depth=baseBB.ZMin, - user_depths=None) - env = PathUtils.getEnvelope(partshape=base_shape, subshape=None, depthparams=depthparams) + user_depths=None, + ) + env = PathUtils.getEnvelope( + partshape=base_shape, subshape=None, depthparams=depthparams + ) # Get top face(s) of envelope at face height rawList = list() for f in env.Faces: @@ -589,7 +648,9 @@ def getWaterlineFace(base_shape, face): rawList.append(f) # make compound and extrude downward rawComp = Part.makeCompound(rawList) - rawCompExtNeg = rawComp.extrude(FreeCAD.Vector(0.0, 0.0, baseBB.ZMin - faceHeight - 1.0)) + rawCompExtNeg = rawComp.extrude( + FreeCAD.Vector(0.0, 0.0, baseBB.ZMin - faceHeight - 1.0) + ) # Cut off bottom of base shape at face height topSolid = base_shape.cut(rawCompExtNeg) diff --git a/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py b/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py index 89d3db6e40..91690ba627 100644 --- a/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py +++ b/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py @@ -33,22 +33,26 @@ from pivy import coin # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader -Part = LazyLoader('Part', globals(), 'Part') + +Part = LazyLoader("Part", globals(), "Part") __title__ = "Path Feature Extensions UI" __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" __doc__ = "Extensions feature page controller." + def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -#PathLog.trackModule(PathLog.thisModule()) +# PathLog.trackModule(PathLog.thisModule()) + class _Extension(object): - ColourEnabled = (1.0, .5, 1.0) - ColourDisabled = (1.0, 1.0, .5) + ColourEnabled = (1.0, 0.5, 1.0) + ColourDisabled = (1.0, 1.0, 0.5) TransparencySelected = 0.0 TransparencyDeselected = 0.7 @@ -152,7 +156,7 @@ class _Extension(object): if self.switch: self.switch.whichChild = coin.SO_SWITCH_NONE - def enable(self, ena = True): + def enable(self, ena=True): if ena: self.material.diffuseColor = self.ColourEnabled else: @@ -173,10 +177,10 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): DataSwitch = QtCore.Qt.ItemDataRole.UserRole + 2 Direction = { - FeatureExtensions.Extension.DirectionNormal: translate('PathPocket', 'Normal'), - FeatureExtensions.Extension.DirectionX: translate('PathPocket', 'X'), - FeatureExtensions.Extension.DirectionY: translate('PathPocket', 'Y') - } + FeatureExtensions.Extension.DirectionNormal: translate("PathPocket", "Normal"), + FeatureExtensions.Extension.DirectionX: translate("PathPocket", "X"), + FeatureExtensions.Extension.DirectionY: translate("PathPocket", "Y"), + } def initPage(self, obj): self.setTitle("Extensions") @@ -193,17 +197,21 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): self.extensions = list() - self.defaultLength = PathGui.QuantitySpinBox(self.form.defaultLength, obj, 'ExtensionLengthDefault') # pylint: disable=attribute-defined-outside-init + self.defaultLength = PathGui.QuantitySpinBox( + self.form.defaultLength, obj, "ExtensionLengthDefault" + ) # pylint: disable=attribute-defined-outside-init self.form.extensionTree.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.form.extensionTree.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.switch = coin.SoSwitch() # pylint: disable=attribute-defined-outside-init + self.switch = coin.SoSwitch() # pylint: disable=attribute-defined-outside-init self.obj.ViewObject.RootNode.addChild(self.switch) self.switch.whichChild = coin.SO_SWITCH_ALL - self.model = QtGui.QStandardItemModel(self.form.extensionTree) # pylint: disable=attribute-defined-outside-init - self.model.setHorizontalHeaderLabels(['Base', 'Extension']) + self.model = QtGui.QStandardItemModel( + self.form.extensionTree + ) # pylint: disable=attribute-defined-outside-init + self.model.setHorizontalHeaderLabels(["Base", "Extension"]) """ # russ4262: This `if` block shows all available extensions upon edit of operation with any extension enabled. @@ -216,7 +224,7 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): """ self.form.showExtensions.setCheckState(QtCore.Qt.Unchecked) - self.blockUpdateData = False # pylint: disable=attribute-defined-outside-init + self.blockUpdateData = False # pylint: disable=attribute-defined-outside-init def cleanupPage(self, obj): try: @@ -243,29 +251,33 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): def currentExtensions(self): PathLog.debug("currentExtensions()") extensions = [] + def extractExtension(item, ext): if ext and ext.edge and item.checkState() == QtCore.Qt.Checked: extensions.append(ext.ext) + if self.form.enableExtensions.isChecked(): self.forAllItemsCall(extractExtension) - PathLog.track('extensions', extensions) + PathLog.track("extensions", extensions) return extensions def updateProxyExtensions(self, obj): PathLog.debug("updateProxyExtensions()") - self.extensions = self.currentExtensions() # pylint: disable=attribute-defined-outside-init + self.extensions = ( + self.currentExtensions() + ) # pylint: disable=attribute-defined-outside-init FeatureExtensions.setExtensions(obj, self.extensions) def getFields(self, obj): PathLog.track(obj.Label, self.model.rowCount(), self.model.columnCount()) - self.blockUpdateData = True # pylint: disable=attribute-defined-outside-init + self.blockUpdateData = True # pylint: disable=attribute-defined-outside-init if obj.ExtensionCorners != self.form.extendCorners.isChecked(): obj.ExtensionCorners = self.form.extendCorners.isChecked() self.defaultLength.updateProperty() self.updateProxyExtensions(obj) - self.blockUpdateData = False # pylint: disable=attribute-defined-outside-init + self.blockUpdateData = False # pylint: disable=attribute-defined-outside-init def setFields(self, obj): PathLog.track(obj.Label) @@ -285,7 +297,9 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): Subroutine called inside `setFields()` to initialize Extensions efficiently.""" if self.enabled: self.extensions = FeatureExtensions.getExtensions(obj) - elif len(obj.ExtensionFeature) > 0: # latter test loads pre-existing extensions (editing of existing operation) + elif ( + len(obj.ExtensionFeature) > 0 + ): # latter test loads pre-existing extensions (editing of existing operation) noEdges = True for (__, __, subFeat) in FeatureExtensions.readObjExtensionFeature(obj): if subFeat.startswith("Edge") or subFeat.startswith("Wire"): @@ -311,7 +325,9 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): self._enableExtensions() # Recalculate extensions def createItemForBaseModel(self, base, sub, edges, extensions): - PathLog.track(base.Label, sub, '+', len(edges), len(base.Shape.getElement(sub).Edges)) + PathLog.track( + base.Label, sub, "+", len(edges), len(base.Shape.getElement(sub).Edges) + ) # PathLog.debug("createItemForBaseModel() label: {}, sub: {}, {}, edgeCnt: {}, subEdges: {}".format(base.Label, sub, '+', len(edges), len(base.Shape.getElement(sub).Edges))) extendCorners = self.form.extendCorners.isChecked() @@ -341,7 +357,7 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): extensionEdges = {} if includeEdges: - if self.useOutline == 1 and sub.startswith('Face'): + if self.useOutline == 1 and sub.startswith("Face"): # Only show exterior extensions if `Use Outline` is True subEdges = subShape.Wires[0].Edges else: @@ -358,26 +374,48 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): createSubItem(label, ext1) if extendCorners and includeEdges: + def edgesMatchShape(e0, e1): flipped = PathGeom.flipEdge(e1) if flipped: - return PathGeom.edgesMatch(e0, e1) or PathGeom.edgesMatch(e0, flipped) + return PathGeom.edgesMatch(e0, e1) or PathGeom.edgesMatch( + e0, flipped + ) else: return PathGeom.edgesMatch(e0, e1) self.extensionEdges = extensionEdges PathLog.debug("extensionEdges.values(): {}".format(extensionEdges.values())) - for edgeList in Part.sortEdges(list(extensionEdges.keys())): # Identify connected edges that form wires + for edgeList in Part.sortEdges( + list(extensionEdges.keys()) + ): # Identify connected edges that form wires self.edgeList = edgeList if len(edgeList) == 1: - label = "Edge%s" % [extensionEdges[keyEdge] for keyEdge in extensionEdges.keys() if edgesMatchShape(keyEdge, edgeList[0])][0] + label = ( + "Edge%s" + % [ + extensionEdges[keyEdge] + for keyEdge in extensionEdges.keys() + if edgesMatchShape(keyEdge, edgeList[0]) + ][0] + ) else: - label = "Wire(%s)" % ','.join(sorted([extensionEdges[keyEdge] for e in edgeList for keyEdge in extensionEdges.keys() if edgesMatchShape(e, keyEdge)], key=lambda s: int(s))) # pylint: disable=unnecessary-lambda + label = "Wire(%s)" % ",".join( + sorted( + [ + extensionEdges[keyEdge] + for e in edgeList + for keyEdge in extensionEdges.keys() + if edgesMatchShape(e, keyEdge) + ], + key=lambda s: int(s), + ) + ) # pylint: disable=unnecessary-lambda ext2 = self._cachedExtension(self.obj, base, sub, label) createSubItem(label, ext2) # Only add these subItems for horizontally oriented faces, not edges or vertical faces (from vertical face loops) - if sub.startswith('Face') and PathGeom.isHorizontal(subShape): + if sub.startswith("Face") and PathGeom.isHorizontal(subShape): # Add entry to extend outline of face label = "Extend_" + sub ext3 = self._cachedExtension(self.obj, base, sub, label) @@ -406,8 +444,11 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): self.form.extensionTree.blockSignals(True) # remember current visual state - if hasattr(self, 'selectionModel'): - selectedExtensions = [self.model.itemFromIndex(index).data(self.DataObject).ext for index in self.selectionModel.selectedIndexes()] + if hasattr(self, "selectionModel"): + selectedExtensions = [ + self.model.itemFromIndex(index).data(self.DataObject).ext + for index in self.selectionModel.selectedIndexes() + ] else: selectedExtensions = [] collapsedModels = [] @@ -420,7 +461,9 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): for featureRow in range(model.rowCount()): feature = model.child(featureRow, 0) if not self.form.extensionTree.isExpanded(feature.index()): - collapsedFeatures.append("%s.%s" % (modelName, feature.data(QtCore.Qt.EditRole))) + collapsedFeatures.append( + "%s.%s" % (modelName, feature.data(QtCore.Qt.EditRole)) + ) # remove current extensions and all their visuals def removeItemSwitch(item, ext): @@ -428,6 +471,7 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): ext.hide() if ext.root: self.switch.removeChild(ext.root) + self.forAllItemsCall(removeItemSwitch) self.model.clear() @@ -435,14 +479,19 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): if self.enabled: for base in self.obj.Base: show = False - edges = [(edge, "Edge%d" % (i + 1)) for i, edge in enumerate(base[0].Shape.Edges)] + edges = [ + (edge, "Edge%d" % (i + 1)) + for i, edge in enumerate(base[0].Shape.Edges) + ] baseItem = QtGui.QStandardItem() baseItem.setData(base[0].Label, QtCore.Qt.EditRole) baseItem.setSelectable(False) for sub in sorted(base[1]): - if sub.startswith('Face'): + if sub.startswith("Face"): show = True - baseItem.appendRow(self.createItemForBaseModel(base[0], sub, edges, extensions)) + baseItem.appendRow( + self.createItemForBaseModel(base[0], sub, edges, extensions) + ) if show: self.model.appendRow(baseItem) @@ -458,10 +507,10 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): self.form.extensionTree.setExpanded(model.index(), False) for featureRow in range(model.rowCount()): feature = model.child(featureRow, 0) - featureName = "%s.%s" % (modelName, feature.data(QtCore.Qt.EditRole)) + featureName = "%s.%s" % (modelName, feature.data(QtCore.Qt.EditRole)) if featureName in collapsedFeatures: self.form.extensionTree.setExpanded(feature.index(), False) - if hasattr(self, 'selectionModel') and selectedExtensions: + if hasattr(self, "selectionModel") and selectedExtensions: self.restoreSelection(selectedExtensions) self.form.extensionTree.blockSignals(False) @@ -475,22 +524,22 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): if not self.blockUpdateData: if self.fieldsSet: if self.form.enableExtensions.isChecked(): - if prop == 'ExtensionLengthDefault': - self.updateQuantitySpinBoxes() - elif prop == 'Base': - self.extensionsReady = False - self.setExtensions(FeatureExtensions.getExtensions(obj)) - elif prop == 'UseOutline': - self._getUseOutlineState() # Find `useOutline` checkbox and get its boolean value - self._includeEdgesAndWires() - elif prop == 'Base': + if prop == "ExtensionLengthDefault": + self.updateQuantitySpinBoxes() + elif prop == "Base": self.extensionsReady = False + self.setExtensions(FeatureExtensions.getExtensions(obj)) + elif prop == "UseOutline": + self._getUseOutlineState() # Find `useOutline` checkbox and get its boolean value + self._includeEdgesAndWires() + elif prop == "Base": + self.extensionsReady = False def restoreSelection(self, selection): PathLog.debug("restoreSelection()") PathLog.track() if 0 == self.model.rowCount(): - PathLog.track('-') + PathLog.track("-") self.form.buttonClear.setEnabled(False) self.form.buttonDisable.setEnabled(False) self.form.buttonEnable.setEnabled(False) @@ -515,7 +564,9 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): def setSelectionVisuals(item, ext): if selectItem(item, ext): - self.selectionModel.select(item.index(), QtCore.QItemSelectionModel.Select) + self.selectionModel.select( + item.index(), QtCore.QItemSelectionModel.Select + ) selected = self.selectionModel.isSelected(item.index()) if selected: @@ -528,6 +579,7 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): ext.show() else: ext.hide() + self.forAllItemsCall(setSelectionVisuals) def selectionChanged(self): @@ -536,6 +588,7 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): def extensionsClear(self): PathLog.debug("extensionsClear()") + def disableItem(item, ext): item.setCheckState(QtCore.Qt.Unchecked) ext.disable() @@ -572,16 +625,20 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): def showHideExtension(self): if self.form.showExtensions.isChecked(): + def enableExtensionEdit(item, ext): # pylint: disable=unused-argument ext.show() + self.forAllItemsCall(enableExtensionEdit) else: + def disableExtensionEdit(item, ext): if not self.selectionModel.isSelected(item.index()): ext.hide() + self.forAllItemsCall(disableExtensionEdit) - #self.setDirty() + # self.setDirty() def toggleExtensionCorners(self): PathLog.debug("toggleExtensionCorners()") @@ -612,7 +669,9 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): self.model.itemChanged.connect(self.updateItemEnabled) - self.selectionModel = self.form.extensionTree.selectionModel() # pylint: disable=attribute-defined-outside-init + self.selectionModel = ( + self.form.extensionTree.selectionModel() + ) # pylint: disable=attribute-defined-outside-init self.selectionModel.selectionChanged.connect(self.selectionChanged) self.selectionChanged() @@ -626,12 +685,14 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): if self.useOutlineCheckbox: self.useOutline = self.useOutlineCheckbox.isChecked() - if hasattr(self, 'parent'): - parent = getattr(self, 'parent') - if parent and hasattr(parent, 'featurePages'): + if hasattr(self, "parent"): + parent = getattr(self, "parent") + if parent and hasattr(parent, "featurePages"): for page in parent.featurePages: - if hasattr(page, 'panelTitle'): - if page.panelTitle == 'Operation' and hasattr(page.form, 'useOutline'): + if hasattr(page, "panelTitle"): + if page.panelTitle == "Operation" and hasattr( + page.form, "useOutline" + ): PathLog.debug("Found useOutline checkbox") self.useOutlineCheckbox = page.form.useOutline if page.form.useOutline.isChecked(): @@ -669,10 +730,14 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): self.form.includeEdges.blockSignals(True) # Make changes to form - msg = translate("PathPocketShape", - "Edge count greater than threshold of" + " " + - str(self.edgeCountThreshold) + ": " + - str(self.initialEdgeCount)) + msg = translate( + "PathPocketShape", + "Edge count greater than threshold of" + + " " + + str(self.edgeCountThreshold) + + ": " + + str(self.initialEdgeCount), + ) self.form.enableExtensionsWarning.setText(msg) self.form.enableExtensions.setChecked(False) self.form.enableExtensionsWarning.show() @@ -763,6 +828,8 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage): reset[k] = self.extensionsCache[k] self.extensionsCache = reset self.extensionsReady = False + + # Eclass FreeCAD.Console.PrintLog("Loading PathFeatureExtensionsGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathJobCmd.py b/src/Mod/Path/PathScripts/PathJobCmd.py index a3b26ac128..0e4ea2607c 100644 --- a/src/Mod/Path/PathScripts/PathJobCmd.py +++ b/src/Mod/Path/PathScripts/PathJobCmd.py @@ -44,20 +44,24 @@ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) class CommandJobCreate: - ''' + """ Command used to create a command. When activated the command opens a dialog allowing the user to select a base object (has to be a solid) and a template to be used for the initial creation. - ''' + """ def __init__(self): pass def GetResources(self): - return {'Pixmap': 'Path_Job', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Job", "Job"), - 'Accel': "P, J", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Job", "Creates a Path Job object")} + return { + "Pixmap": "Path_Job", + "MenuText": QtCore.QT_TRANSLATE_NOOP("Path_Job", "Job"), + "Accel": "P, J", + "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "Path_Job", "Creates a Path Job object" + ), + } def IsActive(self): return FreeCAD.ActiveDocument is not None @@ -74,29 +78,35 @@ class CommandJobCreate: @classmethod def Execute(cls, base, template): - FreeCADGui.addModule('PathScripts.PathJobGui') + FreeCADGui.addModule("PathScripts.PathJobGui") if template: template = "'%s'" % template else: - template = 'None' - FreeCADGui.doCommand('PathScripts.PathJobGui.Create(%s, %s)' % ([o.Name for o in base], template)) + template = "None" + FreeCADGui.doCommand( + "PathScripts.PathJobGui.Create(%s, %s)" % ([o.Name for o in base], template) + ) class CommandJobTemplateExport: - ''' + """ Command to export a template of a given job. Opens a dialog to select the file to store the template in. If the template is stored in Path's file path (see preferences) and named in accordance with job_*.json it will automatically be found on Job creation and be available for selection. - ''' + """ def __init__(self): pass def GetResources(self): - return {'Pixmap': 'Path_ExportTemplate', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Job", "Export Template"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Job", "Exports Path Job as a template to be used for other jobs")} + return { + "Pixmap": "Path_ExportTemplate", + "MenuText": QtCore.QT_TRANSLATE_NOOP("Path_Job", "Export Template"), + "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "Path_Job", "Exports Path Job as a template to be used for other jobs" + ), + } def GetJob(self): # if there's only one Job in the document ... @@ -109,7 +119,7 @@ class CommandJobTemplateExport: sel = FreeCADGui.Selection.getSelection() if len(sel) == 1: job = sel[0] - if hasattr(job, 'Proxy') and isinstance(job.Proxy, PathJob.ObjectJob): + if hasattr(job, "Proxy") and isinstance(job.Proxy, PathJob.ObjectJob): return job return None @@ -124,15 +134,17 @@ class CommandJobTemplateExport: @classmethod def SaveDialog(cls, job, dialog): - foo = QtGui.QFileDialog.getSaveFileName(QtGui.QApplication.activeWindow(), - "Path - Job Template", - PathPreferences.filePath(), - "job_*.json")[0] + foo = QtGui.QFileDialog.getSaveFileName( + QtGui.QApplication.activeWindow(), + "Path - Job Template", + PathPreferences.filePath(), + "job_*.json", + )[0] if foo: - if not os.path.basename(foo).startswith('job_'): - foo = os.path.join(os.path.dirname(foo), 'job_' + os.path.basename(foo)) - if not foo.endswith('.json'): - foo = foo + '.json' + if not os.path.basename(foo).startswith("job_"): + foo = os.path.join(os.path.dirname(foo), "job_" + os.path.basename(foo)) + if not foo.endswith(".json"): + foo = foo + ".json" cls.Execute(job, foo, dialog) @classmethod @@ -155,7 +167,11 @@ class CommandJobTemplateExport: stockAttrs = None if dialog: if dialog.includeStock(): - stockAttrs = PathStock.TemplateAttributes(job.Stock, dialog.includeStockExtent(), dialog.includeStockPlacement()) + stockAttrs = PathStock.TemplateAttributes( + job.Stock, + dialog.includeStockExtent(), + dialog.includeStockPlacement(), + ) else: stockAttrs = PathStock.TemplateAttributes(job.Stock) if stockAttrs: @@ -169,7 +185,8 @@ class CommandJobTemplateExport: dialog.includeSettingCoolant(), dialog.includeSettingOperationHeights(), dialog.includeSettingOperationDepths(), - dialog.includeSettingOpsSettings()) + dialog.includeSettingOpsSettings(), + ) else: setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(True, True, True) if setupSheetAttrs: @@ -177,13 +194,13 @@ class CommandJobTemplateExport: encoded = job.Proxy.setupSheet.encodeTemplateAttributes(attrs) # write template - with open(PathUtil.toUnicode(path), 'w') as fp: + with open(PathUtil.toUnicode(path), "w") as fp: json.dump(encoded, fp, sort_keys=True, indent=2) if FreeCAD.GuiUp: # register the FreeCAD command - FreeCADGui.addCommand('Path_Job', CommandJobCreate()) - FreeCADGui.addCommand('Path_ExportTemplate', CommandJobTemplateExport()) + FreeCADGui.addCommand("Path_Job", CommandJobCreate()) + FreeCADGui.addCommand("Path_ExportTemplate", CommandJobTemplateExport()) FreeCAD.Console.PrintLog("Loading PathJobCmd... done\n") diff --git a/src/Mod/Path/PathScripts/PathJobDlg.py b/src/Mod/Path/PathScripts/PathJobDlg.py index 3a87af21bf..cd15adf863 100644 --- a/src/Mod/Path/PathScripts/PathJobDlg.py +++ b/src/Mod/Path/PathScripts/PathJobDlg.py @@ -43,7 +43,6 @@ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) class _ItemDelegate(QtGui.QStyledItemDelegate): - def __init__(self, controller, parent): self.controller = controller QtGui.QStyledItemDelegate.__init__(self, parent) @@ -54,15 +53,16 @@ class _ItemDelegate(QtGui.QStyledItemDelegate): self.controller.setupColumnEditor(index, editor) return editor + class JobCreate: DataObject = QtCore.Qt.ItemDataRole.UserRole def __init__(self, parent=None, sel=None): # pylint: disable=unused-argument self.dialog = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobCreate.ui") - self.itemsSolid = QtGui.QStandardItem(translate('PathJob', 'Solids')) - self.items2D = QtGui.QStandardItem(translate('PathJob', '2D')) - self.itemsJob = QtGui.QStandardItem(translate('PathJob', 'Jobs')) + self.itemsSolid = QtGui.QStandardItem(translate("PathJob", "Solids")) + self.items2D = QtGui.QStandardItem(translate("PathJob", "2D")) + self.itemsJob = QtGui.QStandardItem(translate("PathJob", "Jobs")) self.dialog.templateGroup.hide() self.dialog.modelGroup.hide() # debugging support @@ -74,27 +74,40 @@ class JobCreate: def setupTitle(self, title): self.dialog.setWindowTitle(title) - def setupModel(self, job = None): + def setupModel(self, job=None): if job: - preSelected = Counter([PathUtil.getPublicObject(job.Proxy.baseObject(job, obj)).Label for obj in job.Model.Group]) + preSelected = Counter( + [ + PathUtil.getPublicObject(job.Proxy.baseObject(job, obj)).Label + for obj in job.Model.Group + ] + ) jobResources = job.Model.Group + [job.Stock] else: - preSelected = Counter([obj.Label for obj in FreeCADGui.Selection.getSelection()]) + preSelected = Counter( + [obj.Label for obj in FreeCADGui.Selection.getSelection()] + ) jobResources = [] - self.candidates = sorted(PathJob.ObjectJob.baseCandidates(), key=lambda o: o.Label) + self.candidates = sorted( + PathJob.ObjectJob.baseCandidates(), key=lambda o: o.Label + ) # If there is only one possibility we might as well make sure it's selected if not preSelected and 1 == len(self.candidates): preSelected = Counter([self.candidates[0].Label]) expandSolids = False - expand2Ds = False - expandJobs = False + expand2Ds = False + expandJobs = False for base in self.candidates: - if not base in jobResources and not PathJob.isResourceClone(job, base, None) and not hasattr(base, 'StockType'): + if ( + not base in jobResources + and not PathJob.isResourceClone(job, base, None) + and not hasattr(base, "StockType") + ): item0 = QtGui.QStandardItem() item1 = QtGui.QStandardItem() @@ -149,7 +162,7 @@ class JobCreate: self.delegate = _ItemDelegate(self, self.dialog.modelTree) self.model = QtGui.QStandardItemModel(self.dialog) - self.model.setHorizontalHeaderLabels(['Model', 'Count']) + self.model.setHorizontalHeaderLabels(["Model", "Count"]) if self.itemsSolid.hasChildren(): self.model.appendRow(self.itemsSolid) @@ -213,7 +226,9 @@ class JobCreate: def setupTemplate(self): templateFiles = [] for path in PathPreferences.searchPaths(): - cleanPaths = [f.replace("\\", "/") for f in self.templateFilesIn(path)] # Standardize slashes used across os platforms + cleanPaths = [ + f.replace("\\", "/") for f in self.templateFilesIn(path) + ] # Standardize slashes used across os platforms templateFiles.extend(cleanPaths) template = {} @@ -229,7 +244,7 @@ class JobCreate: template[name] = tFile selectTemplate = PathPreferences.defaultJobTemplate() index = 0 - self.dialog.jobTemplate.addItem('', '') + self.dialog.jobTemplate.addItem("", "") for name in sorted(template.keys()): if template[name] == selectTemplate: index = self.dialog.jobTemplate.count() @@ -238,16 +253,18 @@ class JobCreate: self.dialog.templateGroup.show() def templateFilesIn(self, path): - '''templateFilesIn(path) ... answer all file in the given directory which fit the job template naming convention. - PathJob template files are name job_*.json''' + """templateFilesIn(path) ... answer all file in the given directory which fit the job template naming convention. + PathJob template files are name job_*.json""" PathLog.track(path) - return glob.glob(path + '/job_*.json') + return glob.glob(path + "/job_*.json") def getModels(self): models = [] for i in range(self.itemsSolid.rowCount()): - for j in range(self.itemsSolid.child(i, 1).data(QtCore.Qt.EditRole)): # pylint: disable=unused-variable + for j in range( + self.itemsSolid.child(i, 1).data(QtCore.Qt.EditRole) + ): # pylint: disable=unused-variable models.append(self.itemsSolid.child(i).data(self.DataObject)) for i in range(self.items2D.rowCount()): @@ -259,12 +276,14 @@ class JobCreate: # Note that we do want to use the models (resource clones) of the # source job as base objects for the new job in order to get the # identical placement, and anything else that's been customized. - models.extend(self.itemsJob.child(i, 0).data(self.DataObject).Model.Group) + models.extend( + self.itemsJob.child(i, 0).data(self.DataObject).Model.Group + ) return models def getTemplate(self): - '''answer the file name of the template to be assigned''' + """answer the file name of the template to be assigned""" return self.dialog.jobTemplate.itemData(self.dialog.jobTemplate.currentIndex()) def exec_(self): @@ -298,24 +317,44 @@ class JobTemplateExport: def updateUI(self): job = self.job if job.PostProcessor: - ppHint = "%s %s %s" % (job.PostProcessor, job.PostProcessorArgs, job.PostProcessorOutputFile) + ppHint = "%s %s %s" % ( + job.PostProcessor, + job.PostProcessorArgs, + job.PostProcessorOutputFile, + ) self.dialog.postProcessingHint.setText(ppHint) else: self.dialog.postProcessingGroup.setEnabled(False) self.dialog.postProcessingGroup.setChecked(False) - if job.Stock and not PathJob.isResourceClone(job, 'Stock', 'Stock'): + if job.Stock and not PathJob.isResourceClone(job, "Stock", "Stock"): stockType = PathStock.StockType.FromStock(job.Stock) if stockType == PathStock.StockType.FromBase: - seHint = translate('PathJob', "Base -/+ %.2f/%.2f %.2f/%.2f %.2f/%.2f") % (job.Stock.ExtXneg, job.Stock.ExtXpos, job.Stock.ExtYneg, job.Stock.ExtYpos, job.Stock.ExtZneg, job.Stock.ExtZpos) + seHint = translate( + "PathJob", "Base -/+ %.2f/%.2f %.2f/%.2f %.2f/%.2f" + ) % ( + job.Stock.ExtXneg, + job.Stock.ExtXpos, + job.Stock.ExtYneg, + job.Stock.ExtYpos, + job.Stock.ExtZneg, + job.Stock.ExtZpos, + ) self.dialog.stockPlacement.setChecked(False) elif stockType == PathStock.StockType.CreateBox: - seHint = translate('PathJob', "Box: %.2f x %.2f x %.2f") % (job.Stock.Length, job.Stock.Width, job.Stock.Height) + seHint = translate("PathJob", "Box: %.2f x %.2f x %.2f") % ( + job.Stock.Length, + job.Stock.Width, + job.Stock.Height, + ) elif stockType == PathStock.StockType.CreateCylinder: - seHint = translate('PathJob', "Cylinder: %.2f x %.2f") % (job.Stock.Radius, job.Stock.Height) + seHint = translate("PathJob", "Cylinder: %.2f x %.2f") % ( + job.Stock.Radius, + job.Stock.Height, + ) else: - seHint = '-' - PathLog.error(translate('PathJob', 'Unsupported stock type')) + seHint = "-" + PathLog.error(translate("PathJob", "Unsupported stock type")) self.dialog.stockExtentHint.setText(seHint) spHint = "%s" % job.Stock.Placement self.dialog.stockPlacementHint.setText(spHint) @@ -325,7 +364,13 @@ class JobTemplateExport: heightsChanged = not job.SetupSheet.Proxy.hasDefaultOperationHeights() coolantChanged = not job.SetupSheet.Proxy.hasDefaultCoolantMode() opsWithSettings = job.SetupSheet.Proxy.operationsWithSettings() - settingsChanged = rapidChanged or depthsChanged or heightsChanged or coolantChanged or 0 != len(opsWithSettings) + settingsChanged = ( + rapidChanged + or depthsChanged + or heightsChanged + or coolantChanged + or 0 != len(opsWithSettings) + ) self.dialog.settingsGroup.setChecked(settingsChanged) self.dialog.settingToolRapid.setChecked(rapidChanged) self.dialog.settingOperationDepths.setChecked(depthsChanged) @@ -346,7 +391,11 @@ class JobTemplateExport: self.dialog.toolsList.addItem(item) def checkUncheckTools(self): - state = QtCore.Qt.CheckState.Checked if self.dialog.toolsGroup.isChecked() else QtCore.Qt.CheckState.Unchecked + state = ( + QtCore.Qt.CheckState.Checked + if self.dialog.toolsGroup.isChecked() + else QtCore.Qt.CheckState.Unchecked + ) for i in range(self.dialog.toolsList.count()): self.dialog.toolsList.item(i).setCheckState(state) From 1683a7292d0f628c779b30f1ea2d6876b2d8cf2b Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 24 Jan 2022 15:10:05 -0600 Subject: [PATCH 2/6] Job translation cleanup --- src/Mod/Path/Gui/Resources/panels/PathEdit.ui | 45 ++---- src/Mod/Path/PathScripts/PathJob.py | 143 ++++++++++++------ src/Mod/Path/PathScripts/PathJobCmd.py | 26 ++-- src/Mod/Path/PathScripts/PathJobDlg.py | 32 ++-- src/Mod/Path/PathScripts/PathJobGui.py | 67 ++++---- 5 files changed, 179 insertions(+), 134 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/PathEdit.ui b/src/Mod/Path/Gui/Resources/panels/PathEdit.ui index fbcba83956..2f5d02dbf2 100644 --- a/src/Mod/Path/Gui/Resources/panels/PathEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PathEdit.ui @@ -31,8 +31,8 @@ 0 0 - 146 - 378 + 561 + 675 @@ -112,8 +112,8 @@ 0 0 - 96 - 26 + 98 + 28 @@ -205,21 +205,6 @@ <html><head/><body><p>Ordering by Fixture, will cause all operations to be performed in the first coordinate system before switching to the second. Then all operations will be performed there in the same order.</p><p>This is useful if the operator can safely load work into one coordinate system while the machine is doing work in another.</p><p>Ordering by Tool, will minimize the Tool Changes. A tool change will be done, then all operations in all coordinate systems before changing tools.</p><p>Ordering by operation will do each operation in all coordinate systems before moving to the next operation. This is especially useful in conjunction with the 'split output' even with only a single work coordinate system since it will put each operation into a separate file</p></body></html> - - - Fixture - - - - - Tool - - - - - Operation - - @@ -251,7 +236,7 @@ - <html><head/><body><p><span style=" font-style:italic;">Work Coordinate Systems</span> also called <span style=" font-style:italic;">Work Offsets</span>, <span style=" font-style:italic;">Fixture Offsets</span>, or <span style=" font-style:italic;">Fixtures </span>are useful for building efficient production jobs where the same part is done many times on the machine.</p><p>FreeCAD has no knowledge of where a particular coordinate system exists within the machine coordinate system so adding additional coordinate systems to your job will have no visual change within your job. It will, however, change your gcode output. The exact way in which the output is affected is controlled by the 'order by' setting.</p></body></html> + <html><head/><body><p><span style=" font-style:italic;">Work Coordinate Systems</span> also called <span style=" font-style:italic;">Work Offsets</span>, <span style=" font-style:italic;">Fixture Offsets</span>, or <span style=" font-style:italic;">Fixtures </span>are useful for building efficient production jobs where the same part is done many times on the machine.</p><p>FreeCAD has no knowledge of where a particular coordinate system exists within the machine coordinate system so adding additional coordinate systems to your job will have no visual change within your job. It will, however, change your gcode output. The exact way in which the output is affected is controlled by the 'order by' setting.</p></body></html> QListView::Adjust @@ -404,7 +389,7 @@ <html><head/><body><p>If multiple coordinate systems are in use, setting this to TRUE will cause the gcode to be written to multiple output files as controlled by the 'order by' property. For example, if ordering by Fixture, the first output file will be for the first fixture and separate file for the second.</p><p><br/></p><p><br/></p></body></html> - <html><head/><body><p>If True, post-processing will create multiple output files based on the <span style=" font-style:italic;">order by</span> setting.</p><p><br/></p><p>For example, if <span style=" font-style:italic;">order by</span> is set to Tool, the first output file will contain the first tool change and all operations, in all coordinate systems, that can be done with that tool before the next tool change is called.</p><p><br/></p><p>If <span style=" font-style:italic;">order by</span> is set to <span style=" font-style:italic;">operation</span> and <span style=" font-style:italic;">split output</span> is true, each operation will be written to a separate file.</p></body></html> + <html><head/><body><p>If True, post-processing will create multiple output files based on the <span style=" font-style:italic;">order by</span> setting.</p><p><br/></p><p>For example, if <span style=" font-style:italic;">order by</span> is set to Tool, the first output file will contain the first tool change and all operations, in all coordinate systems, that can be done with that tool before the next tool change is called.</p><p><br/></p><p>If <span style=" font-style:italic;">order by</span> is set to <span style=" font-style:italic;">operation</span> and <span style=" font-style:italic;">split output</span> is true, each operation will be written to a separate file.</p></body></html> Split Output @@ -424,15 +409,15 @@ - 0 + 1 0 0 - 545 - 896 + 548 + 941 @@ -1002,8 +987,8 @@ 0 0 - 213 - 321 + 561 + 675 @@ -1185,8 +1170,8 @@ 0 0 - 317 - 173 + 561 + 675 @@ -1285,8 +1270,8 @@ 0 0 - 138 - 112 + 151 + 119 diff --git a/src/Mod/Path/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py index 5f21da0c40..72d1085c9d 100644 --- a/src/Mod/Path/PathScripts/PathJob.py +++ b/src/Mod/Path/PathScripts/PathJob.py @@ -20,6 +20,9 @@ # * * # *************************************************************************** +from PathScripts.PathPostProcessor import PostProcessor +from PySide import QtCore +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences @@ -29,8 +32,7 @@ import PathScripts.PathToolController as PathToolController import PathScripts.PathUtil as PathUtil import json import time -from PathScripts.PathPostProcessor import PostProcessor -from PySide import QtCore + # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader @@ -38,12 +40,13 @@ from lazy_loader.lazy_loader import LazyLoader Draft = LazyLoader("Draft", globals(), "Draft") -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) - -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate class JobTemplate: @@ -111,34 +114,35 @@ class ObjectJob: "App::PropertyFile", "PostProcessorOutputFile", "Output", - QtCore.QT_TRANSLATE_NOOP("PathJob", "The NC output file for this project"), + QT_TRANSLATE_NOOP("App::Property", "The NC output file for this project"), ) obj.addProperty( "App::PropertyEnumeration", "PostProcessor", "Output", - QtCore.QT_TRANSLATE_NOOP("PathJob", "Select the Post Processor"), + QT_TRANSLATE_NOOP("App::Property", "Select the Post Processor"), ) obj.addProperty( "App::PropertyString", "PostProcessorArgs", "Output", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "Arguments for the Post Processor (specific to the script)" + QT_TRANSLATE_NOOP( + "App::Property", + "Arguments for the Post Processor (specific to the script)", ), ) obj.addProperty( "App::PropertyString", "LastPostProcessDate", "Output", - QtCore.QT_TRANSLATE_NOOP("PathJob", "Last Time the Job was post-processed"), + QT_TRANSLATE_NOOP("App::Property", "Last Time the Job was post-processed"), ) obj.setEditorMode("LastPostProcessDate", 2) # Hide obj.addProperty( "App::PropertyString", "LastPostProcessOutput", "Output", - QtCore.QT_TRANSLATE_NOOP("PathJob", "Last Time the Job was post-processed"), + QT_TRANSLATE_NOOP("App::Property", "Last Time the Job was post-processed"), ) obj.setEditorMode("LastPostProcessOutput", 2) # Hide @@ -146,21 +150,21 @@ class ObjectJob: "App::PropertyString", "Description", "Path", - QtCore.QT_TRANSLATE_NOOP("PathJob", "An optional description for this job"), + QT_TRANSLATE_NOOP("App::Property", "An optional description for this job"), ) obj.addProperty( "App::PropertyString", "CycleTime", "Path", - QtCore.QT_TRANSLATE_NOOP("PathOp", "Job Cycle Time Estimation"), + QT_TRANSLATE_NOOP("App::Property", "Job Cycle Time Estimation"), ) obj.setEditorMode("CycleTime", 1) # read-only obj.addProperty( "App::PropertyDistance", "GeometryTolerance", "Geometry", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", + QT_TRANSLATE_NOOP( + "App::Property", "For computing Paths; smaller increases accuracy, but slows down computation", ), ) @@ -169,14 +173,14 @@ class ObjectJob: "App::PropertyLink", "Stock", "Base", - QtCore.QT_TRANSLATE_NOOP("PathJob", "Solid object to be used as stock."), + QT_TRANSLATE_NOOP("App::Property", "Solid object to be used as stock."), ) obj.addProperty( "App::PropertyLink", "Operations", "Base", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", + QT_TRANSLATE_NOOP( + "App::Property", "Compound path of all operations in the order they are processed.", ), ) @@ -185,7 +189,7 @@ class ObjectJob: "App::PropertyEnumeration", "JobType", "Base", - QtCore.QT_TRANSLATE_NOOP("PathJob", "Select the Type of Job"), + QT_TRANSLATE_NOOP("App::Property", "Select the Type of Job"), ) obj.setEditorMode("JobType", 2) # Hide @@ -193,30 +197,31 @@ class ObjectJob: "App::PropertyBool", "SplitOutput", "Output", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "Split output into multiple gcode files" + QT_TRANSLATE_NOOP( + "App::Property", "Split output into multiple gcode files" ), ) obj.addProperty( "App::PropertyEnumeration", "OrderOutputBy", "WCS", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "If multiple WCS, order the output this way" + QT_TRANSLATE_NOOP( + "App::Property", "If multiple WCS, order the output this way" ), ) obj.addProperty( "App::PropertyStringList", "Fixtures", "WCS", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "The Work Coordinate Systems for the Job" + QT_TRANSLATE_NOOP( + "App::Property", "The Work Coordinate Systems for the Job" ), ) - obj.OrderOutputBy = ["Fixture", "Tool", "Operation"] + obj.Fixtures = ["G54"] - obj.JobType = ["2D", "2.5D", "Lathe", "Multiaxis"] + for n in self.propertyEnumerations(): + setattr(obj, n[0], n[1]) obj.PostProcessorOutputFile = PathPreferences.defaultOutputFile() obj.PostProcessor = postProcessors = PathPreferences.allEnabledPostProcessors() @@ -236,6 +241,45 @@ class ObjectJob: self.setFromTemplateFile(obj, templateFile) self.setupStock(obj) + @classmethod + def propertyEnumerations(self, dataType="data"): + """propertyEnumerations(dataType="data")... return property enumeration lists of specified dataType. + Args: + dataType = 'data', 'raw', 'translated' + Notes: + 'data' is list of internal string literals used in code + 'raw' is list of (translated_text, data_string) tuples + 'translated' is list of translated string literals + """ + + enums = { + "OrderOutputBy": [ + (translate("Path_Job", "Fixture"), "Fixture"), + (translate("Path_Job", "Tool"), "Tool"), + (translate("Path_Job", "Operation"), "Operation"), + ], + "JobType": [ + (translate("Path_Job", "2D"), "2D"), + (translate("Path_Job", "2.5D"), "2.5D"), + (translate("Path_Job", "Lathe"), "Lathe"), + (translate("Path_Job", "Multiaxis"), "Multiaxis"), + ], + } + + if dataType == "raw": + return enums + + data = list() + idx = 0 if dataType == "translated" else 1 + + PathLog.debug(enums) + + for k, v in enumerate(enums): + data.append((v, [tup[idx] for tup in enums[v]])) + PathLog.debug(data) + + return data + def setupOperations(self, obj): """setupOperations(obj)... setup the Operations group for the Job object.""" ops = FreeCAD.ActiveDocument.addObject( @@ -255,8 +299,8 @@ class ObjectJob: "App::PropertyLink", "SetupSheet", "Base", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "SetupSheet holding the settings for this job" + QT_TRANSLATE_NOOP( + "App::Property", "SetupSheet holding the settings for this job" ), ) obj.SetupSheet = PathSetupSheet.Create() @@ -278,8 +322,8 @@ class ObjectJob: "App::PropertyLink", "Model", "Base", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "The base objects for all operations" + QT_TRANSLATE_NOOP( + "App::Property", "The base objects for all operations" ), ) addModels = True @@ -314,8 +358,8 @@ class ObjectJob: "App::PropertyLink", "Tools", "Base", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "Collection of all tool controllers for the job" + QT_TRANSLATE_NOOP( + "App::Property", "Collection of all tool controllers for the job" ), ) addTable = True @@ -451,7 +495,7 @@ class ObjectJob: "App::PropertyString", "CycleTime", "Path", - QtCore.QT_TRANSLATE_NOOP("PathOp", "Operations Cycle Time Estimation"), + QT_TRANSLATE_NOOP("App::Property", "Operations Cycle Time Estimation"), ) obj.setEditorMode("CycleTime", 1) # read-only @@ -460,8 +504,8 @@ class ObjectJob: "App::PropertyStringList", "Fixtures", "WCS", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "The Work Coordinate Systems for the Job" + QT_TRANSLATE_NOOP( + "App::Property", "The Work Coordinate Systems for the Job" ), ) obj.Fixtures = ["G54"] @@ -471,8 +515,8 @@ class ObjectJob: "App::PropertyEnumeration", "OrderOutputBy", "WCS", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "If multiple WCS, order the output this way" + QT_TRANSLATE_NOOP( + "App::Property", "If multiple WCS, order the output this way" ), ) obj.OrderOutputBy = ["Fixture", "Tool", "Operation"] @@ -482,8 +526,8 @@ class ObjectJob: "App::PropertyBool", "SplitOutput", "Output", - QtCore.QT_TRANSLATE_NOOP( - "PathJob", "Split output into multiple gcode files" + QT_TRANSLATE_NOOP( + "App::Property", "Split output into multiple gcode files" ), ) obj.SplitOutput = False @@ -493,11 +537,12 @@ class ObjectJob: "App::PropertyEnumeration", "JobType", "Base", - QtCore.QT_TRANSLATE_NOOP("PathJob", "Select the Type of Job"), + QT_TRANSLATE_NOOP("App::Property", "Select the Type of Job"), ) obj.setEditorMode("JobType", 2) # Hide - obj.JobType = ["2D", "2.5D", "Lathe", "Multiaxis"] + for n in self.propertyEnumerations(): + setattr(obj, n[0], n[1]) def onChanged(self, obj, prop): if prop == "PostProcessor" and obj.PostProcessor: @@ -577,9 +622,11 @@ class ObjectJob: obj.Tools.Group = tcs else: PathLog.error( - translate("PathJob", "Unsupported PathJob template version %s") - % attrs.get(JobTemplate.Version) + "Unsupported PathJob template version {}".format( + attrs.get(JobTemplate.Version) + ) ) + if not tcs: self.addToolController(PathToolController.Create()) @@ -733,9 +780,7 @@ class ObjectJob: suffix = job.Name[3:] def errorMessage(grp, job): - PathLog.error( - translate("PathJobGui", "{} corrupt in {} job.".format(grp, job.Name)) - ) + PathLog.error("{} corrupt in {} job.".format(grp, job.Name)) if not job.Operations: self.setupOperations(job) diff --git a/src/Mod/Path/PathScripts/PathJobCmd.py b/src/Mod/Path/PathScripts/PathJobCmd.py index 0e4ea2607c..9f20533619 100644 --- a/src/Mod/Path/PathScripts/PathJobCmd.py +++ b/src/Mod/Path/PathScripts/PathJobCmd.py @@ -20,6 +20,8 @@ # * * # *************************************************************************** +from PySide import QtCore, QtGui +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import FreeCADGui import PathScripts.PathJob as PathJob @@ -31,16 +33,14 @@ import PathScripts.PathUtil as PathUtil import json import os -from PySide import QtCore, QtGui +translate = FreeCAD.Qt.translate -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) - - -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule(PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) class CommandJobCreate: @@ -56,9 +56,9 @@ class CommandJobCreate: def GetResources(self): return { "Pixmap": "Path_Job", - "MenuText": QtCore.QT_TRANSLATE_NOOP("Path_Job", "Job"), + "MenuText": QT_TRANSLATE_NOOP("Path_Job", "Job"), "Accel": "P, J", - "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "ToolTip": QT_TRANSLATE_NOOP( "Path_Job", "Creates a Path Job object" ), } @@ -102,9 +102,9 @@ class CommandJobTemplateExport: def GetResources(self): return { "Pixmap": "Path_ExportTemplate", - "MenuText": QtCore.QT_TRANSLATE_NOOP("Path_Job", "Export Template"), - "ToolTip": QtCore.QT_TRANSLATE_NOOP( - "Path_Job", "Exports Path Job as a template to be used for other jobs" + "MenuText": QT_TRANSLATE_NOOP("Path_ExportTemplate", "Export Template"), + "ToolTip": QT_TRANSLATE_NOOP( + "Path_ExportTemplate", "Exports Path Job as a template to be used for other jobs" ), } diff --git a/src/Mod/Path/PathScripts/PathJobDlg.py b/src/Mod/Path/PathScripts/PathJobDlg.py index cd15adf863..10c025b1c6 100644 --- a/src/Mod/Path/PathScripts/PathJobDlg.py +++ b/src/Mod/Path/PathScripts/PathJobDlg.py @@ -20,6 +20,9 @@ # * * # *************************************************************************** +from PySide import QtCore, QtGui +from collections import Counter +import FreeCAD import FreeCADGui import PathScripts.PathJob as PathJob import PathScripts.PathLog as PathLog @@ -29,17 +32,14 @@ import PathScripts.PathUtil as PathUtil import glob import os -from PySide import QtCore, QtGui -from collections import Counter +translate = FreeCAD.Qt.translate -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) - - -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule(PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) class _ItemDelegate(QtGui.QStyledItemDelegate): @@ -60,9 +60,9 @@ class JobCreate: def __init__(self, parent=None, sel=None): # pylint: disable=unused-argument self.dialog = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobCreate.ui") - self.itemsSolid = QtGui.QStandardItem(translate("PathJob", "Solids")) - self.items2D = QtGui.QStandardItem(translate("PathJob", "2D")) - self.itemsJob = QtGui.QStandardItem(translate("PathJob", "Jobs")) + self.itemsSolid = QtGui.QStandardItem(translate("Path_Job", "Solids")) + self.items2D = QtGui.QStandardItem(translate("Path_Job", "2D")) + self.itemsJob = QtGui.QStandardItem(translate("Path_Job", "Jobs")) self.dialog.templateGroup.hide() self.dialog.modelGroup.hide() # debugging support @@ -331,7 +331,7 @@ class JobTemplateExport: stockType = PathStock.StockType.FromStock(job.Stock) if stockType == PathStock.StockType.FromBase: seHint = translate( - "PathJob", "Base -/+ %.2f/%.2f %.2f/%.2f %.2f/%.2f" + "Path_Job", "Base -/+ %.2f/%.2f %.2f/%.2f %.2f/%.2f" ) % ( job.Stock.ExtXneg, job.Stock.ExtXpos, @@ -342,19 +342,19 @@ class JobTemplateExport: ) self.dialog.stockPlacement.setChecked(False) elif stockType == PathStock.StockType.CreateBox: - seHint = translate("PathJob", "Box: %.2f x %.2f x %.2f") % ( + seHint = translate("Path_Job", "Box: %.2f x %.2f x %.2f") % ( job.Stock.Length, job.Stock.Width, job.Stock.Height, ) elif stockType == PathStock.StockType.CreateCylinder: - seHint = translate("PathJob", "Cylinder: %.2f x %.2f") % ( + seHint = translate("Path_Job", "Cylinder: %.2f x %.2f") % ( job.Stock.Radius, job.Stock.Height, ) else: seHint = "-" - PathLog.error(translate("PathJob", "Unsupported stock type")) + PathLog.error(translate("Path_Job", "Unsupported stock type")) self.dialog.stockExtentHint.setText(seHint) spHint = "%s" % job.Stock.Placement self.dialog.stockPlacementHint.setText(spHint) diff --git a/src/Mod/Path/PathScripts/PathJobGui.py b/src/Mod/Path/PathScripts/PathJobGui.py index ff040ce98a..1f3eb6a1e3 100644 --- a/src/Mod/Path/PathScripts/PathJobGui.py +++ b/src/Mod/Path/PathScripts/PathJobGui.py @@ -25,27 +25,25 @@ from PySide import QtCore, QtGui from collections import Counter from contextlib import contextmanager from pivy import coin -import json -import math -import traceback - import FreeCAD import FreeCADGui - +import PathScripts.PathGeom as PathGeom +import PathScripts.PathGuiInit as PathGuiInit import PathScripts.PathJob as PathJob import PathScripts.PathJobCmd as PathJobCmd import PathScripts.PathJobDlg as PathJobDlg -import PathScripts.PathGeom as PathGeom -import PathScripts.PathGuiInit as PathGuiInit import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences import PathScripts.PathSetupSheetGui as PathSetupSheetGui import PathScripts.PathStock as PathStock +import PathScripts.PathToolBitGui as PathToolBitGui import PathScripts.PathToolControllerGui as PathToolControllerGui import PathScripts.PathToolLibraryEditor as PathToolLibraryEditor import PathScripts.PathUtil as PathUtil import PathScripts.PathUtils as PathUtils -import PathScripts.PathToolBitGui as PathToolBitGui +import json +import math +import traceback # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader @@ -54,14 +52,13 @@ Draft = LazyLoader("Draft", globals(), "Draft") Part = LazyLoader("Part", globals(), "Part") DraftVecUtils = LazyLoader("DraftVecUtils", globals(), "DraftVecUtils") +translate = FreeCAD.Qt.translate -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) - - -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule(PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) def _OpenCloseResourceEditor(obj, vobj, edit): @@ -282,7 +279,7 @@ class ViewProvider: PathLog.track() for action in menu.actions(): menu.removeAction(action) - action = QtGui.QAction(translate("Path", "Edit"), menu) + action = QtGui.QAction(translate("Path_Job", "Edit"), menu) action.triggered.connect(self.setEdit) menu.addAction(action) @@ -387,7 +384,7 @@ class StockFromBaseBoundBoxEdit(StockEdit): if self.IsStock(obj): self.getFieldsStock(obj.Stock, fields) else: - PathLog.error(translate("PathJob", "Stock not from Base bound box!")) + PathLog.error("Stock not from Base bound box!") def setFields(self, obj): PathLog.track() @@ -479,7 +476,7 @@ class StockCreateBoxEdit(StockEdit): self.form.stockBoxHeight.text() ) else: - PathLog.error(translate("PathJob", "Stock not a box!")) + PathLog.error("Stock not a box!") except Exception: pass @@ -525,7 +522,7 @@ class StockCreateCylinderEdit(StockEdit): self.form.stockCylinderHeight.text() ) else: - PathLog.error(translate("PathJob", "Stock not a cylinder!")) + PathLog.error(translate("Path_Job", "Stock not a cylinder!")) except Exception: pass @@ -609,7 +606,7 @@ class TaskPanel: DataProperty = QtCore.Qt.ItemDataRole.UserRole + 1 def __init__(self, vobj, deleteOnReject): - FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Edit Job")) + FreeCAD.ActiveDocument.openTransaction("Edit Job") self.vobj = vobj self.vproxy = vobj.Proxy self.obj = vobj.Object @@ -644,6 +641,11 @@ class TaskPanel: self.form.postProcessorArguments.toolTip() ) + # Populate the other comboboxes with enums from the job class + comboToPropertyMap = [("orderBy", "OrderOutputBy")] + enumTups = PathJob.ObjectJob.propertyEnumerations(dataType="raw") + self.populateCombobox(self.form, enumTups, comboToPropertyMap) + self.vproxy.setupEditVisibility(self.obj) self.stockFromBase = None @@ -659,6 +661,21 @@ class TaskPanel: self.obj.SetupSheet, self.form ) + def populateCombobox(self, form, enumTups, comboBoxesPropertyMap): + """fillComboboxes(form, comboBoxesPropertyMap) ... populate comboboxes with translated enumerations + ** comboBoxesPropertyMap will be unnecessary if UI files use strict combobox naming protocol. + Args: + form = UI form + enumTups = list of (translated_text, data_string) tuples + comboBoxesPropertyMap = list of (translated_text, data_string) tuples + """ + # Load appropriate enumerations in each combobox + for cb, prop in comboBoxesPropertyMap: + box = getattr(form, cb) # Get the combobox + box.clear() # clear the combobox + for text, data in enumTups[prop]: # load enumerations + box.addItem(text, data) + def preCleanup(self): PathLog.track() FreeCADGui.Selection.removeObserver(self) @@ -682,9 +699,7 @@ class TaskPanel: FreeCAD.ActiveDocument.abortTransaction() if self.deleteOnReject and FreeCAD.ActiveDocument.getObject(self.name): PathLog.info("Uncreate Job") - FreeCAD.ActiveDocument.openTransaction( - translate("Path_Job", "Uncreate Job") - ) + FreeCAD.ActiveDocument.openTransaction("Uncreate Job") if self.obj.ViewObject.Proxy.onDelete(self.obj.ViewObject, None): FreeCAD.ActiveDocument.removeObject(self.obj.Name) FreeCAD.ActiveDocument.commitTransaction() @@ -1257,7 +1272,7 @@ class TaskPanel: setupFromExisting() else: PathLog.error( - translate("PathJob", "Unsupported stock object %s") + translate("Path_Job", "Unsupported stock object %s") % self.obj.Stock.Label ) else: @@ -1273,7 +1288,7 @@ class TaskPanel: index = -1 else: PathLog.error( - translate("PathJob", "Unsupported stock type %s (%d)") + translate("Path_Job", "Unsupported stock type %s (%d)") % (self.form.stock.currentText(), index) ) self.stockEdit.activate(self.obj, index == -1) @@ -1562,7 +1577,7 @@ def Create(base, template=None): """Create(base, template) ... creates a job instance for the given base object using template to configure it.""" FreeCADGui.addModule("PathScripts.PathJob") - FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job")) + FreeCAD.ActiveDocument.openTransaction("Create Job") try: obj = PathJob.Create("Job", base, template) obj.ViewObject.Proxy = ViewProvider(obj.ViewObject) From fc0963687bfeb2867b1e0629854fdb5e1613e171 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 24 Jan 2022 15:39:11 -0600 Subject: [PATCH 3/6] translation cleanup misc files --- .../PathScripts/PathPreferencesPathDressup.py | 13 ++++---- .../Path/PathScripts/PathProfileContourGui.py | 29 +++++++++-------- .../Path/PathScripts/PathProfileEdgesGui.py | 31 +++++++++++-------- .../Path/PathScripts/PathProfileFacesGui.py | 31 +++++++++++-------- 4 files changed, 59 insertions(+), 45 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathPreferencesPathDressup.py b/src/Mod/Path/PathScripts/PathPreferencesPathDressup.py index 1285546204..ce00ad56e9 100644 --- a/src/Mod/Path/PathScripts/PathPreferencesPathDressup.py +++ b/src/Mod/Path/PathScripts/PathPreferencesPathDressup.py @@ -20,26 +20,28 @@ # * * # *************************************************************************** +import FreeCAD from PySide import QtCore, QtGui -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate + _dressups = [] + def RegisterDressup(dressup): _dressups.append(dressup) + class DressupPreferencesPage: def __init__(self, parent=None): # pylint: disable=unused-argument self.form = QtGui.QToolBox() - self.form.setWindowTitle(translate("Path_PreferencesPathDressup", 'Dressups')) + self.form.setWindowTitle(translate("Path_PreferencesPathDressup", "Dressups")) pages = [] for dressup in _dressups: page = dressup.preferencesPage() - if hasattr(page, 'icon') and page.icon: + if hasattr(page, "icon") and page.icon: self.form.addItem(page.form, page.icon, page.label) else: self.form.addItem(page.form, page.label) @@ -53,4 +55,3 @@ class DressupPreferencesPage: def loadSettings(self): for page in self.pages: page.loadSettings() - diff --git a/src/Mod/Path/PathScripts/PathProfileContourGui.py b/src/Mod/Path/PathScripts/PathProfileContourGui.py index 465ac16cab..89ecb38ad6 100644 --- a/src/Mod/Path/PathScripts/PathProfileContourGui.py +++ b/src/Mod/Path/PathScripts/PathProfileContourGui.py @@ -25,28 +25,31 @@ import FreeCAD import PathScripts.PathOpGui as PathOpGui import PathScripts.PathProfile as PathProfile import PathScripts.PathProfileGui as PathProfileGui -from PySide import QtCore - +from PySide.QtCore import QT_TRANSLATE_NOOP __title__ = "Path Contour Operation UI (depreciated)" __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" -__doc__ = "Contour operation page controller and command implementation (depreciated)." +__doc__ = "Contour operation page controller and command implementation (deprecated)." class TaskPanelOpPage(PathProfileGui.TaskPanelOpPage): - '''Psuedo page controller class for Profile operation, - allowing for backward compatibility with pre-existing "Contour" operations.''' + """Psuedo page controller class for Profile operation, + allowing for backward compatibility with pre-existing "Contour" operations.""" + pass -# Eclass -Command = PathOpGui.SetupOperation('Profile', - PathProfile.Create, - TaskPanelOpPage, - 'Path_Contour', - QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Profile"), - QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Profile entire model, selected face(s) or selected edge(s)"), - PathProfile.SetupProperties) +Command = PathOpGui.SetupOperation( + "Profile", + PathProfile.Create, + TaskPanelOpPage, + "Path_Contour", + QT_TRANSLATE_NOOP("Path_Profile", "Profile"), + QT_TRANSLATE_NOOP( + "Path_Profile", "Profile entire model, selected face(s) or selected edge(s)" + ), + PathProfile.SetupProperties, +) FreeCAD.Console.PrintLog("Loading PathProfileContourGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathProfileEdgesGui.py b/src/Mod/Path/PathScripts/PathProfileEdgesGui.py index e893e65ef0..fae0f913f1 100644 --- a/src/Mod/Path/PathScripts/PathProfileEdgesGui.py +++ b/src/Mod/Path/PathScripts/PathProfileEdgesGui.py @@ -25,28 +25,33 @@ import FreeCAD import PathScripts.PathOpGui as PathOpGui import PathScripts.PathProfile as PathProfile import PathScripts.PathProfileGui as PathProfileGui -from PySide import QtCore - +from PySide.QtCore import QT_TRANSLATE_NOOP __title__ = "Path Profile Edges Operation UI (depreciated)" __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" -__doc__ = "Profile Edges operation page controller and command implementation (depreciated)." +__doc__ = ( + "Profile Edges operation page controller and command implementation (deprecated)." +) class TaskPanelOpPage(PathProfileGui.TaskPanelOpPage): - '''Psuedo page controller class for Profile operation, - allowing for backward compatibility with pre-existing "Profile Edges" operations.''' + """Psuedo page controller class for Profile operation, + allowing for backward compatibility with pre-existing "Profile Edges" operations.""" + pass -# Eclass -Command = PathOpGui.SetupOperation('Profile', - PathProfile.Create, - TaskPanelOpPage, - 'Path_Contour', - QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Profile"), - QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Profile entire model, selected face(s) or selected edge(s)"), - PathProfile.SetupProperties) +Command = PathOpGui.SetupOperation( + "Profile", + PathProfile.Create, + TaskPanelOpPage, + "Path_Contour", + QT_TRANSLATE_NOOP("Path_Profile", "Profile"), + QT_TRANSLATE_NOOP( + "Path_Profile", "Profile entire model, selected face(s) or selected edge(s)" + ), + PathProfile.SetupProperties, +) FreeCAD.Console.PrintLog("Loading PathProfileEdgesGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathProfileFacesGui.py b/src/Mod/Path/PathScripts/PathProfileFacesGui.py index 69bfdbf459..f3bd9814a7 100644 --- a/src/Mod/Path/PathScripts/PathProfileFacesGui.py +++ b/src/Mod/Path/PathScripts/PathProfileFacesGui.py @@ -25,28 +25,33 @@ import FreeCAD import PathScripts.PathOpGui as PathOpGui import PathScripts.PathProfile as PathProfile import PathScripts.PathProfileGui as PathProfileGui -from PySide import QtCore - +from PySide.QtCore import QT_TRANSLATE_NOOP __title__ = "Path Profile Faces Operation UI (depreciated)" __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" -__doc__ = "Profile Faces operation page controller and command implementation (depreciated)." +__doc__ = ( + "Profile Faces operation page controller and command implementation (deprecated)." +) class TaskPanelOpPage(PathProfileGui.TaskPanelOpPage): - '''Psuedo page controller class for Profile operation, - allowing for backward compatibility with pre-existing "Profile Faces" operations.''' + """Psuedo page controller class for Profile operation, + allowing for backward compatibility with pre-existing "Profile Faces" operations.""" + pass -# Eclass -Command = PathOpGui.SetupOperation('Profile', - PathProfile.Create, - TaskPanelOpPage, - 'Path_Contour', - QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Profile"), - QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Profile entire model, selected face(s) or selected edge(s)"), - PathProfile.SetupProperties) +Command = PathOpGui.SetupOperation( + "Profile", + PathProfile.Create, + TaskPanelOpPage, + "Path_Contour", + QT_TRANSLATE_NOOP("Path_Profile", "Profile"), + QT_TRANSLATE_NOOP( + "Path_Profile", "Profile entire model, selected face(s) or selected edge(s)" + ), + PathProfile.SetupProperties, +) FreeCAD.Console.PrintLog("Loading PathProfileFacesGui... done\n") From cf864c4ff188d2919381d54fe9dc757badabc03c Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 24 Jan 2022 16:35:30 -0600 Subject: [PATCH 4/6] dogbone, boundary, ramp entry dressup tranlation fixes --- .../Path/PathScripts/PathDressupDogbone.py | 72 +++++------ .../PathScripts/PathDressupPathBoundary.py | 26 ++-- .../PathScripts/PathDressupPathBoundaryGui.py | 27 ++--- .../Path/PathScripts/PathDressupRampEntry.py | 113 +++++++++++++----- 4 files changed, 140 insertions(+), 98 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDressupDogbone.py b/src/Mod/Path/PathScripts/PathDressupDogbone.py index 1802c1a384..d0e0c5ff51 100644 --- a/src/Mod/Path/PathScripts/PathDressupDogbone.py +++ b/src/Mod/Path/PathScripts/PathDressupDogbone.py @@ -21,6 +21,9 @@ # *************************************************************************** from __future__ import print_function + +from PySide import QtCore +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import Path import PathScripts.PathDressup as PathDressup @@ -29,8 +32,7 @@ import PathScripts.PathLog as PathLog import PathScripts.PathUtil as PathUtil import PathScripts.PathUtils as PathUtils import math - -from PySide import QtCore +from PathScripts.PathGeom import CmdMoveCW, CmdMoveStraight, CmdMoveArc, CmdMoveRapid # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader @@ -38,26 +40,22 @@ from lazy_loader.lazy_loader import LazyLoader DraftGeomUtils = LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils") Part = LazyLoader("Part", globals(), "Part") -LOG_MODULE = PathLog.thisModule() -PathLog.setLevel(PathLog.Level.NOTICE, LOG_MODULE) -# PathLog.trackModule(LOG_MODULE) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate -movecommands = ["G0", "G00", "G1", "G01", "G2", "G02", "G3", "G03"] -movestraight = ["G1", "G01"] -movecw = ["G2", "G02"] -moveccw = ["G3", "G03"] -movearc = movecw + moveccw +movecommands = CmdMoveStraight + CmdMoveRapid + CmdMoveArc def debugMarker(vector, label, color=None, radius=0.5): - if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG: + if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG: obj = FreeCAD.ActiveDocument.addObject("Part::Sphere", label) obj.Label = label obj.Radius = radius @@ -69,7 +67,7 @@ def debugMarker(vector, label, color=None, radius=0.5): def debugCircle(vector, r, label, color=None): - if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG: + if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG: obj = FreeCAD.ActiveDocument.addObject("Part::Cylinder", label) obj.Label = label obj.Radius = r @@ -121,9 +119,9 @@ def edgesForCommands(cmds, startPt): for cmd in cmds: if cmd.Name in movecommands: pt = pointFromCommand(cmd, lastPt) - if cmd.Name in movestraight: + if cmd.Name in CmdMoveStraight: edges.append(Part.Edge(Part.LineSegment(lastPt, pt))) - elif cmd.Name in movearc: + elif cmd.Name in CmdMoveArc: center = lastPt + pointFromCommand( cmd, FreeCAD.Vector(0, 0, 0), "I", "J", "K" ) @@ -134,7 +132,7 @@ def edgesForCommands(cmds, startPt): if d == 0: # we're dealing with half a circle here angle = getAngle(A) + math.pi / 2 - if cmd.Name in movecw: + if cmd.Name in CmdMoveCW: angle -= math.pi else: C = A + B @@ -432,14 +430,14 @@ class ObjectDressup(object): "App::PropertyLink", "Base", "Base", - QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The base path to modify"), + QT_TRANSLATE_NOOP("App::Property", "The base path to modify"), ) obj.addProperty( "App::PropertyEnumeration", "Side", "Dressup", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupDogbone", "The side of path to insert bones" + QT_TRANSLATE_NOOP( + "App::Property", "The side of path to insert bones" ), ) obj.Side = [Side.Left, Side.Right] @@ -448,7 +446,7 @@ class ObjectDressup(object): "App::PropertyEnumeration", "Style", "Dressup", - QtCore.QT_TRANSLATE_NOOP("Path_DressupDogbone", "The style of bones"), + QT_TRANSLATE_NOOP("App::Property", "The style of bones"), ) obj.Style = Style.All obj.Style = Style.Dogbone @@ -456,8 +454,8 @@ class ObjectDressup(object): "App::PropertyIntegerList", "BoneBlacklist", "Dressup", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupDogbone", "Bones that aren't dressed up" + QT_TRANSLATE_NOOP( + "App::Property", "Bones that aren't dressed up" ), ) obj.BoneBlacklist = [] @@ -466,8 +464,8 @@ class ObjectDressup(object): "App::PropertyEnumeration", "Incision", "Dressup", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupDogbone", "The algorithm to determine the bone length" + QT_TRANSLATE_NOOP( + "App::Property", "The algorithm to determine the bone length" ), ) obj.Incision = Incision.All @@ -476,8 +474,8 @@ class ObjectDressup(object): "App::PropertyFloat", "Custom", "Dressup", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupDogbone", "Dressup length if Incision == custom" + QT_TRANSLATE_NOOP( + "App::Property", "Dressup length if Incision == custom" ), ) obj.Custom = 0.0 @@ -510,7 +508,7 @@ class ObjectDressup(object): # Answer true if a dogbone could be on either end of the chord, given its command def canAttachDogbone(self, cmd, chord): return ( - cmd.Name in movestraight + cmd.Name in CmdMoveStraight and not chord.isAPlungeMove() and not chord.isANoopMove() ) @@ -884,7 +882,7 @@ class ObjectDressup(object): commands.append(c1) # 3. change where c2 starts, this depends on the command itself c2 = bone2.inCommands[j] - if c2.Name in movearc: + if c2.Name in CmdMoveArc: center = e2.Curve.Center offset = center - pt c2Params = c2.Parameters @@ -1142,9 +1140,7 @@ class TaskPanel(object): self.obj = obj self.form = FreeCADGui.PySideUic.loadUi(":/panels/DogboneEdit.ui") self.s = None - FreeCAD.ActiveDocument.openTransaction( - translate("Path_DressupDogbone", "Edit Dogbone Dress-up") - ) + FreeCAD.ActiveDocument.openTransaction("Edit Dogbone Dress-up") self.height = 10 self.markers = [] @@ -1231,7 +1227,7 @@ class TaskPanel(object): self.form.customLabel.setEnabled(customSelected) self.updateBoneList() - if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG: + if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG: for obj in FreeCAD.ActiveDocument.Objects: if obj.Name.startswith("Shape"): FreeCAD.ActiveDocument.removeObject(obj.Name) @@ -1384,10 +1380,10 @@ class CommandDressupDogbone(object): def GetResources(self): return { "Pixmap": "Path_Dressup", - "MenuText": QtCore.QT_TRANSLATE_NOOP( + "MenuText": QT_TRANSLATE_NOOP( "Path_DressupDogbone", "Dogbone Dress-up" ), - "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "ToolTip": QT_TRANSLATE_NOOP( "Path_DressupDogbone", "Creates a Dogbone Dress-up object from a selected path", ), @@ -1418,9 +1414,7 @@ class CommandDressupDogbone(object): return # everything ok! - FreeCAD.ActiveDocument.openTransaction( - translate("Path_DressupDogbone", "Create Dogbone Dress-up") - ) + FreeCAD.ActiveDocument.openTransaction("Create Dogbone Dress-up") FreeCADGui.addModule("PathScripts.PathDressupDogbone") FreeCADGui.doCommand( "PathScripts.PathDressupDogbone.Create(FreeCAD.ActiveDocument.%s)" diff --git a/src/Mod/Path/PathScripts/PathDressupPathBoundary.py b/src/Mod/Path/PathScripts/PathDressupPathBoundary.py index 6a2c737924..6e7df53aeb 100644 --- a/src/Mod/Path/PathScripts/PathDressupPathBoundary.py +++ b/src/Mod/Path/PathScripts/PathDressupPathBoundary.py @@ -20,6 +20,7 @@ # * * # *************************************************************************** +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import Path import PathScripts.PathDressup as PathDressup @@ -29,15 +30,14 @@ import PathScripts.PathStock as PathStock import PathScripts.PathUtil as PathUtil import PathScripts.PathUtils as PathUtils -from PySide import QtCore - -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule(PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate def _vstr(v): @@ -52,17 +52,15 @@ class DressupPathBoundary(object): "App::PropertyLink", "Base", "Base", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupPathBoundary", "The base path to modify" - ), + QT_TRANSLATE_NOOP("App::Property", "The base path to modify"), ) obj.Base = base obj.addProperty( "App::PropertyLink", "Stock", "Boundary", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupPathBoundary", + QT_TRANSLATE_NOOP( + "App::Property", "Solid object to be used to limit the generated Path.", ), ) @@ -71,8 +69,8 @@ class DressupPathBoundary(object): "App::PropertyBool", "Inside", "Boundary", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupPathBoundary", + QT_TRANSLATE_NOOP( + "App::Property", "Determines if Boundary describes an inclusion or exclusion mask.", ), ) diff --git a/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py b/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py index c76f9e2042..6d5540d805 100644 --- a/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py +++ b/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py @@ -20,21 +20,22 @@ # * * # *************************************************************************** +from PySide import QtGui +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import FreeCADGui import PathGui as PGui # ensure Path/Gui/Resources are loaded import PathScripts.PathDressupPathBoundary as PathDressupPathBoundary import PathScripts.PathLog as PathLog -from PySide import QtGui, QtCore - -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule() +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate class TaskPanel(object): @@ -245,9 +246,7 @@ class DressupPathBoundaryViewProvider(object): def Create(base, name="DressupPathBoundary"): - FreeCAD.ActiveDocument.openTransaction( - translate("Path_DressupPathBoundary", "Create a Boundary dressup") - ) + FreeCAD.ActiveDocument.openTransaction("Create a Boundary dressup") obj = PathDressupPathBoundary.Create(base, name) obj.ViewObject.Proxy = DressupPathBoundaryViewProvider(obj.ViewObject) obj.Base.ViewObject.Visibility = False @@ -263,10 +262,10 @@ class CommandPathDressupPathBoundary: def GetResources(self): return { "Pixmap": "Path_Dressup", - "MenuText": QtCore.QT_TRANSLATE_NOOP( + "MenuText": QT_TRANSLATE_NOOP( "Path_DressupPathBoundary", "Boundary Dress-up" ), - "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "ToolTip": QT_TRANSLATE_NOOP( "Path_DressupPathBoundary", "Creates a Path Boundary Dress-up object from a selected path", ), @@ -291,9 +290,7 @@ class CommandPathDressupPathBoundary: baseObject = selection[0] # everything ok! - FreeCAD.ActiveDocument.openTransaction( - translate("Path_DressupPathBoundary", "Create Path Boundary Dress-up") - ) + FreeCAD.ActiveDocument.openTransaction("Create Path Boundary Dress-up") FreeCADGui.addModule("PathScripts.PathDressupPathBoundaryGui") FreeCADGui.doCommand( "PathScripts.PathDressupPathBoundaryGui.Create(App.ActiveDocument.%s)" diff --git a/src/Mod/Path/PathScripts/PathDressupRampEntry.py b/src/Mod/Path/PathScripts/PathDressupRampEntry.py index 0724652d99..bd53bbfce5 100644 --- a/src/Mod/Path/PathScripts/PathDressupRampEntry.py +++ b/src/Mod/Path/PathScripts/PathDressupRampEntry.py @@ -20,6 +20,8 @@ # * * # *************************************************************************** +from PathScripts import PathUtils +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import Path import PathScripts.PathDressup as PathDressup @@ -27,8 +29,6 @@ import PathScripts.PathGeom as PathGeom import PathScripts.PathLog as PathLog import math -from PathScripts import PathUtils -from PySide import QtCore # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader @@ -39,12 +39,14 @@ if FreeCAD.GuiUp: import FreeCADGui -# Qt translation handling -def translate(text, context="Path_DressupRampEntry", disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) class ObjectDressup: @@ -54,41 +56,37 @@ class ObjectDressup: "App::PropertyLink", "Base", "Path", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupRampEntry", "The base path to modify" - ), + QT_TRANSLATE_NOOP("App::Property", "The base path to modify"), ) obj.addProperty( "App::PropertyAngle", "Angle", "Path", - QtCore.QT_TRANSLATE_NOOP("Path_DressupRampEntry", "Angle of ramp."), + QT_TRANSLATE_NOOP("App::Property", "Angle of ramp."), ) obj.addProperty( "App::PropertyEnumeration", "Method", "Path", - QtCore.QT_TRANSLATE_NOOP("App::Property", "Ramping Method"), + QT_TRANSLATE_NOOP("App::Property", "Ramping Method"), ) obj.addProperty( "App::PropertyEnumeration", "RampFeedRate", "FeedRate", - QtCore.QT_TRANSLATE_NOOP( - "App::Property", "Which feed rate to use for ramping" - ), + QT_TRANSLATE_NOOP("App::Property", "Which feed rate to use for ramping"), ) obj.addProperty( "App::PropertySpeed", "CustomFeedRate", "FeedRate", - QtCore.QT_TRANSLATE_NOOP("App::Property", "Custom feed rate"), + QT_TRANSLATE_NOOP("App::Property", "Custom feed rate"), ) obj.addProperty( "App::PropertyBool", "UseStartDepth", "StartDepth", - QtCore.QT_TRANSLATE_NOOP( + QT_TRANSLATE_NOOP( "App::Property", "Should the dressup ignore motion commands above DressupStartDepth", ), @@ -97,18 +95,16 @@ class ObjectDressup: "App::PropertyDistance", "DressupStartDepth", "StartDepth", - QtCore.QT_TRANSLATE_NOOP( + QT_TRANSLATE_NOOP( "App::Property", "The depth where the ramp dressup is enabled. Above this ramps are not generated, but motion commands are passed through as is.", ), ) - obj.Method = ["RampMethod1", "RampMethod2", "RampMethod3", "Helix"] - obj.RampFeedRate = [ - "Horizontal Feed Rate", - "Vertical Feed Rate", - "Ramp Feed Rate", - "Custom", - ] + + # populate the enumerations + for n in self.propertyEnumerations(): + setattr(obj, n[0], n[1]) + obj.Proxy = self self.setEditorProperties(obj) @@ -121,6 +117,55 @@ class ObjectDressup: self.ignoreAboveEnabled = None self.ignoreAbove = None + @classmethod + def propertyEnumerations(self, dataType="data"): + """PropertyEnumerations(dataType="data")... return property enumeration lists of specified dataType. + Args: + dataType = 'data', 'raw', 'translated' + Notes: + 'data' is list of internal string literals used in code + 'raw' is list of (translated_text, data_string) tuples + 'translated' is list of translated string literals + """ + + enums = { + "Object": [ + (translate("Path_DressupRampEntry", "RampMethod1"), "RampMethod1"), + (translate("Path_DressupRampEntry", "RampMethod2"), "RampMethod2"), + (translate("Path_DressupRampEntry", "RampMethod3"), "RampMethod3"), + (translate("Path_DressupRampEntry", "Helix"), "Helix"), + ], + "RampFeedRate": [ + ( + translate("Path_DressupRampEntry", "Horizontal Feed Rate"), + "Horizontal Feed Rate", + ), + ( + translate("Path_DressupRampEntry", "Vertical Feed Rate"), + "Vertical Feed Rate", + ), + ( + translate("Path_DressupRampEntry", "Ramp Feed Rate"), + "Ramp Feed Rate", + ), + (translate("Path_DressupRampEntry", "Custom"), "Custom"), + ], + } + + if dataType == "raw": + return enums + + data = list() + idx = 0 if dataType == "translated" else 1 + + PathLog.debug(enums) + + for k, v in enumerate(enums): + data.append((v, [tup[idx] for tup in enums[v]])) + PathLog.debug(data) + + return data + def __getstate__(self): return None @@ -855,10 +900,10 @@ class CommandPathDressupRampEntry: def GetResources(self): return { "Pixmap": "Path_Dressup", - "MenuText": QtCore.QT_TRANSLATE_NOOP( + "MenuText": QT_TRANSLATE_NOOP( "Path_DressupRampEntry", "RampEntry Dress-up" ), - "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "ToolTip": QT_TRANSLATE_NOOP( "Path_DressupRampEntry", "Creates a Ramp Entry Dress-up object from a selected path", ), @@ -875,18 +920,26 @@ class CommandPathDressupRampEntry: # check that the selection contains exactly what we want selection = FreeCADGui.Selection.getSelection() if len(selection) != 1: - PathLog.error(translate("Please select one path object") + "\n") + PathLog.error( + translate("Path_DressupRampEntry", "Please select one path object") + + "\n" + ) return baseObject = selection[0] if not baseObject.isDerivedFrom("Path::Feature"): - PathLog.error(translate("The selected object is not a path") + "\n") + PathLog.error( + translate("Path_DressupRampEntry", "The selected object is not a path") + + "\n" + ) return if baseObject.isDerivedFrom("Path::FeatureCompoundPython"): - PathLog.error(translate("Please select a Profile object")) + PathLog.error( + translate("Path_DressupRampEntry", "Please select a Profile object") + ) return # everything ok! - FreeCAD.ActiveDocument.openTransaction(translate("Create RampEntry Dress-up")) + FreeCAD.ActiveDocument.openTransaction("Create RampEntry Dress-up") FreeCADGui.addModule("PathScripts.PathDressupRampEntry") FreeCADGui.addModule("PathScripts.PathUtils") FreeCADGui.doCommand( From 44e4e8bddc0d0fdef1a5fa9be91e7ad15be831dd Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 24 Jan 2022 16:52:54 -0600 Subject: [PATCH 5/6] Holding tag translation cleanup --- .../PathScripts/PathDressupHoldingTags.py | 44 +++++++++---------- src/Mod/Path/PathScripts/PathDressupTag.py | 40 +++++++---------- src/Mod/Path/PathScripts/PathDressupTagGui.py | 41 +++++++---------- .../PathScripts/PathDressupTagPreferences.py | 12 ++--- 4 files changed, 61 insertions(+), 76 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py index 66e5061183..788e21bf0b 100644 --- a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py +++ b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py @@ -20,6 +20,9 @@ # * * # *************************************************************************** +from PathScripts.PathDressupTagPreferences import HoldingTagPreferences +from PathScripts.PathUtils import waiting_effects +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import Path import PathScripts.PathDressup as PathDressup @@ -30,24 +33,23 @@ import PathScripts.PathUtils as PathUtils import copy import math -from PathScripts.PathDressupTagPreferences import HoldingTagPreferences -from PathScripts.PathUtils import waiting_effects -from PySide import QtCore # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader Part = LazyLoader("Part", globals(), "Part") -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule() +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + +translate = FreeCAD.Qt.translate + failures = [] -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) - def debugEdge(edge, prefix, force=False): if force or PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG: @@ -956,56 +958,50 @@ class ObjectTagDressup: "App::PropertyLink", "Base", "Base", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "The base path to modify"), + QT_TRANSLATE_NOOP("App::Property", "The base path to modify"), ) obj.addProperty( "App::PropertyLength", "Width", "Tag", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Width of tags."), + QT_TRANSLATE_NOOP("App::Property", "Width of tags."), ) obj.addProperty( "App::PropertyLength", "Height", "Tag", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Height of tags."), + QT_TRANSLATE_NOOP("App::Property", "Height of tags."), ) obj.addProperty( "App::PropertyAngle", "Angle", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", "Angle of tag plunge and ascent." - ), + QT_TRANSLATE_NOOP("App::Property", "Angle of tag plunge and ascent."), ) obj.addProperty( "App::PropertyLength", "Radius", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", "Radius of the fillet for the tag." - ), + QT_TRANSLATE_NOOP("App::Property", "Radius of the fillet for the tag."), ) obj.addProperty( "App::PropertyVectorList", "Positions", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", "Locations of inserted holding tags" - ), + QT_TRANSLATE_NOOP("App::Property", "Locations of inserted holding tags"), ) obj.addProperty( "App::PropertyIntegerList", "Disabled", "Tag", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "IDs of disabled holding tags"), + QT_TRANSLATE_NOOP("App::Property", "IDs of disabled holding tags"), ) obj.addProperty( "App::PropertyInteger", "SegmentationFactor", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", + QT_TRANSLATE_NOOP( + "App::Property", "Factor determining the # of segments used to approximate rounded tags.", ), ) diff --git a/src/Mod/Path/PathScripts/PathDressupTag.py b/src/Mod/Path/PathScripts/PathDressupTag.py index 763b8d55ba..e7fbb451a4 100644 --- a/src/Mod/Path/PathScripts/PathDressupTag.py +++ b/src/Mod/Path/PathScripts/PathDressupTag.py @@ -20,6 +20,8 @@ # * * # *************************************************************************** +from PathScripts.PathDressupTagPreferences import HoldingTagPreferences +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import PathScripts.PathDressup as PathDressup import PathScripts.PathGeom as PathGeom @@ -33,16 +35,14 @@ from lazy_loader.lazy_loader import LazyLoader DraftGeomUtils = LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils") Part = LazyLoader("Part", globals(), "Part") -from PathScripts.PathDressupTagPreferences import HoldingTagPreferences -from PySide import QtCore -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule() +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) - -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate MaxInt = 99999999999999 @@ -122,56 +122,50 @@ class ObjectDressup: "App::PropertyLink", "Base", "Base", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "The base path to modify"), + QT_TRANSLATE_NOOP("App::Property", "The base path to modify"), ) obj.addProperty( "App::PropertyLength", "Width", "Tag", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Width of tags."), + QT_TRANSLATE_NOOP("App::Property", "Width of tags."), ) obj.addProperty( "App::PropertyLength", "Height", "Tag", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Height of tags."), + QT_TRANSLATE_NOOP("App::Property", "Height of tags."), ) obj.addProperty( "App::PropertyAngle", "Angle", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", "Angle of tag plunge and ascent." - ), + QT_TRANSLATE_NOOP("App::Property", "Angle of tag plunge and ascent."), ) obj.addProperty( "App::PropertyLength", "Radius", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", "Radius of the fillet for the tag." - ), + QT_TRANSLATE_NOOP("App::Property", "Radius of the fillet for the tag."), ) obj.addProperty( "App::PropertyVectorList", "Positions", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", "Locations of inserted holding tags" - ), + QT_TRANSLATE_NOOP("App::Property", "Locations of inserted holding tags"), ) obj.addProperty( "App::PropertyIntegerList", "Disabled", "Tag", - QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "IDs of disabled holding tags"), + QT_TRANSLATE_NOOP("App::Property", "IDs of disabled holding tags"), ) obj.addProperty( "App::PropertyInteger", "SegmentationFactor", "Tag", - QtCore.QT_TRANSLATE_NOOP( - "Path_DressupTag", + QT_TRANSLATE_NOOP( + "App::Property", "Factor determining the # of segments used to approximate rounded tags.", ), ) diff --git a/src/Mod/Path/PathScripts/PathDressupTagGui.py b/src/Mod/Path/PathScripts/PathDressupTagGui.py index ce181d306c..b42738ae0c 100644 --- a/src/Mod/Path/PathScripts/PathDressupTagGui.py +++ b/src/Mod/Path/PathScripts/PathDressupTagGui.py @@ -20,26 +20,27 @@ # * * # *************************************************************************** +from PySide import QtCore, QtGui +from PySide.QtCore import QT_TRANSLATE_NOOP +from pivy import coin import FreeCAD import FreeCADGui import PathGui as PGui # ensure Path/Gui/Resources are loaded +import PathScripts.PathDressupHoldingTags as PathDressupTag import PathScripts.PathGeom as PathGeom import PathScripts.PathGetPoint as PathGetPoint -import PathScripts.PathDressupHoldingTags as PathDressupTag import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences import PathScripts.PathUtils as PathUtils -from PySide import QtCore, QtGui -from pivy import coin -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule() +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) - -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate def addDebugDisplay(): @@ -60,9 +61,7 @@ class PathDressupTagTaskPanel: self.getPoint = PathGetPoint.TaskPanel(self.form.removeEditAddGroup, True) self.jvo = PathUtils.findParentJob(obj).ViewObject if jvoVisibility is None: - FreeCAD.ActiveDocument.openTransaction( - translate("PathDressup_HoldingTags", "Edit HoldingTags Dress-up") - ) + FreeCAD.ActiveDocument.openTransaction("Edit HoldingTags Dress-up") self.jvoVisible = self.jvo.isVisible() if self.jvoVisible: self.jvo.hide() @@ -207,9 +206,7 @@ class PathDressupTagTaskPanel: self.Disabled = self.obj.Disabled self.updateTagsView() else: - PathLog.error( - translate("Path_DressupTag", "Cannot copy tags - internal error") + "\n" - ) + PathLog.error("Cannot copy tags - internal error") def updateModel(self): self.getFields() @@ -381,7 +378,7 @@ class PathDressupTagViewProvider: def debugDisplay(self): # if False and addDebugDisplay(): # if not hasattr(self.vobj, 'Debug'): - # self.vobj.addProperty('App::PropertyLink', 'Debug', 'Debug', QtCore.QT_TRANSLATE_NOOP('Path_DressupTag', 'Some elements for debugging')) + # self.vobj.addProperty('App::PropertyLink', 'Debug', 'Debug', QT_TRANSLATE_NOOP('Path_DressupTag', 'Some elements for debugging')) # dbg = self.vobj.Object.Document.addObject('App::DocumentObjectGroup', 'TagDebug') # self.vobj.Debug = dbg # return True @@ -559,9 +556,7 @@ def Create(baseObject, name="DressupTag"): Create(basePath, name = 'DressupTag') ... create tag dressup object for the given base path. Use this command only iff the UI is up - for batch processing see PathDressupTag.Create """ - FreeCAD.ActiveDocument.openTransaction( - translate("Path_DressupTag", "Create a Tag dressup") - ) + FreeCAD.ActiveDocument.openTransaction("Create a Tag dressup") obj = PathDressupTag.Create(baseObject, name) obj.ViewObject.Proxy = PathDressupTagViewProvider(obj.ViewObject) FreeCAD.ActiveDocument.commitTransaction() @@ -575,8 +570,8 @@ class CommandPathDressupTag: def GetResources(self): return { "Pixmap": "Path_Dressup", - "MenuText": QtCore.QT_TRANSLATE_NOOP("Path_DressupTag", "Tag Dress-up"), - "ToolTip": QtCore.QT_TRANSLATE_NOOP( + "MenuText": QT_TRANSLATE_NOOP("Path_DressupTag", "Tag Dress-up"), + "ToolTip": QT_TRANSLATE_NOOP( "Path_DressupTag", "Creates a Tag Dress-up object from a selected path" ), } @@ -599,9 +594,7 @@ class CommandPathDressupTag: baseObject = selection[0] # everything ok! - FreeCAD.ActiveDocument.openTransaction( - translate("Path_DressupTag", "Create Tag Dress-up") - ) + FreeCAD.ActiveDocument.openTransaction("Create Tag Dress-up") FreeCADGui.addModule("PathScripts.PathDressupTagGui") FreeCADGui.doCommand( "PathScripts.PathDressupTagGui.Create(App.ActiveDocument.%s)" diff --git a/src/Mod/Path/PathScripts/PathDressupTagPreferences.py b/src/Mod/Path/PathScripts/PathDressupTagPreferences.py index 6d171fd8ba..c242e6c564 100644 --- a/src/Mod/Path/PathScripts/PathDressupTagPreferences.py +++ b/src/Mod/Path/PathScripts/PathDressupTagPreferences.py @@ -21,15 +21,17 @@ # *************************************************************************** import FreeCAD +import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences import PathScripts.PathPreferencesPathDressup as PathPreferencesPathDressup -from PySide import QtCore +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) - -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate class HoldingTagPreferences: From 988b980d0d91e07844a2a46a61bc6df67e5efa68 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 24 Jan 2022 17:07:14 -0600 Subject: [PATCH 6/6] feature extension translaton cleanup --- .../Path/PathScripts/PathFeatureExtensions.py | 27 ++++++++++--------- .../PathScripts/PathFeatureExtensionsGui.py | 18 ++++++------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathFeatureExtensions.py b/src/Mod/Path/PathScripts/PathFeatureExtensions.py index dc0d9cf23f..51d17a55fa 100644 --- a/src/Mod/Path/PathScripts/PathFeatureExtensions.py +++ b/src/Mod/Path/PathScripts/PathFeatureExtensions.py @@ -20,10 +20,11 @@ # * * # *************************************************************************** +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD +import Part import PathScripts.PathGeom as PathGeom import PathScripts.PathLog as PathLog -import Part import math # lazily loaded modules @@ -31,20 +32,20 @@ from lazy_loader.lazy_loader import LazyLoader PathUtils = LazyLoader("PathScripts.PathUtils", globals(), "PathScripts.PathUtils") -from PySide import QtCore __title__ = "Path Features Extensions" __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" __doc__ = "Class and implementation of face extensions features." -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule(PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# Qt translation handling -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate def endPoints(edgeOrWire): @@ -104,6 +105,7 @@ def extendWire(feature, wire, length): try: off2D = wire.makeOffset2D(length) except FreeCAD.Base.FreeCADError as ee: + PathLog.debug(ee) return None endPts = endPoints(wire) # Assumes wire is NOT closed if endPts: @@ -389,6 +391,7 @@ class Extension(object): try: off2D = sub.makeOffset2D(length) except FreeCAD.Base.FreeCADError as ee: + PathLog.debug(ee) return None if isOutside: @@ -511,24 +514,22 @@ def initialize_properties(obj): "App::PropertyDistance", "ExtensionLengthDefault", "Extension", - QtCore.QT_TRANSLATE_NOOP( - "PathPocketShape", "Default length of extensions." - ), + QT_TRANSLATE_NOOP("App::Property", "Default length of extensions."), ) if not hasattr(obj, "ExtensionFeature"): obj.addProperty( "App::PropertyLinkSubListGlobal", "ExtensionFeature", "Extension", - QtCore.QT_TRANSLATE_NOOP("PathPocketShape", "List of features to extend."), + QT_TRANSLATE_NOOP("App::Property", "List of features to extend."), ) if not hasattr(obj, "ExtensionCorners"): obj.addProperty( "App::PropertyBool", "ExtensionCorners", "Extension", - QtCore.QT_TRANSLATE_NOOP( - "PathPocketShape", + QT_TRANSLATE_NOOP( + "App::Property", "When enabled connected extension edges are combined to wires.", ), ) diff --git a/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py b/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py index 91690ba627..a4a9a8e869 100644 --- a/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py +++ b/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py @@ -20,16 +20,15 @@ # * * # *************************************************************************** +from PySide import QtCore, QtGui +from pivy import coin import FreeCAD import FreeCADGui +import PathScripts.PathFeatureExtensions as FeatureExtensions import PathScripts.PathGeom as PathGeom import PathScripts.PathGui as PathGui import PathScripts.PathLog as PathLog import PathScripts.PathOpGui as PathOpGui -import PathScripts.PathFeatureExtensions as FeatureExtensions - -from PySide import QtCore, QtGui -from pivy import coin # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader @@ -42,12 +41,13 @@ __url__ = "https://www.freecadweb.org" __doc__ = "Extensions feature page controller." -def translate(context, text, disambig=None): - return QtCore.QCoreApplication.translate(context, text, disambig) +translate = FreeCAD.Qt.translate - -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) -# PathLog.trackModule(PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) class _Extension(object):