Merge branch 'master' into master

This commit is contained in:
FreeCAD-Tools
2021-09-28 10:26:41 +03:00
committed by GitHub
4 changed files with 331 additions and 145 deletions

View File

@@ -263,7 +263,7 @@ class PathArray:
if self.arrayType == 'Linear1D':
for i in range(self.copies):
pos = FreeCAD.Vector(self.offsetVector.x * (i + 1), self.offsetVector.y * (i + 1), 0)
pos = FreeCAD.Vector(self.offsetVector.x * (i + 1), self.offsetVector.y * (i + 1), self.offsetVector.z * (i + 1))
pos = self._calculateJitter(pos)
for b in base:
@@ -278,9 +278,9 @@ class PathArray:
for i in range(self.copiesY + 1):
for j in range(self.copiesX + 1):
if (i % 2) == 0:
pos = FreeCAD.Vector(self.offsetVector.x * j, self.offsetVector.y * i, 0)
pos = FreeCAD.Vector(self.offsetVector.x * j, self.offsetVector.y * i, self.offsetVector.z * i)
else:
pos = FreeCAD.Vector(self.offsetVector.x * (self.copiesX - j), self.offsetVector.y * i, 0)
pos = FreeCAD.Vector(self.offsetVector.x * (self.copiesX - j), self.offsetVector.y * i, self.offsetVector.z * i)
pos = self._calculateJitter(pos)
for b in base:
@@ -294,9 +294,9 @@ class PathArray:
for i in range(self.copiesX + 1):
for j in range(self.copiesY + 1):
if (i % 2) == 0:
pos = FreeCAD.Vector(self.offsetVector.x * i, self.offsetVector.y * j, 0)
pos = FreeCAD.Vector(self.offsetVector.x * i, self.offsetVector.y * j, self.offsetVector.z * i)
else:
pos = FreeCAD.Vector(self.offsetVector.x * i, self.offsetVector.y * (self.copiesY - j), 0)
pos = FreeCAD.Vector(self.offsetVector.x * i, self.offsetVector.y * (self.copiesY - j), self.offsetVector.z * i)
pos = self._calculateJitter(pos)
for b in base:

View File

