Merge pull request #3231 from Russ4262/4th_axis_fixes
[Path] 4th-axis rotational alignment improvements; Code clean-up
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * Copyright (c) 2020 russ4262 (Russell Johnson) *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
@@ -49,6 +48,7 @@ PathLog.setLevel(LOGLEVEL, PathLog.thisModule())
|
||||
if LOGLEVEL is PathLog.Level.DEBUG:
|
||||
PathLog.trackModule()
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
@@ -66,7 +66,6 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
'''opFeatures(obj) ... returns the base features supported by all Path.Area based operations.
|
||||
The standard feature list is OR'ed with the return value of areaOpFeatures().
|
||||
Do not overwrite, implement areaOpFeatures(obj) instead.'''
|
||||
# return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureStepDown | PathOp.FeatureHeights | PathOp.FeatureStartPoint | self.areaOpFeatures(obj) | PathOp.FeatureRotation
|
||||
return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureStepDown | PathOp.FeatureHeights | PathOp.FeatureStartPoint | self.areaOpFeatures(obj) | PathOp.FeatureCoolant
|
||||
|
||||
def areaOpFeatures(self, obj):
|
||||
@@ -304,8 +303,6 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
pathParams['return_end'] = True
|
||||
# Note that emitting preambles between moves breaks some dressups and prevents path optimization on some controllers
|
||||
pathParams['preamble'] = False
|
||||
#if not self.areaOpRetractTool(obj):
|
||||
# pathParams['threshold'] = 2.001 * self.radius
|
||||
|
||||
if self.endVector is None:
|
||||
V = hWire.Wires[0].Vertexes
|
||||
@@ -374,12 +371,6 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
obj.ClearanceHeight.Value = strDep + self.clrOfset
|
||||
obj.SafeHeight.Value = strDep + self.safOfst
|
||||
|
||||
#if self.initWithRotation is False:
|
||||
# if obj.FinalDepth.Value == obj.OpFinalDepth.Value:
|
||||
# obj.FinalDepth.Value = finDep
|
||||
# if obj.StartDepth.Value == obj.OpStartDepth.Value:
|
||||
# obj.StartDepth.Value = strDep
|
||||
|
||||
# Create visual axes when debugging.
|
||||
if PathLog.getLevel(PathLog.thisModule()) == 4:
|
||||
self.visualAxis()
|
||||
@@ -467,10 +458,14 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
# Rotate Model to correct angle
|
||||
ppCmds.insert(0, Path.Command('G0', {axisOfRot: angle, 'F': self.axialRapid}))
|
||||
|
||||
# Raise cutter to safe depth and return index to starting position
|
||||
ppCmds.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
if axis != nextAxis:
|
||||
ppCmds.append(Path.Command('G0', {axisOfRot: 0.0, 'F': self.axialRapid}))
|
||||
# Raise cutter to safe height
|
||||
ppCmds.insert(0, Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
|
||||
# Return index to starting position if axis of rotation changes.
|
||||
if numShapes > 1:
|
||||
if ns != numShapes - 1:
|
||||
if axis != nextAxis:
|
||||
ppCmds.append(Path.Command('G0', {axisOfRot: 0.0, 'F': self.axialRapid}))
|
||||
# Eif
|
||||
|
||||
# Save gcode commands to object command list
|
||||
@@ -483,9 +478,43 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
|
||||
# Raise cutter to safe height and rotate back to original orientation
|
||||
if self.rotateFlag is True:
|
||||
resetAxis = False
|
||||
lastJobOp = None
|
||||
nextJobOp = None
|
||||
opIdx = 0
|
||||
JOB = PathUtils.findParentJob(obj)
|
||||
jobOps = JOB.Operations.Group
|
||||
numJobOps = len(jobOps)
|
||||
|
||||
for joi in range(0, numJobOps):
|
||||
jo = jobOps[joi]
|
||||
if jo.Name == obj.Name:
|
||||
opIdx = joi
|
||||
lastOpIdx = opIdx - 1
|
||||
nextOpIdx = opIdx + 1
|
||||
if lastOpIdx > -1:
|
||||
lastJobOp = jobOps[lastOpIdx]
|
||||
if nextOpIdx < numJobOps:
|
||||
nextJobOp = jobOps[nextOpIdx]
|
||||
|
||||
if lastJobOp is not None:
|
||||
if hasattr(lastJobOp, 'EnableRotation'):
|
||||
PathLog.debug('Last Op, {}, has `EnableRotation` set to {}'.format(lastJobOp.Label, lastJobOp.EnableRotation))
|
||||
if lastJobOp.EnableRotation != obj.EnableRotation:
|
||||
resetAxis = True
|
||||
if ns == numShapes - 1: # If last shape, check next op EnableRotation setting
|
||||
if nextJobOp is not None:
|
||||
if hasattr(nextJobOp, 'EnableRotation'):
|
||||
PathLog.debug('Next Op, {}, has `EnableRotation` set to {}'.format(nextJobOp.Label, nextJobOp.EnableRotation))
|
||||
if nextJobOp.EnableRotation != obj.EnableRotation:
|
||||
resetAxis = True
|
||||
|
||||
# Raise to safe height if rotation activated
|
||||
self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
self.commandlist.append(Path.Command('G0', {'A': 0.0, 'F': self.axialRapid}))
|
||||
self.commandlist.append(Path.Command('G0', {'B': 0.0, 'F': self.axialRapid}))
|
||||
# reset rotational axises if necessary
|
||||
if resetAxis is True:
|
||||
self.commandlist.append(Path.Command('G0', {'A': 0.0, 'F': self.axialRapid}))
|
||||
self.commandlist.append(Path.Command('G0', {'B': 0.0, 'F': self.axialRapid}))
|
||||
|
||||
self.useTempJobClones('Delete') # Delete temp job clone group and contents
|
||||
self.guiMessage('title', None, show=True) # Process GUI messages to user
|
||||
@@ -531,10 +560,8 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
Determine rotational radii for 4th-axis rotations, for clearance/safe heights '''
|
||||
|
||||
parentJob = PathUtils.findParentJob(obj)
|
||||
# bb = parentJob.Stock.Shape.BoundBox
|
||||
xlim = 0.0
|
||||
ylim = 0.0
|
||||
# zlim = 0.0
|
||||
|
||||
# Determine boundbox radius based upon xzy limits data
|
||||
if math.fabs(self.stockBB.ZMin) > math.fabs(self.stockBB.ZMax):
|
||||
|
||||
@@ -99,7 +99,7 @@ class ObjectFace(PathPocketBase.ObjectPocket):
|
||||
'''areaOpShapes(obj) ... return top face'''
|
||||
# Facing is done either against base objects
|
||||
holeShape = None
|
||||
|
||||
|
||||
if obj.Base:
|
||||
PathLog.debug("obj.Base: {}".format(obj.Base))
|
||||
faces = []
|
||||
@@ -147,17 +147,17 @@ class ObjectFace(PathPocketBase.ObjectPocket):
|
||||
# Find the correct shape depending on Boundary shape.
|
||||
PathLog.debug("Boundary Shape: {}".format(obj.BoundaryShape))
|
||||
bb = planeshape.BoundBox
|
||||
|
||||
|
||||
# Apply offset for clearing edges
|
||||
offset = 0;
|
||||
if obj.ClearEdges == True:
|
||||
offset = self.radius + 0.1
|
||||
|
||||
|
||||
bb.XMin = bb.XMin - offset
|
||||
bb.YMin = bb.YMin - offset
|
||||
bb.XMax = bb.XMax + offset
|
||||
bb.YMax = bb.YMax + offset
|
||||
|
||||
|
||||
if obj.BoundaryShape == 'Boundbox':
|
||||
bbperim = Part.makeBox(bb.XLength, bb.YLength, 1, FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin), FreeCAD.Vector(0, 0, 1))
|
||||
env = PathUtils.getEnvelope(partshape=bbperim, depthparams=self.depthparams)
|
||||
@@ -170,7 +170,7 @@ class ObjectFace(PathPocketBase.ObjectPocket):
|
||||
elif obj.BoundaryShape == 'Stock':
|
||||
stock = PathUtils.findParentJob(obj).Stock.Shape
|
||||
env = stock
|
||||
|
||||
|
||||
if obj.ExcludeRaisedAreas is True and oneBase[1] is True:
|
||||
includedFaces = self.getAllIncludedFaces(oneBase[0], stock, faceZ=minHeight)
|
||||
if len(includedFaces) > 0:
|
||||
@@ -269,7 +269,6 @@ def SetupProperties():
|
||||
setup.append("BoundaryShape")
|
||||
setup.append("ExcludeRaisedAreas")
|
||||
setup.append("ClearEdges")
|
||||
|
||||
return setup
|
||||
|
||||
|
||||
@@ -278,5 +277,4 @@ def Create(name, obj=None):
|
||||
if obj is None:
|
||||
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
|
||||
obj.Proxy = ObjectFace(obj, name)
|
||||
|
||||
return obj
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * Copyright (c) 2020 russ4262 (Russell Johnson) *
|
||||
# * Copyright (c) 2020 Schildkroet *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
@@ -42,7 +41,7 @@ __author__ = "sliptonic (Brad Collette)"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
__doc__ = "Class and implementation of shape based Pocket operation."
|
||||
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
@@ -435,7 +434,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
if obj.Base:
|
||||
PathLog.debug('Processing... obj.Base')
|
||||
self.removalshapes = [] # pylint: disable=attribute-defined-outside-init
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if obj.EnableRotation == 'Off':
|
||||
stock = PathUtils.findParentJob(obj).Stock
|
||||
for (base, subList) in obj.Base:
|
||||
@@ -450,11 +449,11 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
(isLoop, norm, surf) = self.checkForFacesLoop(base, subsList)
|
||||
|
||||
if isLoop is True:
|
||||
PathLog.info("Common Surface.Axis or normalAt() value found for loop faces.")
|
||||
PathLog.debug("Common Surface.Axis or normalAt() value found for loop faces.")
|
||||
rtn = False
|
||||
subCount += 1
|
||||
(rtn, angle, axis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
PathLog.info("angle: {}; axis: {}".format(angle, axis))
|
||||
PathLog.debug("angle: {}; axis: {}".format(angle, axis))
|
||||
|
||||
if rtn is True:
|
||||
faceNums = ""
|
||||
@@ -471,15 +470,17 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
rtn = False
|
||||
PathLog.warning(translate("PathPocketShape", "Face appears to NOT be horizontal AFTER rotation applied."))
|
||||
break
|
||||
|
||||
if rtn is False:
|
||||
PathLog.debug(translate("Path", "Face appears misaligned after initial rotation."))
|
||||
if obj.InverseAngle is False:
|
||||
if obj.AttemptInverseAngle is True:
|
||||
PathLog.debug("Applying the inverse angle.")
|
||||
(clnBase, clnStock, angle) = self.applyInverseAngle(obj, clnBase, clnStock, axis, angle)
|
||||
else:
|
||||
PathLog.warning(translate("Path", "Consider toggling the InverseAngle property and recomputing the operation."))
|
||||
msg = translate("Path", "Consider toggling the 'InverseAngle' property and recomputing.")
|
||||
PathLog.warning(msg)
|
||||
|
||||
if angle < -180.0:
|
||||
if angle < 0.0:
|
||||
angle += 360.0
|
||||
|
||||
tup = clnBase, subsList, angle, axis, clnStock
|
||||
@@ -518,6 +519,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
|
||||
(norm, surf) = self.getFaceNormAndSurf(face)
|
||||
(rtn, angle, axis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
PathLog.debug("initial {}".format(praInfo))
|
||||
|
||||
if rtn is True:
|
||||
faceNum = sub.replace('Face', '')
|
||||
@@ -525,20 +527,31 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
# Verify faces are correctly oriented - InverseAngle might be necessary
|
||||
faceIA = clnBase.Shape.getElement(sub)
|
||||
(norm, surf) = self.getFaceNormAndSurf(faceIA)
|
||||
(rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
(rtn, praAngle, praAxis, praInfo2) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
PathLog.debug("follow-up {}".format(praInfo2))
|
||||
|
||||
if abs(praAngle) == 180.0:
|
||||
rtn = False
|
||||
if self.isFaceUp(clnBase, faceIA) is False:
|
||||
PathLog.debug('isFaceUp is False')
|
||||
angle -= 180.0
|
||||
|
||||
if rtn is True:
|
||||
PathLog.debug("Face not aligned after initial rotation.")
|
||||
PathLog.debug(translate("Path", "Face appears misaligned after initial rotation."))
|
||||
if obj.InverseAngle is False:
|
||||
if obj.AttemptInverseAngle is True:
|
||||
PathLog.debug("Applying the inverse angle.")
|
||||
(clnBase, clnStock, angle) = self.applyInverseAngle(obj, clnBase, clnStock, axis, angle)
|
||||
else:
|
||||
PathLog.warning(translate("Path", "Consider toggling the InverseAngle property and recomputing the operation."))
|
||||
msg = translate("Path", "Consider toggling the 'InverseAngle' property and recomputing.")
|
||||
PathLog.warning(msg)
|
||||
|
||||
if self.isFaceUp(clnBase, faceIA) is False:
|
||||
PathLog.debug('isFaceUp is False')
|
||||
angle += 180.0
|
||||
else:
|
||||
PathLog.debug("Face appears to be oriented correctly.")
|
||||
|
||||
if angle < -180.0:
|
||||
if angle < 0.0:
|
||||
angle += 360.0
|
||||
|
||||
tup = clnBase, [sub], angle, axis, clnStock
|
||||
@@ -650,8 +663,9 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
if shpZMin > obj.FinalDepth.Value:
|
||||
afD = shpZMin
|
||||
if sD <= afD:
|
||||
PathLog.error('Start Depth is lower than face depth.')
|
||||
sD = afD + 1.0
|
||||
msg = translate('PathPocketShape', 'Start Depth is lower than face depth. Setting to ')
|
||||
PathLog.warning(msg + ' {} mm.'.format(sD))
|
||||
else:
|
||||
face.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - shpZMin))
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2020 russ4262 (Russell Johnson) *
|
||||
# * Copyright (c) 2020 Schildkroet *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
@@ -43,6 +42,7 @@ __doc__ = "Path Profile operation based on faces."
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
@@ -132,22 +132,42 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
|
||||
rtn = False
|
||||
(norm, surf) = self.getFaceNormAndSurf(shape)
|
||||
(rtn, angle, axis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
PathLog.debug("initial faceRotationAnalysis: {}".format(praInfo))
|
||||
if rtn is True:
|
||||
(clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis(obj, base, angle, axis, subCount)
|
||||
# Verify faces are correctly oriented - InverseAngle might be necessary
|
||||
faceIA = getattr(clnBase.Shape, sub)
|
||||
(norm, surf) = self.getFaceNormAndSurf(faceIA)
|
||||
(rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
(rtn, praAngle, praAxis, praInfo2) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
PathLog.debug("follow-up faceRotationAnalysis: {}".format(praInfo2))
|
||||
|
||||
if abs(praAngle) == 180.0:
|
||||
rtn = False
|
||||
if self.isFaceUp(clnBase, faceIA) is False:
|
||||
PathLog.debug('isFaceUp 1 is False')
|
||||
angle -= 180.0
|
||||
|
||||
if rtn is True:
|
||||
PathLog.error(translate("Path", "Face appears misaligned after initial rotation."))
|
||||
if obj.AttemptInverseAngle is True and obj.InverseAngle is False:
|
||||
(clnBase, clnStock, angle) = self.applyInverseAngle(obj, clnBase, clnStock, axis, angle)
|
||||
PathLog.debug(translate("Path", "Face appears misaligned after initial rotation."))
|
||||
if obj.InverseAngle is False:
|
||||
if obj.AttemptInverseAngle is True:
|
||||
(clnBase, clnStock, angle) = self.applyInverseAngle(obj, clnBase, clnStock, axis, angle)
|
||||
else:
|
||||
msg = translate("Path", "Consider toggling the 'InverseAngle' property and recomputing.")
|
||||
PathLog.warning(msg)
|
||||
|
||||
if self.isFaceUp(clnBase, faceIA) is False:
|
||||
PathLog.debug('isFaceUp 2 is False')
|
||||
angle += 180.0
|
||||
else:
|
||||
msg = translate("Path", "Consider toggling the 'InverseAngle' property and recomputing.")
|
||||
PathLog.error(msg)
|
||||
PathLog.debug(' isFaceUp')
|
||||
|
||||
else:
|
||||
PathLog.debug("Face appears to be oriented correctly.")
|
||||
|
||||
if angle < 0.0:
|
||||
angle += 360.0
|
||||
|
||||
tup = clnBase, sub, tag, angle, axis, clnStock
|
||||
else:
|
||||
if self.warnDisabledAxis(obj, axis) is False:
|
||||
@@ -157,21 +177,21 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
|
||||
tag = base.Name + '_' + axis + str(angle).replace('.', '_')
|
||||
stock = PathUtils.findParentJob(obj).Stock
|
||||
tup = base, sub, tag, angle, axis, stock
|
||||
|
||||
|
||||
allTuples.append(tup)
|
||||
|
||||
|
||||
if subCount > 1:
|
||||
msg = translate('Path', "Multiple faces in Base Geometry.") + " "
|
||||
msg += translate('Path', "Depth settings will be applied to all faces.")
|
||||
PathLog.warning(msg)
|
||||
|
||||
|
||||
(Tags, Grps) = self.sortTuplesByIndex(allTuples, 2) # return (TagList, GroupList)
|
||||
subList = []
|
||||
for o in range(0, len(Tags)):
|
||||
subList = []
|
||||
for (base, sub, tag, angle, axis, stock) in Grps[o]:
|
||||
subList.append(sub)
|
||||
|
||||
|
||||
pair = base, subList, angle, axis, stock
|
||||
baseSubsTuples.append(pair)
|
||||
# Efor
|
||||
@@ -196,7 +216,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
|
||||
if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face
|
||||
for wire in shape.Wires[1:]:
|
||||
holes.append((base.Shape, wire))
|
||||
|
||||
|
||||
# Add face depth to list
|
||||
faceDepths.append(shape.BoundBox.ZMin)
|
||||
else:
|
||||
@@ -205,13 +225,12 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
|
||||
PathLog.error(msg)
|
||||
FreeCAD.Console.PrintWarning(msg)
|
||||
|
||||
|
||||
# Set initial Start and Final Depths and recalculate depthparams
|
||||
finDep = obj.FinalDepth.Value
|
||||
strDep = obj.StartDepth.Value
|
||||
if strDep > stock.Shape.BoundBox.ZMax:
|
||||
strDep = stock.Shape.BoundBox.ZMax
|
||||
|
||||
|
||||
startDepths.append(strDep)
|
||||
self.depthparams = self._customDepthParams(obj, strDep, finDep)
|
||||
|
||||
@@ -230,31 +249,34 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
|
||||
if obj.processPerimeter:
|
||||
if obj.HandleMultipleFeatures == 'Collectively':
|
||||
custDepthparams = self.depthparams
|
||||
|
||||
if obj.LimitDepthToFace is True and obj.EnableRotation != 'Off':
|
||||
if profileshape.BoundBox.ZMin > obj.FinalDepth.Value:
|
||||
finDep = profileshape.BoundBox.ZMin
|
||||
custDepthparams = self._customDepthParams(obj, strDep, finDep - 0.5) # only an envelope
|
||||
envDepthparams = self._customDepthParams(obj, strDep + 0.5, finDep) # only an envelope
|
||||
try:
|
||||
env = PathUtils.getEnvelope(base.Shape, subshape=profileshape, depthparams=custDepthparams)
|
||||
# env = PathUtils.getEnvelope(base.Shape, subshape=profileshape, depthparams=envDepthparams)
|
||||
env = PathUtils.getEnvelope(profileshape, depthparams=envDepthparams)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# PathUtils.getEnvelope() failed to return an object.
|
||||
PathLog.error(translate('Path', 'Unable to create path for face(s).'))
|
||||
else:
|
||||
tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep
|
||||
shapes.append(tup)
|
||||
|
||||
|
||||
elif obj.HandleMultipleFeatures == 'Individually':
|
||||
for shape in faces:
|
||||
profShape = Part.makeCompound([shape])
|
||||
# profShape = Part.makeCompound([shape])
|
||||
finalDep = obj.FinalDepth.Value
|
||||
custDepthparams = self.depthparams
|
||||
if obj.Side == 'Inside':
|
||||
if finalDep < shape.BoundBox.ZMin:
|
||||
# Recalculate depthparams
|
||||
finalDep = shape.BoundBox.ZMin
|
||||
custDepthparams = self._customDepthParams(obj, strDep, finalDep - 0.5)
|
||||
|
||||
env = PathUtils.getEnvelope(base.Shape, subshape=profShape, depthparams=custDepthparams)
|
||||
custDepthparams = self._customDepthParams(obj, strDep + 0.5, finalDep)
|
||||
|
||||
# env = PathUtils.getEnvelope(base.Shape, subshape=profShape, depthparams=custDepthparams)
|
||||
env = PathUtils.getEnvelope(shape, depthparams=custDepthparams)
|
||||
tup = env, False, 'pathProfileFaces', angle, axis, strDep, finalDep
|
||||
shapes.append(tup)
|
||||
|
||||
@@ -262,11 +284,11 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
|
||||
startDepth = max(startDepths)
|
||||
if obj.StartDepth.Value > startDepth:
|
||||
obj.StartDepth.Value = startDepth
|
||||
|
||||
|
||||
else: # Try to build targets from the job base
|
||||
if 1 == len(self.model):
|
||||
if hasattr(self.model[0], "Proxy"):
|
||||
PathLog.info("hasattr() Proxy")
|
||||
PathLog.debug("hasattr() Proxy")
|
||||
if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet
|
||||
if obj.processCircles or obj.processHoles:
|
||||
for shape in self.model[0].Proxy.getHoles(self.model[0], transform=True):
|
||||
@@ -302,7 +324,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
|
||||
obj.InverseAngle = False
|
||||
obj.AttemptInverseAngle = True
|
||||
obj.LimitDepthToFace = True
|
||||
obj.HandleMultipleFeatures = 'Collectively'
|
||||
obj.HandleMultipleFeatures = 'Individually'
|
||||
|
||||
|
||||
def SetupProperties():
|
||||
@@ -321,6 +343,5 @@ def Create(name, obj=None):
|
||||
'''Create(name) ... Creates and returns a Profile based on faces operation.'''
|
||||
if obj is None:
|
||||
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
|
||||
|
||||
obj.Proxy = ObjectProfile(obj, name)
|
||||
return obj
|
||||
|
||||
Reference in New Issue
Block a user