Merge branch 'master' into allow-neg-boundary-limits

This commit is contained in:
sliptonic
2020-02-17 17:40:05 -06:00
committed by GitHub
162 changed files with 6331 additions and 3454 deletions

View File

@@ -406,10 +406,10 @@
<item row="1" column="1">
<widget class="Gui::PrefComboBox" name="DefaultTaskPanelLayout">
<property name="prefEntry" stdset="0">
<string>DefaultTaskPanelLayout</string>
<cstring>DefaultTaskPanelLayout</cstring>
</property>
<property name="prefPath" stdset="0">
<string>Mod/Path</string>
<cstring>Mod/Path</cstring>
</property>
<item>
<property name="text">

View File

@@ -97,22 +97,26 @@ public:
setArrow();
return;
}
if((msg.Type!=Gui::SelectionChanges::SetPreselect
if(msg.Type!=Gui::SelectionChanges::SetPreselect
&& msg.Type!=Gui::SelectionChanges::MovePreselect)
|| !msg.pOriginalMsg || !msg.pSubObject || !msg.pParentObject)
return;
auto obj = msg.Object.getObject();
if(!obj)
return;
Base::Matrix4D mat;
auto sobj = obj->getSubObject(msg.pSubName,0,&mat);
if(!sobj)
return;
Base::Matrix4D linkMat;
auto sobj = msg.pSubObject->getLinkedObject(true,&linkMat,false);
auto linked = sobj->getLinkedObject(true,&linkMat,false);
auto vp = Base::freecad_dynamic_cast<ViewProviderPath>(
Application::Instance->getViewProvider(sobj));
Application::Instance->getViewProvider(linked));
if(!vp) {
setArrow();
return;
}
if(vp->pt0Index >= 0) {
Base::Matrix4D mat;
msg.pParentObject->getSubObject(msg.pSubName,0,&mat);
mat *= linkMat;
mat.inverse();
Base::Vector3d pt = mat*Base::Vector3d(msg.x,msg.y,msg.z);

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -52,6 +52,8 @@ class TaskPanelHoleGeometryPage(PathOpGui.TaskPanelBaseGeometryPage):
DataObject = QtCore.Qt.ItemDataRole.UserRole + 1
DataObjectSub = QtCore.Qt.ItemDataRole.UserRole + 2
InitBase = False
def getForm(self):
'''getForm() ... load and return page'''
return FreeCADGui.PySideUic.loadUi(":/panels/PageBaseHoleGeometryEdit.ui")

View File

@@ -1017,7 +1017,7 @@ class TaskPanel(object):
if self.deleteOnReject and PathOp.FeatureBaseGeometry & self.obj.Proxy.opFeatures(self.obj):
sel = FreeCADGui.Selection.getSelectionEx()
for page in self.featurePages:
if hasattr(page, 'addBase'):
if getattr(page, 'InitBase', True) and hasattr(page, 'addBase'):
page.clearBase()
page.addBaseGeometry(sel)

View File

@@ -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)

View File

@@ -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 ...'))