@@ -32,7 +32,8 @@ from PySide import QtCore
# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader
Part = LazyLoader('Part', globals(), 'Part')
Part = LazyLoader("Part", globals(), "Part")
if FreeCAD.GuiUp:
import FreeCADGui
@@ -47,18 +48,67 @@ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
class ObjectDressup:
def __init__(self, obj):
self.obj = obj
obj.addProperty("App::PropertyLink", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupRampEntry", "The base path to modify"))
obj.addProperty("App::PropertyAngle", "Angle", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupRampEntry", "Angle of ramp."))
obj.addProperty("App::PropertyEnumeration", "Method", "Path", QtCore.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"))
obj.addProperty("App::PropertySpeed", "CustomFeedRate", "FeedRate", QtCore.QT_TRANSLATE_NOOP("App::Property", "Custom feed rate"))
obj.addProperty("App::PropertyBool", "UseStartDepth", "StartDepth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Should the dressup ignore motion commands above DressupStartDepth"))
obj.addProperty("App::PropertyDistance", "DressupStartDepth", "StartDepth", QtCore.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']
obj.addProperty(
"App::PropertyLink",
"Base",
"Path",
QtCore.QT_TRANSLATE_NOOP(
"Path_DressupRampEntry", "The base path to modify"
),
)
obj.addProperty(
"App::PropertyAngle",
"Angle",
"Path",
QtCore.QT_TRANSLATE_NOOP("Path_DressupRampEntry", "Angle of ramp."),
)
obj.addProperty(
"App::PropertyEnumeration",
"Method",
"Path",
QtCore.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"
),
)
obj.addProperty(
"App::PropertySpeed",
"CustomFeedRate",
"FeedRate",
QtCore.QT_TRANSLATE_NOOP("App::Property", "Custom feed rate"),
)
obj.addProperty(
"App::PropertyBool",
"UseStartDepth",
"StartDepth",
QtCore.QT_TRANSLATE_NOOP(
"App::Property",
"Should the dressup ignore motion commands above DressupStartDepth",
),
)
obj.addProperty(
"App::PropertyDistance",
"DressupStartDepth",
"StartDepth",
QtCore.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",
]
obj.Proxy = self
self.setEditorProperties(obj)
@@ -82,16 +132,16 @@ class ObjectDressup:
self.setEditorProperties(obj)
def setEditorProperties(self, obj):
if hasattr(obj, 'UseStartDepth'):
if hasattr(obj, "UseStartDepth"):
if obj.UseStartDepth:
obj.setEditorMode('DressupStartDepth', 0)
obj.setEditorMode("DressupStartDepth", 0)
else:
obj.setEditorMode('DressupStartDepth', 2)
obj.setEditorMode("DressupStartDepth", 2)
if obj.RampFeedRate == 'Custom':
obj.setEditorMode('CustomFeedRate', 0)
if obj.RampFeedRate == "Custom":
obj.setEditorMode("CustomFeedRate", 0)
else:
obj.setEditorMode('CustomFeedRate', 2)
obj.setEditorMode("CustomFeedRate", 2)
def onDocumentRestored(self, obj):
self.setEditorProperties(obj)
@@ -109,12 +159,18 @@ class ObjectDressup:
return
if not obj.Base.Path:
return
if not obj.Base.Active:
path = Path.Path("(inactive operation)")
obj.Path = path
return
if obj.Angle >= 90:
obj.Angle = 89.9
elif obj.Angle <= 0:
obj.Angle = 0.1
if hasattr(obj, 'UseStartDepth'):
if hasattr(obj, "UseStartDepth"):
self.ignoreAboveEnabled = obj.UseStartDepth
self.ignoreAbove = obj.DressupStartDepth
else:
@@ -124,7 +180,7 @@ class ObjectDressup:
self.angle = obj.Angle
self.method = obj.Method
self.wire, self.rapids = PathGeom.wireForPath(obj.Base.Path)
if self.method in ['RampMethod1', 'RampMethod2', 'RampMethod3']:
if self.method in ["RampMethod1", "RampMethod2", "RampMethod3"]:
self.outedges = self.generateRamps()
else:
self.outedges = self.generateHelix()
@@ -143,7 +199,12 @@ class ObjectDressup:
p0 = edge.Vertexes[0].Point
p1 = edge.Vertexes[1].Point
rampangle = self.angle
if bb.XLength < 1e-6 and bb.YLength < 1e-6 and bb.ZLength > 0 and p0.z > p1.z:
if (
bb.XLength < 1e-6
and bb.YLength < 1e-6
and bb.ZLength > 0
and p0.z > p1.z
):
# check if above ignoreAbove parameter - do not generate ramp if it is
newEdge, cont = self.checkIgnoreAbove(edge)
@@ -154,9 +215,15 @@ class ObjectDressup:
continue
plungelen = abs(p0.z - p1.z)
projectionlen = plungelen * math.tan(math.radians(rampangle)) # length of the forthcoming ramp projected to XY plane
PathLog.debug("Found plunge move at X:{} Y:{} From Z:{} to Z{}, length of ramp: {}".format(p0.x, p0.y, p0.z, p1.z, projectionlen))
if self.method == 'RampMethod3':
projectionlen = plungelen * math.tan(
math.radians(rampangle)
) # length of the forthcoming ramp projected to XY plane
PathLog.debug(
"Found plunge move at X:{} Y:{} From Z:{} to Z{}, length of ramp: {}".format(
p0.x, p0.y, p0.z, p1.z, projectionlen
)
)
if self.method == "RampMethod3":
projectionlen = projectionlen / 2
# next need to determine how many edges in the path after
@@ -182,34 +249,58 @@ class ObjectDressup:
if i >= len(edges):
break
if len(rampedges) == 0:
PathLog.debug("No suitable edges for ramping, plunge will remain as such")
PathLog.debug(
"No suitable edges for ramping, plunge will remain as such"
)
outedges.append(edge)
else:
if not covered:
if (not allowBounce) or self.method == 'RampMethod2':
if (not allowBounce) or self.method == "RampMethod2":
l = 0
for redge in rampedges:
l = l + redge.Length
if self.method == 'RampMethod3':
rampangle = math.degrees(math.atan(l / (plungelen / 2)))
if self.method == "RampMethod3":
rampangle = math.degrees(
math.atan(l / (plungelen / 2))
)
else:
rampangle = math.degrees(math.atan(l / plungelen))
PathLog.warning("Cannot cover with desired angle, tightening angle to: {}".format(rampangle))
PathLog.warning(
"Cannot cover with desired angle, tightening angle to: {}".format(
rampangle
)
)
# PathLog.debug("Doing ramp to edges: {}".format(rampedges))
if self.method == 'RampMethod1':
outedges.extend(self.createRampMethod1(rampedges, p0, projectionlen, rampangle))
elif self.method == 'RampMethod2':
outedges.extend(self.createRampMethod2(rampedges, p0, projectionlen, rampangle))
if self.method == "RampMethod1":
outedges.extend(
self.createRampMethod1(
rampedges, p0, projectionlen, rampangle
)
)
elif self.method == "RampMethod2":
outedges.extend(
self.createRampMethod2(
rampedges, p0, projectionlen, rampangle
)
)
else:
# if the ramp cannot be covered with Method3, revert to Method1
# because Method1 support going back-and-forth and thus results in same path as Method3 when
# length of the ramp is smaller than needed for single ramp.
if (not covered) and allowBounce:
projectionlen = projectionlen * 2
outedges.extend(self.createRampMethod1(rampedges, p0, projectionlen, rampangle))
outedges.extend(
self.createRampMethod1(
rampedges, p0, projectionlen, rampangle
)
)
else:
outedges.extend(self.createRampMethod3(rampedges, p0, projectionlen, rampangle))
outedges.extend(
self.createRampMethod3(
rampedges, p0, projectionlen, rampangle
)
)
else:
outedges.append(edge)
else:
@@ -232,9 +323,18 @@ class ObjectDressup:
bb = edge.BoundBox
p0 = edge.Vertexes[0].Point
p1 = edge.Vertexes[1].Point
if bb.XLength < 1e-6 and bb.YLength < 1e-6 and bb.ZLength > 0 and p0.z > p1.z:
if (
bb.XLength < 1e-6
and bb.YLength < 1e-6
and bb.ZLength > 0
and p0.z > p1.z
):
# plungelen = abs(p0.z-p1.z)
PathLog.debug("Found plunge move at X:{} Y:{} From Z:{} to Z{}, Searching for closed loop".format(p0.x, p0.y, p0.z, p1.z))
PathLog.debug(
"Found plunge move at X:{} Y:{} From Z:{} to Z{}, Searching for closed loop".format(
p0.x, p0.y, p0.z, p1.z
)
)
# check if above ignoreAbove parameter - do not generate helix if it is
newEdge, cont = self.checkIgnoreAbove(edge)
if newEdge is not None:
@@ -285,11 +385,18 @@ class ObjectDressup:
if self.ignoreAboveEnabled:
p0 = edge.Vertexes[0].Point
p1 = edge.Vertexes[1].Point
if p0.z > self.ignoreAbove and (p1.z > self.ignoreAbove or PathGeom.isRoughly(p1.z, self.ignoreAbove.Value)):
if p0.z > self.ignoreAbove and (
p1.z > self.ignoreAbove
or PathGeom.isRoughly(p1.z, self.ignoreAbove.Value)
):
PathLog.debug("Whole plunge move above 'ignoreAbove', ignoring")
return (edge, True)
elif p0.z > self.ignoreAbove and not PathGeom.isRoughly(p0.z, self.ignoreAbove.Value):
PathLog.debug("Plunge move partially above 'ignoreAbove', splitting into two")
elif p0.z > self.ignoreAbove and not PathGeom.isRoughly(
p0.z, self.ignoreAbove.Value
):
PathLog.debug(
"Plunge move partially above 'ignoreAbove', splitting into two"
)
newPoint = FreeCAD.Base.Vector(p0.x, p0.y, self.ignoreAbove)
return (Part.makeLine(p0, newPoint), False)
else:
@@ -308,7 +415,11 @@ class ObjectDressup:
for i, redge in enumerate(rampedges):
if i < len(rampedges) - 1:
deltaZ = redge.Length / math.tan(rampangle_rad)
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.LastParameter).x,
redge.valueAt(redge.LastParameter).y,
curPoint.z - deltaZ,
)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
else:
@@ -319,10 +430,15 @@ class ObjectDressup:
def createRampEdge(self, originalEdge, startPoint, endPoint):
# PathLog.debug("Create edge from [{},{},{}] to [{},{},{}]".format(startPoint.x,startPoint.y, startPoint.z, endPoint.x, endPoint.y, endPoint.z))
if type(originalEdge.Curve) == Part.Line or type(originalEdge.Curve) == Part.LineSegment:
if (
type(originalEdge.Curve) == Part.Line
or type(originalEdge.Curve) == Part.LineSegment
):
return Part.makeLine(startPoint, endPoint)
elif type(originalEdge.Curve) == Part.Circle:
arcMid = originalEdge.valueAt((originalEdge.FirstParameter + originalEdge.LastParameter) / 2)
arcMid = originalEdge.valueAt(
(originalEdge.FirstParameter + originalEdge.LastParameter) / 2
)
arcMid.z = (startPoint.z + endPoint.z) / 2
return Part.Arc(startPoint, arcMid, endPoint).toShape()
else:
@@ -385,22 +501,38 @@ class ObjectDressup:
p1 = self.getSplitPoint(redge, rampremaining)
splitEdge = PathGeom.splitEdgeAt(redge, p1)
PathLog.debug("Ramp remaining: {}".format(rampremaining))
PathLog.debug("Got split edge (index: {}) (total len: {}) with lengths: {}, {}".format(i, redge.Length, splitEdge[0].Length, splitEdge[1].Length))
PathLog.debug(
"Got split edge (index: {}) (total len: {}) with lengths: {}, {}".format(
i, redge.Length, splitEdge[0].Length, splitEdge[1].Length
)
)
# ramp ends to the last point of first edge
p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
outedges.append(self.createRampEdge(splitEdge[0], curPoint, p1))
# now we have reached the end of the ramp. Go back to plunge position with constant Z
# start that by going to the beginning of this splitEdge
if goingForward:
outedges.append(self.createRampEdge(splitEdge[0], p1, redge.valueAt(redge.FirstParameter)))
outedges.append(
self.createRampEdge(
splitEdge[0], p1, redge.valueAt(redge.FirstParameter)
)
)
else:
# if we were reversing, we continue to the same direction as the ramp
outedges.append(self.createRampEdge(splitEdge[0], p1, redge.valueAt(redge.LastParameter)))
outedges.append(
self.createRampEdge(
splitEdge[0], p1, redge.valueAt(redge.LastParameter)
)
)
done = True
break
else:
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.LastParameter).x,
redge.valueAt(redge.LastParameter).y,
curPoint.z - deltaZ,
)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
rampremaining = rampremaining - redge.Length
@@ -421,7 +553,7 @@ class ObjectDressup:
else:
# if the ramp was already reversing, the edges needed for return are the ones
# which were not covered in ramp
returnedges = rampedges[(i + 1):]
returnedges = rampedges[(i + 1) :]
# add the return edges:
outedges.extend(returnedges)
@@ -451,7 +583,11 @@ class ObjectDressup:
# will reach end of ramp within this edge, needs to be split
p1 = self.getSplitPoint(redge, rampremaining)
splitEdge = PathGeom.splitEdgeAt(redge, p1)
PathLog.debug("Got split edge (index: {}) with lengths: {}, {}".format(i, splitEdge[0].Length, splitEdge[1].Length))
PathLog.debug(
"Got split edge (index: {}) with lengths: {}, {}".format(
i, splitEdge[0].Length, splitEdge[1].Length
)
)
# ramp ends to the last point of first edge
p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
deltaZ = splitEdge[0].Length / math.tan(math.radians(rampangle))
@@ -472,13 +608,21 @@ class ObjectDressup:
p1.z = curPoint.z - deltaZ
outedges.append(self.createRampEdge(redge, curPoint, p1))
# and go back that edge
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.FirstParameter).x, redge.valueAt(redge.FirstParameter).y, p1.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.FirstParameter).x,
redge.valueAt(redge.FirstParameter).y,
p1.z - deltaZ,
)
outedges.append(self.createRampEdge(redge, p1, newPoint))
curPoint = newPoint
done = True
else:
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.LastParameter).x,
redge.valueAt(redge.LastParameter).y,
curPoint.z - deltaZ,
)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
rampremaining = rampremaining - redge.Length
@@ -488,7 +632,11 @@ class ObjectDressup:
# ramp backwards to the plunge position
for i, redge in enumerate(returnedges):
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.LastParameter).x,
redge.valueAt(redge.LastParameter).y,
curPoint.z - deltaZ,
)
if i == len(rampedges) - 1:
# make sure that the last point of the ramps ends to the original position
newPoint = redge.valueAt(redge.LastParameter)
@@ -510,15 +658,24 @@ class ObjectDressup:
outedges = []
rampremaining = projectionlen
curPoint = p0 # start from the upper point of plunge
if PathGeom.pointsCoincide(PathGeom.xy(p0), PathGeom.xy(rampedges[-1].valueAt(rampedges[-1].LastParameter))):
PathLog.debug("The ramp forms a closed wire, needless to move on original Z height")
if PathGeom.pointsCoincide(
PathGeom.xy(p0),
PathGeom.xy(rampedges[-1].valueAt(rampedges[-1].LastParameter)),
):
PathLog.debug(
"The ramp forms a closed wire, needless to move on original Z height"
)
else:
for i, redge in enumerate(rampedges):
if redge.Length >= rampremaining:
# this edge needs to be split
p1 = self.getSplitPoint(redge, rampremaining)
splitEdge = PathGeom.splitEdgeAt(redge, p1)
PathLog.debug("Got split edges with lengths: {}, {}".format(splitEdge[0].Length, splitEdge[1].Length))
PathLog.debug(
"Got split edges with lengths: {}, {}".format(
splitEdge[0].Length, splitEdge[1].Length
)
)
# ramp starts at the last point of first edge
p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
p1.z = p0.z
@@ -526,7 +683,11 @@ class ObjectDressup:
# now we have reached the beginning of the ramp.
# start that by going to the beginning of this splitEdge
deltaZ = splitEdge[0].Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(splitEdge[0].valueAt(splitEdge[0].FirstParameter).x, splitEdge[0].valueAt(splitEdge[0].FirstParameter).y, p1.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
splitEdge[0].valueAt(splitEdge[0].FirstParameter).x,
splitEdge[0].valueAt(splitEdge[0].FirstParameter).y,
p1.z - deltaZ,
)
outedges.append(self.createRampEdge(splitEdge[0], p1, newPoint))
curPoint = newPoint
elif i == len(rampedges) - 1:
@@ -538,13 +699,21 @@ class ObjectDressup:
outedges.append(self.createRampEdge(redge, curPoint, p1))
# and go back that edge
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.FirstParameter).x, redge.valueAt(redge.FirstParameter).y, p1.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.FirstParameter).x,
redge.valueAt(redge.FirstParameter).y,
p1.z - deltaZ,
)
outedges.append(self.createRampEdge(redge, p1, newPoint))
curPoint = newPoint
else:
# we are traveling on start depth
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, p0.z)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.LastParameter).x,
redge.valueAt(redge.LastParameter).y,
p0.z,
)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
rampremaining = rampremaining - redge.Length
@@ -554,7 +723,11 @@ class ObjectDressup:
# ramp backwards to the plunge position
for i, redge in enumerate(reversed(rampedges)):
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.FirstParameter).x, redge.valueAt(redge.FirstParameter).y, curPoint.z - deltaZ)
newPoint = FreeCAD.Base.Vector(
redge.valueAt(redge.FirstParameter).x,
redge.valueAt(redge.FirstParameter).y,
curPoint.z - deltaZ,
)
if i == len(rampedges) - 1:
# make sure that the last point of the ramps ends to the original position
newPoint = redge.valueAt(redge.FirstParameter)
@@ -572,11 +745,11 @@ class ObjectDressup:
israpid = True
if israpid:
v = edge.valueAt(edge.LastParameter)
commands.append(Path.Command('G0', {'X': v.x, 'Y': v.y, 'Z': v.z}))
commands.append(Path.Command("G0", {"X": v.x, "Y": v.y, "Z": v.z}))
else:
commands.extend(PathGeom.cmdsForEdge(edge))
lastCmd = Path.Command('G0', {'X': 0.0, 'Y': 0.0, 'Z': 0.0})
lastCmd = Path.Command("G0", {"X": 0.0, "Y": 0.0, "Z": 0.0})
outCommands = []
@@ -589,7 +762,7 @@ class ObjectDressup:
rampFeed = tc.HorizFeed.Value
elif obj.RampFeedRate == "Vertical Feed Rate":
rampFeed = tc.VertFeed.Value
elif obj.RampFeedRate == 'Ramp Feed Rate':
elif obj.RampFeedRate == "Ramp Feed Rate":
rampFeed = math.sqrt(pow(tc.VertFeed.Value, 2) + pow(tc.HorizFeed.Value, 2))
else:
rampFeed = obj.CustomFeedRate.Value
@@ -599,35 +772,37 @@ class ObjectDressup:
for cmd in commands:
params = cmd.Parameters
zVal = params.get('Z', None)
zVal2 = lastCmd.Parameters.get('Z', None)
zVal = params.get("Z", None)
zVal2 = lastCmd.Parameters.get("Z", None)
xVal = params.get('X', None)
xVal2 = lastCmd.Parameters.get('X', None)
xVal = params.get("X", None)
xVal2 = lastCmd.Parameters.get("X", None)
yVal2 = lastCmd.Parameters.get('Y', None)
yVal = params.get('Y', None)
yVal2 = lastCmd.Parameters.get("Y", None)
yVal = params.get("Y", None)
zVal = zVal and round(zVal, 8)
zVal2 = zVal2 and round(zVal2, 8)
if cmd.Name in ['G1', 'G2', 'G3', 'G01', 'G02', 'G03']:
if cmd.Name in ["G1", "G2", "G3", "G01", "G02", "G03"]:
if zVal is not None and zVal2 != zVal:
if PathGeom.isRoughly(xVal, xVal2) and PathGeom.isRoughly(yVal, yVal2):
if PathGeom.isRoughly(xVal, xVal2) and PathGeom.isRoughly(
yVal, yVal2
):
# this is a straight plunge
params['F'] = vertFeed
params["F"] = vertFeed
else:
# this is a ramp
params['F'] = rampFeed
params["F"] = rampFeed
else:
params['F'] = horizFeed
params["F"] = horizFeed
lastCmd = cmd
elif cmd.Name in ['G0', 'G00']:
elif cmd.Name in ["G0", "G00"]:
if zVal is not None and zVal2 != zVal:
params['F'] = vertRapid
params["F"] = vertRapid
else:
params['F'] = horizRapid
params["F"] = horizRapid
lastCmd = cmd
outCommands.append(Path.Command(cmd.Name, params))
@@ -636,7 +811,6 @@ class ObjectDressup:
class ViewProviderDressup:
def __init__(self, vobj):
self.obj = vobj.Object
@@ -657,7 +831,7 @@ class ViewProviderDressup:
return [self.obj.Base]
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
PathLog.debug("Deleting Dressup")
if arg1.Object and arg1.Object.Base:
@@ -679,9 +853,16 @@ class CommandPathDressupRampEntry:
# pylint: disable=no-init
def GetResources(self):
return {'Pixmap': 'Path_Dressup',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_DressupRampEntry", "RampEntry Dress-up"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_DressupRampEntry", "Creates a Ramp Entry Dress-up object from a selected path")}
return {
"Pixmap": "Path_Dressup",
"MenuText": QtCore.QT_TRANSLATE_NOOP(
"Path_DressupRampEntry", "RampEntry Dress-up"
),
"ToolTip": QtCore.QT_TRANSLATE_NOOP(
"Path_DressupRampEntry",
"Creates a Ramp Entry Dress-up object from a selected path",
),
}
def IsActive(self):
op = PathDressup.selection()
@@ -708,21 +889,29 @@ class CommandPathDressupRampEntry:
FreeCAD.ActiveDocument.openTransaction(translate("Create RampEntry Dress-up"))
FreeCADGui.addModule("PathScripts.PathDressupRampEntry")
FreeCADGui.addModule("PathScripts.PathUtils")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "RampEntryDressup")')
FreeCADGui.doCommand('dbo = PathScripts.PathDressupRampEntry.ObjectDressup(obj)')
FreeCADGui.doCommand('base = FreeCAD.ActiveDocument.' + selection[0].Name)
FreeCADGui.doCommand('job = PathScripts.PathUtils.findParentJob(base)')
FreeCADGui.doCommand('obj.Base = base')
FreeCADGui.doCommand('job.Proxy.addOperation(obj, base)')
FreeCADGui.doCommand('obj.ViewObject.Proxy = PathScripts.PathDressupRampEntry.ViewProviderDressup(obj.ViewObject)')
FreeCADGui.doCommand('Gui.ActiveDocument.getObject(base.Name).Visibility = False')
FreeCADGui.doCommand('dbo.setup(obj)')
FreeCADGui.doCommand(
'obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "RampEntryDressup")'
)
FreeCADGui.doCommand(
"dbo = PathScripts.PathDressupRampEntry.ObjectDressup(obj)"
)
FreeCADGui.doCommand("base = FreeCAD.ActiveDocument." + selection[0].Name)
FreeCADGui.doCommand("job = PathScripts.PathUtils.findParentJob(base)")
FreeCADGui.doCommand("obj.Base = base")
FreeCADGui.doCommand("job.Proxy.addOperation(obj, base)")
FreeCADGui.doCommand(
"obj.ViewObject.Proxy = PathScripts.PathDressupRampEntry.ViewProviderDressup(obj.ViewObject)"
)
FreeCADGui.doCommand(
"Gui.ActiveDocument.getObject(base.Name).Visibility = False"
)
FreeCADGui.doCommand("dbo.setup(obj)")
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_DressupRampEntry', CommandPathDressupRampEntry())
FreeCADGui.addCommand("Path_DressupRampEntry", CommandPathDressupRampEntry())
PathLog.notice("Loading Path_DressupRampEntry... done\n")

