Merge pull request #2996 from Russ4262/Fix_MillFace_FinalDepth
[Path] Restore manual override of FinalDepth values
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -50,8 +50,8 @@ __url__ = "https://www.freecadweb.org"
|
||||
__doc__ = "Base class an implementation for operations on circular holes."
|
||||
__contributors__ = "russ4262 (Russell Johnson)"
|
||||
__created__ = "2017"
|
||||
__scriptVersion__ = "1e testing"
|
||||
__lastModified__ = "2019-07-26 14:15 CST"
|
||||
__scriptVersion__ = "2b"
|
||||
__lastModified__ = "2020-02-13 17:11 CST"
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
@@ -60,7 +60,7 @@ def translate(context, text, disambig=None):
|
||||
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
class ObjectOp(PathOp.ObjectOp):
|
||||
@@ -75,7 +75,7 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
def opFeatures(self, obj):
|
||||
'''opFeatures(obj) ... calls circularHoleFeatures(obj) and ORs in the standard features required for processing circular holes.
|
||||
Do not overwrite, implement circularHoleFeatures(obj) instead'''
|
||||
return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureHeights | PathOp.FeatureBaseFaces | self.circularHoleFeatures(obj) | PathOp.FeatureCoolant
|
||||
return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureHeights | PathOp.FeatureBaseFaces | self.circularHoleFeatures(obj) | PathOp.FeatureCoolant
|
||||
|
||||
def circularHoleFeatures(self, obj):
|
||||
'''circularHoleFeatures(obj) ... overwrite to add operations specific features.
|
||||
@@ -136,15 +136,14 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
|
||||
if shape.ShapeType == 'Edge' and type(shape.Curve) == Part.Circle:
|
||||
return shape.Curve.Radius * 2
|
||||
|
||||
|
||||
if shape.ShapeType == 'Face':
|
||||
for i in range(len(shape.Edges)):
|
||||
if (type(shape.Edges[i].Curve) == Part.Circle and
|
||||
shape.Edges[i].Curve.Radius * 2 < shape.BoundBox.XLength*1.1 and
|
||||
if (type(shape.Edges[i].Curve) == Part.Circle and
|
||||
shape.Edges[i].Curve.Radius * 2 < shape.BoundBox.XLength*1.1 and
|
||||
shape.Edges[i].Curve.Radius * 2 > shape.BoundBox.XLength*0.9):
|
||||
return shape.Edges[i].Curve.Radius * 2
|
||||
|
||||
|
||||
|
||||
# for all other shapes the diameter is just the dimension in X. This may be inaccurate as the BoundBox is calculated on the tessellated geometry
|
||||
PathLog.warning(translate("Path", "Hole diameter may be inaccurate due to tessellation on face. Consider selecting hole edge."))
|
||||
return shape.BoundBox.XLength
|
||||
@@ -207,7 +206,6 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
self.safeHeight = obj.SafeHeight.Value # pylint: disable=attribute-defined-outside-init
|
||||
self.axialFeed = 0.0 # pylint: disable=attribute-defined-outside-init
|
||||
self.axialRapid = 0.0 # pylint: disable=attribute-defined-outside-init
|
||||
trgtDep = None
|
||||
|
||||
def haveLocations(self, obj):
|
||||
if PathOp.FeatureLocations & self.opFeatures(obj):
|
||||
@@ -324,38 +322,29 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
pos = self.holePosition(obj, base, sub)
|
||||
if pos:
|
||||
# Default is treat selection as 'Face' shape
|
||||
finDep = base.Shape.getElement(sub).BoundBox.ZMin
|
||||
holeBtm = base.Shape.getElement(sub).BoundBox.ZMin
|
||||
if base.Shape.getElement(sub).ShapeType == 'Edge':
|
||||
msg = translate("Path", "Verify Final Depth of holes based on edges. {} depth is: {} mm".format(sub, round(finDep, 4))) + " "
|
||||
msg = translate("Path", "Verify Final Depth of holes based on edges. {} depth is: {} mm".format(sub, round(holeBtm, 4))) + " "
|
||||
msg += translate("Path", "Always select the bottom edge of the hole when using an edge.")
|
||||
PathLog.warning(msg)
|
||||
|
||||
# If user has not adjusted Final Depth value, attempt to determine from sub
|
||||
trgtDep = obj.FinalDepth.Value
|
||||
if obj.OpFinalDepth.Value == obj.FinalDepth.Value:
|
||||
trgtDep = finDep
|
||||
if obj.FinalDepth.Value < finDep:
|
||||
msg = translate("Path", "Final Depth setting is below the hole bottom for {}.".format(sub))
|
||||
# Warn user if Final Depth set lower than bottom of hole
|
||||
if finDep < holeBtm:
|
||||
msg = translate("Path", "Final Depth setting is below the hole bottom for {}.".format(sub)) + ' '
|
||||
msg += translate("Path", "{} depth is calculated at {} mm".format(sub, round(holeBtm, 4)))
|
||||
PathLog.warning(msg)
|
||||
|
||||
holes.append({'x': pos.x, 'y': pos.y, 'r': self.holeDiameter(obj, base, sub),
|
||||
'angle': angle, 'axis': axis, 'trgtDep': trgtDep,
|
||||
'angle': angle, 'axis': axis, 'trgtDep': finDep,
|
||||
'stkTop': stock.Shape.BoundBox.ZMax})
|
||||
|
||||
if haveLocations(self, obj):
|
||||
for location in obj.Locations:
|
||||
# holes.append({'x': location.x, 'y': location.y, 'r': 0, 'angle': 0.0, 'axis': 'X', 'finDep': obj.FinalDepth.Value})
|
||||
trgtDep = obj.FinalDepth.Value
|
||||
# holes.append({'x': location.x, 'y': location.y, 'r': 0, 'angle': 0.0, 'axis': 'X', 'holeBtm': obj.FinalDepth.Value})
|
||||
holes.append({'x': location.x, 'y': location.y, 'r': 0,
|
||||
'angle': 0.0, 'axis': 'X', 'trgtDep': trgtDep,
|
||||
'angle': 0.0, 'axis': 'X', 'trgtDep': finDep,
|
||||
'stkTop': PathUtils.findParentJob(obj).stock.Shape.BoundBox.ZMax})
|
||||
|
||||
# If all holes based upon edges, set post-operation Final Depth to highest edge height
|
||||
if obj.OpFinalDepth.Value == obj.FinalDepth.Value:
|
||||
if len(holes) == 1:
|
||||
PathLog.info(translate('Path', "Single-hole operation. Saving Final Depth determined from hole base."))
|
||||
obj.FinalDepth.Value = trgtDep
|
||||
|
||||
if len(holes) > 0:
|
||||
self.circularHoleExecute(obj, holes) # circularHoleExecute() located in PathDrilling.py
|
||||
|
||||
@@ -822,23 +811,6 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
angle = -1 * angle
|
||||
return (clnBase, clnStock, angle)
|
||||
|
||||
def calculateStartFinalDepths(self, obj, shape, stock):
|
||||
'''calculateStartFinalDepths(obj, shape, stock)
|
||||
Calculate correct start and final depths for the shape(face) object provided.'''
|
||||
finDep = max(obj.FinalDepth.Value, shape.BoundBox.ZMin)
|
||||
stockTop = stock.Shape.BoundBox.ZMax
|
||||
if obj.EnableRotation == 'Off':
|
||||
strDep = obj.StartDepth.Value
|
||||
if strDep <= finDep:
|
||||
strDep = stockTop
|
||||
else:
|
||||
strDep = min(obj.StartDepth.Value, stockTop)
|
||||
if strDep <= finDep:
|
||||
strDep = stockTop
|
||||
msg = translate('Path', "Start depth <= face depth.\nIncreased to stock top.")
|
||||
PathLog.error(msg)
|
||||
return (strDep, finDep)
|
||||
|
||||
def sortTuplesByIndex(self, TupleList, tagIdx):
|
||||
'''sortTuplesByIndex(TupleList, tagIdx)
|
||||
sort list of tuples based on tag index provided
|
||||
|
||||
@@ -37,11 +37,11 @@ __url__ = "http://www.freecadweb.org"
|
||||
__doc__ = "Class and implementation of the 3D Pocket operation."
|
||||
__contributors__ = "russ4262 (Russell Johnson)"
|
||||
__created__ = "2014"
|
||||
__scriptVersion__ = "2g testing"
|
||||
__lastModified__ = "2019-07-20 22:02 CST"
|
||||
__scriptVersion__ = "2e"
|
||||
__lastModified__ = "2020-02-13 17:22 CST"
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
@@ -102,8 +102,11 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
allSubsFaceType = False
|
||||
|
||||
if allSubsFaceType is True and obj.HandleMultipleFeatures == 'Collectively':
|
||||
(fzmin, fzmax) = self.getMinMaxOfFaces(Faces)
|
||||
if obj.FinalDepth.Value < fzmin:
|
||||
PathLog.warning(translate('PathPocket', 'Final depth set below ZMin of face(s) selected.'))
|
||||
'''
|
||||
if obj.OpFinalDepth == obj.FinalDepth:
|
||||
(fzmin, fzmax) = self.getMinMaxOfFaces(Faces)
|
||||
obj.FinalDepth.Value = fzmin
|
||||
finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
|
||||
self.depthparams = PathUtils.depth_params(
|
||||
@@ -115,6 +118,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
final_depth=fzmin,
|
||||
user_depths=None)
|
||||
PathLog.info("Updated obj.FinalDepth.Value and self.depthparams to zmin: {}".format(fzmin))
|
||||
'''
|
||||
|
||||
if obj.AdaptivePocketStart is True or obj.AdaptivePocketFinish is True:
|
||||
pocketTup = self.calculateAdaptivePocket(obj, base, subObjTups)
|
||||
@@ -148,8 +152,9 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
PathLog.debug("processing the whole job base object")
|
||||
strDep = obj.StartDepth.Value
|
||||
finDep = obj.FinalDepth.Value
|
||||
recomputeDepthparams = False
|
||||
# recomputeDepthparams = False
|
||||
for base in self.model:
|
||||
'''
|
||||
if obj.OpFinalDepth == obj.FinalDepth:
|
||||
if base.Shape.BoundBox.ZMin < obj.FinalDepth.Value:
|
||||
obj.FinalDepth.Value = base.Shape.BoundBox.ZMin
|
||||
@@ -173,11 +178,13 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
final_depth=obj.FinalDepth.Value,
|
||||
user_depths=None)
|
||||
recomputeDepthparams = False
|
||||
'''
|
||||
|
||||
if obj.ProcessStockArea is True:
|
||||
job = PathUtils.findParentJob(obj)
|
||||
finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
|
||||
|
||||
'''
|
||||
finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
|
||||
depthparams = PathUtils.depth_params(
|
||||
clearance_height=obj.ClearanceHeight.Value,
|
||||
safe_height=obj.SafeHeight.Value,
|
||||
@@ -187,6 +194,8 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
final_depth=base.Shape.BoundBox.ZMin,
|
||||
user_depths=None)
|
||||
stockEnvShape = PathUtils.getEnvelope(job.Stock.Shape, subshape=None, depthparams=depthparams)
|
||||
'''
|
||||
stockEnvShape = PathUtils.getEnvelope(job.Stock.Shape, subshape=None, depthparams=self.depthparams)
|
||||
|
||||
obj.removalshape = stockEnvShape.cut(base.Shape)
|
||||
obj.removalshape.tessellate(0.1)
|
||||
@@ -225,7 +234,6 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
tryNonPlanar = False
|
||||
isHighFacePlanar = True
|
||||
isLowFacePlanar = True
|
||||
faceType = 0
|
||||
|
||||
for (sub, face) in subObjTups:
|
||||
Faces.append(face)
|
||||
|
||||
@@ -40,11 +40,11 @@ __url__ = "http://www.freecadweb.org"
|
||||
__doc__ = "Class and implementation of shape based Pocket operation."
|
||||
__contributors__ = "russ4262 (Russell Johnson)"
|
||||
__created__ = "2017"
|
||||
__scriptVersion__ = "2i usable"
|
||||
__lastModified__ = "2019-09-07 08:32 CST"
|
||||
__scriptVersion__ = "2i"
|
||||
__lastModified__ = "2020-02-13 17:01 CST"
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
@@ -65,11 +65,12 @@ def endPoints(edgeOrWire):
|
||||
unique.append(p)
|
||||
return unique
|
||||
pfirst = edgeOrWire.valueAt(edgeOrWire.FirstParameter)
|
||||
plast = edgeOrWire.valueAt(edgeOrWire.LastParameter)
|
||||
plast = edgeOrWire.valueAt(edgeOrWire.LastParameter)
|
||||
if PathGeom.pointsCoincide(pfirst, plast):
|
||||
return None
|
||||
return [pfirst, plast]
|
||||
|
||||
|
||||
def includesPoint(p, pts):
|
||||
'''includesPoint(p, pts) ... answer True if the collection of pts includes the point p'''
|
||||
for pt in pts:
|
||||
@@ -83,7 +84,7 @@ def selectOffsetWire(feature, wires):
|
||||
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:
|
||||
return closest[1]
|
||||
@@ -116,6 +117,7 @@ def extendWire(feature, wire, length):
|
||||
return Part.Wire(edges)
|
||||
return None
|
||||
|
||||
|
||||
class Extension(object):
|
||||
DirectionNormal = 0
|
||||
DirectionX = 1
|
||||
@@ -163,7 +165,7 @@ class Extension(object):
|
||||
return [self.obj.Shape.getElement(sub) for sub in self._getEdgeNames()]
|
||||
|
||||
def _getDirectedNormal(self, p0, normal):
|
||||
poffPlus = p0 + 0.01 * normal
|
||||
poffPlus = p0 + 0.01 * normal
|
||||
poffMinus = p0 - 0.01 * normal
|
||||
if not self.obj.Shape.isInside(poffPlus, 0.005, True):
|
||||
return normal
|
||||
@@ -281,7 +283,6 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
baseSubsTuples = []
|
||||
subCount = 0
|
||||
allTuples = []
|
||||
finalDepths = []
|
||||
|
||||
def planarFaceFromExtrusionEdges(face, trans):
|
||||
useFace = 'useFaceName'
|
||||
@@ -383,7 +384,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
|
||||
if obj.Base:
|
||||
PathLog.debug('Processing... obj.Base')
|
||||
self.removalshapes = [] # pylint: disable=attribute-defined-outside-init
|
||||
self.removalshapes = [] # pylint: disable=attribute-defined-outside-init
|
||||
# ----------------------------------------------------------------------
|
||||
if obj.EnableRotation == 'Off':
|
||||
stock = PathUtils.findParentJob(obj).Stock
|
||||
@@ -401,14 +402,14 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
PathLog.info("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
|
||||
(rtn, angle, axis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
PathLog.info("angle: {}; axis: {}".format(angle, axis))
|
||||
|
||||
if rtn is True:
|
||||
faceNums = ""
|
||||
for f in subsList:
|
||||
faceNums += '_' + f.replace('Face', '')
|
||||
(clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis(obj, base, angle, axis, faceNums) # pylint: disable=unused-variable
|
||||
(clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis(obj, base, angle, axis, faceNums) # pylint: disable=unused-variable
|
||||
|
||||
# Verify faces are correctly oriented - InverseAngle might be necessary
|
||||
PathLog.debug("Checking if faces are oriented correctly after rotation...")
|
||||
@@ -458,7 +459,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
PathLog.error(translate("Path", "Failed to create a planar face from edges in {}.".format(sub)))
|
||||
|
||||
(norm, surf) = self.getFaceNormAndSurf(face)
|
||||
(rtn, angle, axis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
(rtn, angle, axis, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
|
||||
if rtn is True:
|
||||
faceNum = sub.replace('Face', '')
|
||||
@@ -466,7 +467,7 @@ 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, praInfo) = self.faceRotationAnalysis(obj, norm, surf) # pylint: disable=unused-variable
|
||||
if rtn is True:
|
||||
PathLog.debug("Face not aligned after initial rotation.")
|
||||
if obj.AttemptInverseAngle is True and obj.InverseAngle is False:
|
||||
@@ -492,8 +493,8 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
PathLog.error(translate('Path', "Selected feature is not a Face. Ignoring: {}".format(ignoreSub)))
|
||||
|
||||
for o in baseSubsTuples:
|
||||
self.horiz = [] # pylint: disable=attribute-defined-outside-init
|
||||
self.vert = [] # pylint: disable=attribute-defined-outside-init
|
||||
self.horiz = [] # pylint: disable=attribute-defined-outside-init
|
||||
self.vert = [] # pylint: disable=attribute-defined-outside-init
|
||||
subBase = o[0]
|
||||
subsList = o[1]
|
||||
angle = o[2]
|
||||
@@ -545,7 +546,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
|
||||
# move all horizontal faces to FinalDepth
|
||||
for f in self.horiz:
|
||||
finDep = max(obj.FinalDepth.Value, f.BoundBox.ZMin)
|
||||
finDep = obj.FinalDepth.Value # max(obj.FinalDepth.Value, f.BoundBox.ZMin)
|
||||
f.translate(FreeCAD.Vector(0, 0, finDep - f.BoundBox.ZMin))
|
||||
|
||||
# check all faces and see if they are touching/overlapping and combine those into a compound
|
||||
@@ -560,20 +561,17 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
else:
|
||||
self.horizontal.append(shape)
|
||||
|
||||
# extrude all faces up to StartDepth and those are the removal shapes
|
||||
sD = obj.StartDepth.Value
|
||||
fD = obj.FinalDepth.Value
|
||||
extent = FreeCAD.Vector(0, 0, sD - fD)
|
||||
for face in self.horizontal:
|
||||
# extrude all faces up to StartDepth and those are the removal shapes
|
||||
(strDep, finDep) = self.calculateStartFinalDepths(obj, face, stock)
|
||||
finalDepths.append(finDep)
|
||||
extent = FreeCAD.Vector(0, 0, strDep - finDep)
|
||||
self.removalshapes.append((face.removeSplitter().extrude(extent), False, 'pathPocketShape', angle, axis, strDep, finDep))
|
||||
PathLog.debug("Extent depths are str: {}, and fin: {}".format(strDep, finDep))
|
||||
self.removalshapes.append((face.removeSplitter().extrude(extent),
|
||||
False, 'pathPocketShape', angle, axis, sD, fD))
|
||||
PathLog.debug("Extent depths are str: {}, and fin: {}".format(sD, fD))
|
||||
# Efor face
|
||||
# Efor
|
||||
|
||||
# Adjust obj.FinalDepth.Value as needed.
|
||||
if len(finalDepths) > 0:
|
||||
finalDep = min(finalDepths)
|
||||
if subCount == 1:
|
||||
obj.FinalDepth.Value = finalDep
|
||||
else:
|
||||
# process the job base object as a whole
|
||||
PathLog.debug(translate("Path", 'Processing model as a whole ...'))
|
||||
|
||||
Reference in New Issue
Block a user