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/PathDressupDogbone.py b/src/Mod/Path/PathScripts/PathDressupDogbone.py
index c91ef30078..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,48 +32,49 @@ 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
-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)
+DraftGeomUtils = LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils")
+Part = LazyLoader("Part", globals(), "Part")
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-movecommands = ['G0', 'G00', 'G1', 'G01', 'G2', 'G02', 'G3', 'G03']
-movestraight = ['G1', 'G01']
-movecw = ['G2', 'G02']
-moveccw = ['G3', 'G03']
-movearc = movecw + moveccw
+
+translate = FreeCAD.Qt.translate
+
+
+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
- 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
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
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 +83,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 +106,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)
@@ -115,18 +119,20 @@ 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:
- center = lastPt + pointFromCommand(cmd, FreeCAD.Vector(0, 0, 0), 'I', 'J', 'K')
+ elif cmd.Name in CmdMoveArc:
+ 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
- if cmd.Name in movecw:
+ angle = getAngle(A) + math.pi / 2
+ if cmd.Name in CmdMoveCW:
angle -= math.pi
else:
C = A + B
@@ -143,19 +149,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 +176,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 +200,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 +210,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 +256,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 +290,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 +299,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 +314,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 +351,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 +361,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 +384,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 +395,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 +416,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",
+ QT_TRANSLATE_NOOP("App::Property", "The base path to modify"),
+ )
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "Side",
+ "Dressup",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "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",
+ QT_TRANSLATE_NOOP("App::Property", "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",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "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",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "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",
+ QT_TRANSLATE_NOOP(
+ "App::Property", "Dressup length if Incision == custom"
+ ),
+ )
obj.Custom = 0.0
obj.Proxy = self
obj.Base = base
@@ -431,7 +492,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 +507,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 CmdMoveStraight
+ 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 +545,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 +557,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 +577,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 +619,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 +637,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 +685,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 +702,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 +716,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 +752,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 +770,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 +804,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 +828,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 +847,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,36 +858,40 @@ 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
c2 = bone2.inCommands[j]
- if c2.Name in movearc:
+ if c2.Name in CmdMoveArc:
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 +911,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 +937,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 +1022,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 +1044,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 +1073,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 +1084,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 +1126,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 +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 = []
@@ -999,8 +1182,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 +1193,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 +1208,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:
@@ -1033,11 +1227,11 @@ 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'):
+ 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 +1285,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 +1346,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 +1357,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 +1378,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": QT_TRANSLATE_NOOP(
+ "Path_DressupDogbone", "Dogbone Dress-up"
+ ),
+ "ToolTip": 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 +1401,25 @@ 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("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 +1428,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..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,33 +33,51 @@ 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()
+Part = LazyLoader("Part", globals(), "Part")
+
+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:
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 +85,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 +98,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 +113,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 +123,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 +134,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 +185,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 +198,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 +214,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 +243,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 +260,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 +275,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 +297,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 +306,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 +346,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 +374,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 +388,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 +408,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 +432,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 +493,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 +510,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 +541,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 +570,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 +632,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 +672,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 +700,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 +739,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 +752,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 +762,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 +775,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 +799,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 +818,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 +838,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 +886,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 +912,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 +952,59 @@ 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",
+ QT_TRANSLATE_NOOP("App::Property", "The base path to modify"),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "Width",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Width of tags."),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "Height",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Height of tags."),
+ )
+ obj.addProperty(
+ "App::PropertyAngle",
+ "Angle",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Angle of tag plunge and ascent."),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "Radius",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Radius of the fillet for the tag."),
+ )
+ obj.addProperty(
+ "App::PropertyVectorList",
+ "Positions",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Locations of inserted holding tags"),
+ )
+ obj.addProperty(
+ "App::PropertyIntegerList",
+ "Disabled",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "IDs of disabled holding tags"),
+ )
+ obj.addProperty(
+ "App::PropertyInteger",
+ "SegmentationFactor",
+ "Tag",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Factor determining the # of segments used to approximate rounded tags.",
+ ),
+ )
# for pylint ...
self.obj = obj
@@ -802,7 +1040,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 +1063,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 +1098,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 +1114,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 +1139,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 +1190,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 +1211,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 +1263,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 +1280,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 +1303,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 +1327,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 +1362,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 +1380,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 +1401,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..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,31 +30,50 @@ 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):
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",
+ 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", "Solid object to be used to limit the generated Path."))
+ obj.addProperty(
+ "App::PropertyLink",
+ "Stock",
+ "Boundary",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "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",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Determines if Boundary describes an inclusion or exclusion mask.",
+ ),
+ )
obj.Inside = True
self.obj = obj
@@ -85,6 +105,8 @@ class DressupPathBoundary(object):
def execute(self, obj):
pb = PathBoundary(obj.Base, obj.Stock.Shape, obj.Inside)
obj.Path = pb.execute()
+
+
# Eclass
@@ -114,15 +136,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 +157,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 +189,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 +225,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 +284,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 +292,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..6d5540d805 100644
--- a/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py
+++ b/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py
@@ -20,28 +20,29 @@
# * *
# ***************************************************************************
+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 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):
-
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 +59,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 +118,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 +162,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 +178,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 +204,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 +245,8 @@ 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("Create a Boundary dressup")
obj = PathDressupPathBoundary.Create(base, name)
obj.ViewObject.Proxy = DressupPathBoundaryViewProvider(obj.ViewObject)
obj.Base.ViewObject.Visibility = False
@@ -235,18 +255,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": QT_TRANSLATE_NOOP(
+ "Path_DressupPathBoundary", "Boundary Dress-up"
+ ),
+ "ToolTip": 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 +282,26 @@ 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("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/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(
diff --git a/src/Mod/Path/PathScripts/PathDressupTag.py b/src/Mod/Path/PathScripts/PathDressupTag.py
index 30e2243a52..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
@@ -29,22 +31,23 @@ import math
# lazily loaded modules
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()
+DraftGeomUtils = LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils")
+Part = LazyLoader("Part", globals(), "Part")
-# Qt translation handling
-def translate(context, text, disambig=None):
- return QtCore.QCoreApplication.translate(context, text, disambig)
+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
+
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,59 @@ 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",
+ QT_TRANSLATE_NOOP("App::Property", "The base path to modify"),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "Width",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Width of tags."),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "Height",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Height of tags."),
+ )
+ obj.addProperty(
+ "App::PropertyAngle",
+ "Angle",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Angle of tag plunge and ascent."),
+ )
+ obj.addProperty(
+ "App::PropertyLength",
+ "Radius",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Radius of the fillet for the tag."),
+ )
+ obj.addProperty(
+ "App::PropertyVectorList",
+ "Positions",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "Locations of inserted holding tags"),
+ )
+ obj.addProperty(
+ "App::PropertyIntegerList",
+ "Disabled",
+ "Tag",
+ QT_TRANSLATE_NOOP("App::Property", "IDs of disabled holding tags"),
+ )
+ obj.addProperty(
+ "App::PropertyInteger",
+ "SegmentationFactor",
+ "Tag",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "Factor determining the # of segments used to approximate rounded tags.",
+ ),
+ )
obj.Proxy = self
obj.Base = base
@@ -152,16 +199,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 +241,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 +266,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 +282,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 +297,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 +318,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..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 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,7 +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()
@@ -76,7 +77,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 +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()
@@ -273,10 +278,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 +303,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 +332,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 +350,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
@@ -362,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
@@ -376,15 +392,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 +424,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 +444,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 +464,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 +474,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 +498,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 +530,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 +551,12 @@ 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("Create a Tag dressup")
obj = PathDressupTag.Create(baseObject, name)
obj.ViewObject.Proxy = PathDressupTagViewProvider(obj.ViewObject)
FreeCAD.ActiveDocument.commitTransaction()
@@ -536,14 +568,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": QT_TRANSLATE_NOOP("Path_DressupTag", "Tag Dress-up"),
+ "ToolTip": 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 +587,25 @@ 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("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..c242e6c564 100644
--- a/src/Mod/Path/PathScripts/PathDressupTagPreferences.py
+++ b/src/Mod/Path/PathScripts/PathDressupTagPreferences.py
@@ -21,79 +21,116 @@
# ***************************************************************************
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:
- 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..51d17a55fa 100644
--- a/src/Mod/Path/PathScripts/PathFeatureExtensions.py
+++ b/src/Mod/Path/PathScripts/PathFeatureExtensions.py
@@ -20,34 +20,36 @@
# * *
# ***************************************************************************
+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
from lazy_loader.lazy_loader import LazyLoader
-PathUtils = LazyLoader('PathScripts.PathUtils', globals(), 'PathScripts.PathUtils')
-from PySide import QtCore
+PathUtils = LazyLoader("PathScripts.PathUtils", globals(), "PathScripts.PathUtils")
+
__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):
- '''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 +71,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 +80,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 +96,24 @@ 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:
+ PathLog.debug(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 +136,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 +153,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 +165,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 +178,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 +211,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 +228,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 +257,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 +265,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 +303,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 +336,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])
@@ -357,8 +391,9 @@ class Extension(object):
try:
off2D = sub.makeOffset2D(length)
except FreeCAD.Base.FreeCADError as ee:
+ PathLog.debug(ee)
return None
-
+
if isOutside:
self.extFaces = [Part.Face(off2D).cut(featFace)]
else:
@@ -369,9 +404,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 +446,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 +486,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 +502,58 @@ 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",
+ QT_TRANSLATE_NOOP("App::Property", "Default length of extensions."),
+ )
+ if not hasattr(obj, "ExtensionFeature"):
+ obj.addProperty(
+ "App::PropertyLinkSubListGlobal",
+ "ExtensionFeature",
+ "Extension",
+ QT_TRANSLATE_NOOP("App::Property", "List of features to extend."),
+ )
+ if not hasattr(obj, "ExtensionCorners"):
+ obj.addProperty(
+ "App::PropertyBool",
+ "ExtensionCorners",
+ "Extension",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "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 +569,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 +594,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 +617,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 +637,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 +649,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..a4a9a8e869 100644
--- a/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py
+++ b/src/Mod/Path/PathScripts/PathFeatureExtensionsGui.py
@@ -20,35 +20,39 @@
# * *
# ***************************************************************************
+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
-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())
+translate = FreeCAD.Qt.translate
+
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, 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/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 a3b26ac128..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,33 +33,35 @@ 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:
- '''
+ """
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": QT_TRANSLATE_NOOP("Path_Job", "Job"),
+ "Accel": "P, J",
+ "ToolTip": 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": 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"
+ ),
+ }
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..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,21 +32,17 @@ 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):
-
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("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
@@ -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(
+ "Path_Job", "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("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") % (job.Stock.Radius, job.Stock.Height)
+ seHint = translate("Path_Job", "Cylinder: %.2f x %.2f") % (
+ job.Stock.Radius,
+ job.Stock.Height,
+ )
else:
- seHint = '-'
- PathLog.error(translate('PathJob', 'Unsupported stock type'))
+ seHint = "-"
+ PathLog.error(translate("Path_Job", "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)
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)
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")