View File

@@ -192,19 +192,22 @@ class ObjectFace(PathPocketBase.ObjectPocket):
else:
env = PathUtils.getEnvelope(partshape=planeshape, depthparams=self.depthparams)
elif obj.BoundaryShape == 'Face Region':
import PathScripts.PathSurfaceSupport as PathSurfaceSupport
baseShape = oneBase[0].Shape
psZMin = planeshape.BoundBox.ZMin
ofstShape = PathUtils.getOffsetArea(planeshape,
self.tool.Diameter * 1.1,
plane=planeshape)
ofst = 0.0
if obj.ClearEdges:
ofst = self.tool.Diameter * 0.51
ofstShape = PathUtils.getOffsetArea(planeshape, ofst, plane=planeshape)
ofstShape.translate(FreeCAD.Vector(0.0, 0.0, psZMin - ofstShape.BoundBox.ZMin))
# Calculate custom depth params for removal shape envelope, with start and final depth buffers
custDepthparams = self._customDepthParams(obj, obj.StartDepth.Value + 0.2, obj.FinalDepth.Value - 0.1) # only an envelope
ofstShapeEnv = PathUtils.getEnvelope(partshape=ofstShape, depthparams=custDepthparams)
env = ofstShapeEnv.cut(baseShape)
env.translate(FreeCAD.Vector(0.0, 0.0, -0.000001)) # lower removal shape into buffer zone
if obj.ExcludeRaisedAreas:
env = ofstShapeEnv.cut(baseShape)
env.translate(FreeCAD.Vector(0.0, 0.0, -0.00001)) # lower removal shape into buffer zone
else:
env = ofstShapeEnv
if holeShape:
PathLog.debug("Processing holes and face ...")
@@ -257,6 +260,8 @@ class ObjectFace(PathPocketBase.ObjectPocket):
return False
def getAllIncludedFaces(self, base, env, faceZ):
'''getAllIncludedFaces(base, env, faceZ)...
Return all `base` faces extending above `faceZ` whose boundboxes overlap with the `env` boundbox.'''
included = []
eXMin = env.BoundBox.XMin
@@ -265,20 +270,14 @@ class ObjectFace(PathPocketBase.ObjectPocket):
eYMax = env.BoundBox.YMax
eZMin = faceZ
def isOverlap(fMn, fMx, eMn, eMx):
if fMx > eMn:
if fMx <= eMx:
return True
elif fMx >= eMx and fMn <= eMx:
return True
if fMn < eMx:
if fMn >= eMn:
return True
elif fMn <= eMn and fMx >= eMn:
def isOverlap(faceMin, faceMax, envMin, envMax):
if faceMax > envMin:
if faceMin <= envMax or faceMin == envMin:
return True
return False
for fi in range(0, len(base.Shape.Faces)):
# Check all faces of `base` shape
incl = False
face = base.Shape.Faces[fi]
fXMin = face.BoundBox.XMin
@@ -288,8 +287,9 @@ class ObjectFace(PathPocketBase.ObjectPocket):
fZMax = face.BoundBox.ZMax
if fZMax > eZMin:
if isOverlap(fXMin, fXMax, eXMin, eXMax):
if isOverlap(fYMin, fYMax, eYMin, eYMax):
# Include face if its boundbox overlaps envelope boundbox
if isOverlap(fXMin, fXMax, eXMin, eXMax): # check X values
if isOverlap(fYMin, fYMax, eYMin, eYMax): # check Y values
incl = True
if incl:
included.append(face)

