Merge pull request #4484 from Russ4262/fix_profile_feature_filter

[Path] Fixes for Profile operation [0.19]
This commit is contained in:
sliptonic
2021-02-20 17:27:00 -06:00
committed by GitHub

View File

@@ -37,6 +37,7 @@ from PySide import QtCore
from lazy_loader.lazy_loader import LazyLoader
ArchPanel = LazyLoader('ArchPanel', globals(), 'ArchPanel')
Part = LazyLoader('Part', globals(), 'Part')
DraftGeomUtils = LazyLoader('DraftGeomUtils', globals(), 'DraftGeomUtils')
__title__ = "Path Profile Operation"
@@ -145,7 +146,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
return {
'AttemptInverseAngle': True,
'Direction': 'CW',
'HandleMultipleFeatures': 'Individually',
'HandleMultipleFeatures': 'Collectively',
'InverseAngle': False,
'JoinType': 'Round',
'LimitDepthToFace': True,
@@ -171,7 +172,8 @@ class ObjectProfile(PathAreaOp.ObjectOp):
if isinstance(val, int) or isinstance(val, float):
setVal = True
if setVal:
propVal = getattr(prop, 'Value')
# propVal = getattr(prop, 'Value')
# Need to check if `val` below should be `propVal` commented out above
setattr(prop, 'Value', val)
else:
setattr(obj, n, val)
@@ -214,7 +216,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
return 'Contour'
# return first geometry type selected
(base, subsList) = obj.Base[0]
(_, subsList) = obj.Base[0]
return subsList[0][:4]
def areaOpOnDocumentRestored(self, obj):
@@ -295,7 +297,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
shapes = []
baseSubsTuples = list()
allTuples = list()
edgeFaces = list()
remainingObjBaseFeatures = list()
subCount = 0
self.isDebug = True if PathLog.getLevel(PathLog.thisModule()) == 4 else False
self.inaccessibleMsg = translate('PathProfile', 'The selected edge(s) are inaccessible. If multiple, re-ordering selection might work.')
@@ -322,12 +324,15 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# Pre-process Base Geometry to process edges
if obj.Base and len(obj.Base) > 0: # The user has selected subobjects from the base. Process each.
shapes.extend(self._processEdges(obj))
shapes.extend(self._processEdges(obj, remainingObjBaseFeatures))
if obj.Base and len(obj.Base) > 0: # The user has selected subobjects from the base. Process each.
if obj.Base and len(obj.Base) > 0 and not remainingObjBaseFeatures:
# Edges were already processed, or whole model targeted.
PathLog.debug("remainingObjBaseFeatures is False")
elif remainingObjBaseFeatures and len(remainingObjBaseFeatures) > 0: # Process remaining features after edges processed above.
if obj.EnableRotation != 'Off':
for p in range(0, len(obj.Base)):
(base, subsList) = obj.Base[p]
for p in range(0, len(remainingObjBaseFeatures)):
(base, subsList) = remainingObjBaseFeatures[p]
for sub in subsList:
subCount += 1
shape = getattr(base.Shape, sub)
@@ -344,7 +349,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
subList = []
for o in range(0, len(Tags)):
subList = []
for (base, sub, tag, angle, axis, stock) in Grps[o]:
for (base, sub, _, angle, axis, stock) in Grps[o]:
subList.append(sub)
pair = base, subList, angle, axis, stock
@@ -352,12 +357,11 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# Efor
else:
stock = PathUtils.findParentJob(obj).Stock
for (base, subList) in obj.Base:
for (base, subList) in remainingObjBaseFeatures:
baseSubsTuples.append((base, subList, 0.0, 'X', stock))
# Eif
# for base in obj.Base:
finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
# for base in remainingObjBaseFeatures:
for (base, subsList, angle, axis, stock) in baseSubsTuples:
holes = []
faces = []
@@ -377,7 +381,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
else:
ignoreSub = base.Name + '.' + sub
msg = translate('PathProfile', "Found a selected object which is not a face. Ignoring:")
# FreeCAD.Console.PrintWarning(msg + " {}\n".format(ignoreSub))
PathLog.warning(msg + " {}".format(ignoreSub))
# Identify initial Start and Final Depths
finDep = obj.FinalDepth.Value
@@ -406,13 +410,11 @@ class ObjectProfile(PathAreaOp.ObjectOp):
tup = shapeEnv, True, 'pathProfile', angle, axis, strDep, finDep
shapes.append(tup)
if obj.processPerimeter:
if faces and obj.processPerimeter:
if obj.HandleMultipleFeatures == 'Collectively':
custDepthparams = self.depthparams
cont = True
if len(faces) > 0:
profileshape = Part.makeCompound(faces)
profileshape = Part.makeCompound(faces)
if obj.LimitDepthToFace is True and obj.EnableRotation != 'Off':
if profileshape.BoundBox.ZMin > obj.FinalDepth.Value:
@@ -588,17 +590,15 @@ class ObjectProfile(PathAreaOp.ObjectOp):
return shapeTups
# Edges pre-processing
def _processEdges(self, obj):
import DraftGeomUtils
def _processEdges(self, obj, remainingObjBaseFeatures):
shapes = list()
basewires = list()
delPairs = list()
ezMin = None
self.cutOut = self.tool.Diameter
for p in range(0, len(obj.Base)):
(base, subsList) = obj.Base[p]
tmpSubs = list()
keepFaces = list()
edgelist = list()
for sub in subsList:
shape = getattr(base.Shape, sub)
@@ -607,16 +607,14 @@ class ObjectProfile(PathAreaOp.ObjectOp):
edgelist.append(getattr(base.Shape, sub))
# save faces for regular processing
if isinstance(shape, Part.Face):
tmpSubs.append(sub)
keepFaces.append(sub)
if len(edgelist) > 0:
basewires.append((base, DraftGeomUtils.findWires(edgelist)))
if ezMin is None or base.Shape.BoundBox.ZMin < ezMin:
ezMin = base.Shape.BoundBox.ZMin
# If faces
if len(tmpSubs) == 0: # all edges in subsList = remove pair in obj.Base
delPairs.append(p)
elif len(edgelist) > 0: # some edges in subsList were extracted, return faces only to subsList
obj.Base[p] = (base, tmpSubs)
if len(keepFaces) > 0: # save faces for returning and processing
remainingObjBaseFeatures.append((base, keepFaces))
for base, wires in basewires:
for wire in wires:
@@ -637,12 +635,13 @@ class ObjectProfile(PathAreaOp.ObjectOp):
else:
# Attempt open-edges profile
if self.JOB.GeometryTolerance.Value == 0.0:
msg = self.JOB.Label + '.GeometryTolerance = 0.0.'
msg = self.JOB.Label + '.GeometryTolerance = 0.0. '
msg += translate('PathProfile', 'Please set to an acceptable value greater than zero.')
PathLog.error(msg)
else:
flattened = self._flattenWire(obj, wire, obj.FinalDepth.Value)
if flattened:
zDiff = math.fabs(wire.BoundBox.ZMin - obj.FinalDepth.Value)
if flattened and zDiff >= self.JOB.GeometryTolerance.Value:
cutWireObjs = False
openEdges = list()
passOffsets = [self.ofstRadius]
@@ -662,20 +661,20 @@ class ObjectProfile(PathAreaOp.ObjectOp):
else:
PathLog.error(self.inaccessibleMsg)
tup = openEdges, False, 'OpenEdge', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value
shapes.append(tup)
if openEdges:
tup = openEdges, False, 'OpenEdge', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value
shapes.append(tup)
else:
PathLog.error(self.inaccessibleMsg)
if zDiff < self.JOB.GeometryTolerance.Value:
msg = translate('PathProfile', 'Check edge selection and Final Depth requirements for profiling open edge(s).')
PathLog.error(msg)
else:
PathLog.error(self.inaccessibleMsg)
# Eif
# Eif
# Efor
# Efor
delPairs.sort(reverse=True)
for p in delPairs:
# obj.Base.pop(p)
pass
return shapes
def _flattenWire(self, obj, wire, trgtDep):
@@ -706,14 +705,14 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# Open-edges methods
def _getCutAreaCrossSection(self, obj, base, origWire, flatWire):
PathLog.debug('_getCutAreaCrossSection()')
FCAD = FreeCAD.ActiveDocument
# FCAD = FreeCAD.ActiveDocument
tolerance = self.JOB.GeometryTolerance.Value
toolDiam = 2 * self.radius # self.radius defined in PathAreaOp or PathProfileBase modules
minBfr = toolDiam * 1.25
bbBfr = (self.ofstRadius * 2) * 1.25
if bbBfr < minBfr:
bbBfr = minBfr
fwBB = flatWire.BoundBox
# fwBB = flatWire.BoundBox
wBB = origWire.BoundBox
minArea = (self.ofstRadius - tolerance)**2 * math.pi
@@ -742,10 +741,10 @@ class ObjectProfile(PathAreaOp.ObjectOp):
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
# 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:
@@ -939,10 +938,16 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# CHECK for ZERO area of offset shape
try:
osArea = ofstShp.Area
if hasattr(ofstShp, "Area"):
osArea = ofstShp.Area
if osArea: # Make LGTM parser happy
pass
else:
PathLog.error('No area to offset shape returned.')
return list()
except Exception as ee:
PathLog.error('No area to offset shape returned.\n{}'.format(ee))
return False
return list()
self._addDebugObject('OffsetShape', ofstShp)
@@ -959,7 +964,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
if N[4] < min0:
min0 = N[4]
min0i = n
(w0, vi0, pnt0, vrt0, d0) = NEAR0[0] # min0i
(w0, vi0, pnt0, _, _) = NEAR0[0] # min0i
near0Shp = Part.makeLine(cent0, pnt0)
self._addDebugObject('Near0', near0Shp)
@@ -971,7 +976,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
if N[4] < min1:
min1 = N[4]
min1i = n
(w1, vi1, pnt1, vrt1, d1) = NEAR1[0] # min1i
(w1, vi1, pnt1, _, _) = NEAR1[0] # min1i
near1Shp = Part.makeLine(cent1, pnt1)
self._addDebugObject('Near1', near1Shp)
@@ -1270,7 +1275,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
nt = 4 # desired + 1
mid = LE / nt
spc = self.radius / 10
for i in range(0, nt):
for i in range(0, int(nt)):
if i == 0:
if e == 0:
if LE > 0.2:
@@ -1298,7 +1303,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
tagCnt += nt
intTags.append(intTObj)
extTags.append(extTObj)
tagArea = math.pi * tagRad**2 * tagCnt
# tagArea = math.pi * tagRad**2 * tagCnt
iTAG = Part.makeCompound(intTags)
eTAG = Part.makeCompound(extTags)
@@ -1335,13 +1340,14 @@ class ObjectProfile(PathAreaOp.ObjectOp):
def _makeStop(self, sType, pA, pB, lbl):
# PathLog.debug('_makeStop()')
rad = self.radius
ofstRad = self.ofstRadius
extra = self.radius / 10
extra = self.radius / 5.0
lng = 0.05
med = lng / 2.0
shrt = lng / 5.0
E = FreeCAD.Vector(pB.x, pB.y, 0) # endpoint
C = FreeCAD.Vector(pA.x, pA.y, 0) # checkpoint
lenEC = E.sub(C).Length
if self.useComp is True or (self.useComp is False and self.offsetExtra != 0):
# 'L' stop shape and edge map
@@ -1355,16 +1361,16 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# positive dist in _makePerp2DVector() is CCW rotation
p1 = E
if sType == 'BEG':
p2 = self._makePerp2DVector(C, E, -0.25) # E1
p3 = self._makePerp2DVector(p1, p2, ofstRad + 1.0 + extra) # E2
p4 = self._makePerp2DVector(p2, p3, 0.25 + ofstRad + extra) # E3
p5 = self._makePerp2DVector(p3, p4, 1.0 + extra) # E4
p2 = self._makePerp2DVector(C, E, -1 * shrt) # E1
p3 = self._makePerp2DVector(p1, p2, ofstRad + lng + extra) # E2
p4 = self._makePerp2DVector(p2, p3, shrt + ofstRad + extra) # E3
p5 = self._makePerp2DVector(p3, p4, lng + extra) # E4
p6 = self._makePerp2DVector(p4, p5, ofstRad + extra) # E5
elif sType == 'END':
p2 = self._makePerp2DVector(C, E, 0.25) # E1
p3 = self._makePerp2DVector(p1, p2, -1 * (ofstRad + 1.0 + extra)) # E2
p4 = self._makePerp2DVector(p2, p3, -1 * (0.25 + ofstRad + extra)) # E3
p5 = self._makePerp2DVector(p3, p4, -1 * (1.0 + extra)) # E4
p2 = self._makePerp2DVector(C, E, shrt) # E1
p3 = self._makePerp2DVector(p1, p2, -1 * (ofstRad + lng + extra)) # E2
p4 = self._makePerp2DVector(p2, p3, -1 * (shrt + ofstRad + extra)) # E3
p5 = self._makePerp2DVector(p3, p4, -1 * (lng + extra)) # E4
p6 = self._makePerp2DVector(p4, p5, -1 * (ofstRad + extra)) # E5
p7 = E # E6
L1 = Part.makeLine(p1, p2)
@@ -1383,15 +1389,15 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# positive dist in _makePerp2DVector() is CCW rotation
p1 = E
if sType == 'BEG':
p2 = self._makePerp2DVector(C, E, -1 * (0.25 + abs(self.offsetExtra))) # left, 0.25
p3 = self._makePerp2DVector(p1, p2, 0.25 + abs(self.offsetExtra))
p4 = self._makePerp2DVector(p2, p3, (0.5 + abs(self.offsetExtra))) # FIRST POINT
p5 = self._makePerp2DVector(p3, p4, 0.25 + abs(self.offsetExtra)) # E1 SECOND
p2 = self._makePerp2DVector(C, E, -1 * (shrt + abs(self.offsetExtra))) # left, shrt
p3 = self._makePerp2DVector(p1, p2, shrt + abs(self.offsetExtra))
p4 = self._makePerp2DVector(p2, p3, (med + abs(self.offsetExtra))) # FIRST POINT
p5 = self._makePerp2DVector(p3, p4, shrt + abs(self.offsetExtra)) # E1 SECOND
elif sType == 'END':
p2 = self._makePerp2DVector(C, E, (0.25 + abs(self.offsetExtra))) # left, 0.25
p3 = self._makePerp2DVector(p1, p2, -1 * (0.25 + abs(self.offsetExtra)))
p4 = self._makePerp2DVector(p2, p3, -1 * (0.5 + abs(self.offsetExtra))) # FIRST POINT
p5 = self._makePerp2DVector(p3, p4, -1 * (0.25 + abs(self.offsetExtra))) # E1 SECOND
p2 = self._makePerp2DVector(C, E, (shrt + abs(self.offsetExtra))) # left, shrt
p3 = self._makePerp2DVector(p1, p2, -1 * (shrt + abs(self.offsetExtra)))
p4 = self._makePerp2DVector(p2, p3, -1 * (med + abs(self.offsetExtra))) # FIRST POINT
p5 = self._makePerp2DVector(p3, p4, -1 * (shrt + abs(self.offsetExtra))) # E1 SECOND
p6 = p1 # E4
L1 = Part.makeLine(p1, p2)
L2 = Part.makeLine(p2, p3)