View File

@@ -676,12 +676,6 @@ class ObjectProfile(PathAreaOp.ObjectOp):
pb = FreeCAD.Vector(Vb.X, Vb.Y, fdv)
pe = FreeCAD.Vector(Ve.X, Ve.Y, fdv)
# Identify endpoints connecting circle center and diameter
# vectDist = pe.sub(pb)
# diam = vectDist.Length
# cntr = vectDist.multiply(0.5).add(pb)
# R = diam / 2
# Obtain beginning point perpendicular points
if blen > 0.1:
bcp = begE.valueAt(
@@ -787,12 +781,13 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# Identify closed wire in cross-section that corresponds to user-selected edge(s)
workShp = comFC
fcShp = workShp
wire = origWire
WS = workShp.Wires
lenWS = len(WS)
wi = 0
if lenWS < 3:
wi = 0
# fcShp = workShp
pass
else:
wi = None
for wvt in wire.Vertexes:
@@ -914,26 +909,26 @@ class ObjectProfile(PathAreaOp.ObjectOp):
osWrIdxs.append(w)
# Identify two vertexes for dividing offset loop
NEAR0 = self._findNearestVertex(ofstShp, cent0)
min0i = 0
NEAR0 = self._findNearestVertex(ofstShp, cent0)
# min0i = 0
min0 = NEAR0[0][4]
for n in range(0, len(NEAR0)):
N = NEAR0[n]
if N[4] < min0:
min0 = N[4]
min0i = n
# min0i = n
(w0, vi0, pnt0, _, _) = NEAR0[0] # min0i
near0Shp = Part.makeLine(cent0, pnt0)
self._addDebugObject("Near0", near0Shp)
NEAR1 = self._findNearestVertex(ofstShp, cent1)
min1i = 0
NEAR1 = self._findNearestVertex(ofstShp, cent1)
# min1i = 0
min1 = NEAR1[0][4]
for n in range(0, len(NEAR1)):
N = NEAR1[n]
if N[4] < min1:
min1 = N[4]
min1i = n
# min1i = n
(w1, vi1, pnt1, _, _) = NEAR1[0] # min1i
near1Shp = Part.makeLine(cent1, pnt1)
self._addDebugObject("Near1", near1Shp)
@@ -945,13 +940,16 @@ class ObjectProfile(PathAreaOp.ObjectOp):
)
)
if self.isDebug and False:
PathLog.debug("min0i is {}.".format(min0i))
PathLog.debug("min1i is {}.".format(min1i))
PathLog.debug("NEAR0[{}] is {}.".format(w0, NEAR0[w0]))
PathLog.debug("NEAR1[{}] is {}.".format(w1, NEAR1[w1]))
PathLog.debug("NEAR0 is {}.".format(NEAR0))
PathLog.debug("NEAR1 is {}.".format(NEAR1))
# Debugging
'''
if self.isDebug:
PathLog.debug('min0i is {}.'.format(min0i))
PathLog.debug('min1i is {}.'.format(min1i))
PathLog.debug('NEAR0[{}] is {}.'.format(w0, NEAR0[w0]))
PathLog.debug('NEAR1[{}] is {}.'.format(w1, NEAR1[w1]))
PathLog.debug('NEAR0 is {}.'.format(NEAR0))
PathLog.debug('NEAR1 is {}.'.format(NEAR1))
'''
mainWire = ofstShp.Wires[w0]
@@ -1122,7 +1120,6 @@ class ObjectProfile(PathAreaOp.ObjectOp):
if chk4 is True:
# find beginning 1 edge
begIdx = None
begFlg = False
for e in range(0, lenFULL):
f = PRE[e]
i = IDXS[e]
@@ -1132,7 +1129,6 @@ class ObjectProfile(PathAreaOp.ObjectOp):
wireIdxs[0].append(i)
break
# find first 3 edge
endIdx = None
for e in range(begIdx + 1, lenE + begIdx):
f = PRE[e]
i = IDXS[e]
@@ -1177,15 +1173,16 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# Efor
# Eif
# Remove `and False` when debugging open edges, as needed
if self.isDebug and False:
PathLog.debug("grps[0]: {}".format(grps[0]))
PathLog.debug("grps[1]: {}".format(grps[1]))
PathLog.debug("wireIdxs[0]: {}".format(wireIdxs[0]))
PathLog.debug("wireIdxs[1]: {}".format(wireIdxs[1]))
PathLog.debug("PRE: {}".format(PRE))
PathLog.debug("IDXS: {}".format(IDXS))
# Debugging
'''
if self.isDebug:
PathLog.debug('grps[0]: {}'.format(grps[0]))
PathLog.debug('grps[1]: {}'.format(grps[1]))
PathLog.debug('wireIdxs[0]: {}'.format(wireIdxs[0]))
PathLog.debug('wireIdxs[1]: {}'.format(wireIdxs[1]))
PathLog.debug('PRE: {}'.format(PRE))
PathLog.debug('IDXS: {}'.format(IDXS))
'''
return (wireIdxs[0], wireIdxs[1])
def _makeCrossSection(self, shape, sliceZ, zHghtTrgt=False):