diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpPocketFullEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpPocketFullEdit.ui
index d1a81ae2c1..de4c2d5f77 100644
--- a/src/Mod/Path/Gui/Resources/panels/PageOpPocketFullEdit.ui
+++ b/src/Mod/Path/Gui/Resources/panels/PageOpPocketFullEdit.ui
@@ -131,6 +131,12 @@
<html><head/><body><p>Pattern the tool bit is moved in to clear the material.</p></body></html>
+
+
+
+
+ ZigZag
+
-
ZigZag
@@ -138,7 +144,7 @@
-
- Offset
+ Offset
-
@@ -222,6 +228,37 @@
+ -
+
+
+ Enable Rotation
+
+
+
+ -
+
+
-
+
+ Off
+
+
+ -
+
+ A(x)
+
+
+ -
+
+ B(y)
+
+
+ -
+
+ A & B
+
+
+
+
diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpProfileFullEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpProfileFullEdit.ui
index dba10c387d..5a5ca84a85 100644
--- a/src/Mod/Path/Gui/Resources/panels/PageOpProfileFullEdit.ui
+++ b/src/Mod/Path/Gui/Resources/panels/PageOpProfileFullEdit.ui
@@ -56,6 +56,9 @@
-
+
+
+
-
@@ -125,6 +128,37 @@
+ -
+
+
+ Enable Rotation
+
+
+
+ -
+
+
-
+
+ Off
+
+
+ -
+
+ A(x)
+
+
+ -
+
+ B(y)
+
+
+ -
+
+ A & B
+
+
+
+
diff --git a/src/Mod/Path/PathScripts/PathAreaOp.py b/src/Mod/Path/PathScripts/PathAreaOp.py
index 965e5d89e5..b63d7f5974 100644
--- a/src/Mod/Path/PathScripts/PathAreaOp.py
+++ b/src/Mod/Path/PathScripts/PathAreaOp.py
@@ -3,6 +3,7 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 sliptonic *
+# * 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) *
@@ -392,15 +393,7 @@ class ObjectOp(PathOp.ObjectOp):
self.axialRapid = 360 / safeCircum * self.horizRapid # pylint: disable=attribute-defined-outside-init
# Initiate depthparams and calculate operation heights for rotational operation
- finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
- self.depthparams = PathUtils.depth_params( # pylint: disable=attribute-defined-outside-init
- clearance_height=obj.ClearanceHeight.Value,
- safe_height=obj.SafeHeight.Value,
- start_depth=obj.StartDepth.Value,
- step_down=obj.StepDown.Value,
- z_finish_step=finish_step,
- final_depth=obj.FinalDepth.Value,
- user_depths=None)
+ self.depthparams = self._customDepthParams(obj, obj.StartDepth.Value, obj.FinalDepth.Value)
# Set start point
if PathOp.FeatureStartPoint & self.opFeatures(obj) and obj.UseStartPoint:
@@ -446,15 +439,7 @@ class ObjectOp(PathOp.ObjectOp):
else:
nextAxis = 'L'
- finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
- self.depthparams = PathUtils.depth_params( # pylint: disable=attribute-defined-outside-init
- clearance_height=obj.ClearanceHeight.Value,
- safe_height=obj.SafeHeight.Value,
- start_depth=strDep, # obj.StartDepth.Value,
- step_down=obj.StepDown.Value,
- z_finish_step=finish_step,
- final_depth=finDep, # obj.FinalDepth.Value,
- user_depths=None)
+ self.depthparams = self._customDepthParams(obj, strDep, finDep)
try:
if self.profileEdgesIsOpen is True:
@@ -475,19 +460,14 @@ class ObjectOp(PathOp.ObjectOp):
axisOfRot = 'A'
elif axis == 'Y':
axisOfRot = 'B'
- # Reverse angle temporarily to match model. Error in FreeCAD render of B axis rotations
- if obj.B_AxisErrorOverride is True:
- angle = -1 * angle
elif axis == 'Z':
axisOfRot = 'C'
else:
axisOfRot = 'A'
# Rotate Model to correct angle
- ppCmds.insert(0, Path.Command('G1', {axisOfRot: angle, 'F': self.axialFeed}))
- ppCmds.insert(0, Path.Command('N100', {}))
+ 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('N200', {}))
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}))
@@ -761,7 +741,7 @@ class ObjectOp(PathOp.ObjectOp):
xAx = 'xAxCyl'
yAx = 'yAxCyl'
# zAx = 'zAxCyl'
- FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", "visualAxis")
+ VA = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", "visualAxis")
if FreeCAD.GuiUp:
FreeCADGui.ActiveDocument.getObject('visualAxis').Visibility = False
vaGrp = FreeCAD.ActiveDocument.getObject("visualAxis")
@@ -793,6 +773,7 @@ class ObjectOp(PathOp.ObjectOp):
cylGui.Transparency = 85
cylGui.Visibility = False
vaGrp.addObject(cyl)
+ VA.purgeTouched()
def useTempJobClones(self, cloneName):
'''useTempJobClones(cloneName)
@@ -808,6 +789,8 @@ class ObjectOp(PathOp.ObjectOp):
for cln in FreeCAD.ActiveDocument.getObject('rotJobClones').Group:
FreeCAD.ActiveDocument.removeObject(cln.Name)
FreeCAD.ActiveDocument.removeObject('rotJobClones')
+ else:
+ FreeCAD.ActiveDocument.getObject('rotJobClones').purgeTouched()
else:
FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", "rotJobClones")
if FreeCAD.GuiUp:
@@ -917,7 +900,7 @@ class ObjectOp(PathOp.ObjectOp):
obj.AttemptInverseAngle = False
angle = -1 * angle
- PathLog.info(translate("Path", "Rotated to inverse angle."))
+ PathLog.debug(translate("Path", "Rotated to inverse angle."))
return (clnBase, clnStock, angle)
def sortTuplesByIndex(self, TupleList, tagIdx):
@@ -960,3 +943,28 @@ class ObjectOp(PathOp.ObjectOp):
return True
else:
return False
+
+ def isFaceUp(self, base, face):
+ up = face.extrude(FreeCAD.Vector(0.0, 0.0, 5.0))
+ dwn = face.extrude(FreeCAD.Vector(0.0, 0.0, -5.0))
+ upCmn = base.Shape.common(up)
+ dwnCmn = base.Shape.common(dwn)
+ if upCmn.Volume == 0.0:
+ return True
+ elif dwnCmn.Volume == 0.0:
+ return False
+ if dwnCmn.Volume > upCmn.Volume:
+ return True
+ return False
+
+ def _customDepthParams(self, obj, strDep, finDep):
+ finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
+ cdp = PathUtils.depth_params(
+ clearance_height=obj.ClearanceHeight.Value,
+ safe_height=obj.SafeHeight.Value,
+ start_depth=strDep,
+ step_down=obj.StepDown.Value,
+ z_finish_step=finish_step,
+ final_depth=finDep,
+ user_depths=None)
+ return cdp
diff --git a/src/Mod/Path/PathScripts/PathCircularHoleBase.py b/src/Mod/Path/PathScripts/PathCircularHoleBase.py
index 986c79d539..eea0deda3b 100644
--- a/src/Mod/Path/PathScripts/PathCircularHoleBase.py
+++ b/src/Mod/Path/PathScripts/PathCircularHoleBase.py
@@ -333,6 +333,7 @@ class ObjectOp(PathOp.ObjectOp):
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)
+ finDep = holeBtm
holes.append({'x': pos.x, 'y': pos.y, 'r': self.holeDiameter(obj, base, sub),
'angle': angle, 'axis': axis, 'trgtDep': finDep,
@@ -440,7 +441,7 @@ class ObjectOp(PathOp.ObjectOp):
zlim = 0.0
xRotRad = 0.01
yRotRad = 0.01
- xRotRad = 0.01
+ #xRotRad = 0.01
# Determine boundbox radius based upon xzy limits data
if math.fabs(self.stockBB.ZMin) > math.fabs(self.stockBB.ZMax):
diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py
index 99d3b8ac74..96d6a4b637 100644
--- a/src/Mod/Path/PathScripts/PathDrilling.py
+++ b/src/Mod/Path/PathScripts/PathDrilling.py
@@ -3,6 +3,8 @@
# ***************************************************************************
# * *
# * Copyright (c) 2014 Yorik van Havre *
+# * Copyright (c) 2020 russ4262 (Russell Johnson) *
+# * Copyright (c) 2020 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -43,13 +45,9 @@ __title__ = "Path Drilling Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Path Drilling operation."
-__contributors__ = "russ4262 (Russell Johnson), IMBack!"
-__created__ = "2014"
-__scriptVersion__ = "1c testing"
-__lastModified__ = "2019-06-25 14:49 CST"
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+# PathLog.trackModule(PathLog.thisModule())
# Qt translation handling
@@ -86,8 +84,6 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
obj.addProperty('App::PropertyBool', 'ReverseDirection', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Reverse direction of pocket operation.'))
if not hasattr(obj, 'InverseAngle'):
obj.addProperty('App::PropertyBool', 'InverseAngle', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Inverse the angle. Example: -22.5 -> 22.5 degrees.'))
- if not hasattr(obj, 'B_AxisErrorOverride'):
- obj.addProperty('App::PropertyBool', 'B_AxisErrorOverride', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Match B rotations to model (error in FreeCAD rendering).'))
if not hasattr(obj, 'AttemptInverseAngle'):
obj.addProperty('App::PropertyBool', 'AttemptInverseAngle', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Attempt the inverse angle for face access if original rotation fails.'))
@@ -113,7 +109,7 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
holes = PathUtils.sort_jobs(holes, ['x', 'y'])
self.commandlist.append(Path.Command('G90'))
self.commandlist.append(Path.Command(obj.ReturnLevel))
-
+
for p in holes:
cmd = "G81"
cmdParams = {}
@@ -139,9 +135,6 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
axisOfRot = 'A'
elif axis == 'Y':
axisOfRot = 'B'
- # Reverse angle temporarily to match model. Error in FreeCAD render of B axis rotations
- if obj.B_AxisErrorOverride is True:
- angle = -1 * angle
elif axis == 'Z':
axisOfRot = 'C'
else:
@@ -163,13 +156,13 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
self.commandlist.append(Path.Command('G0', {axisOfRot: angle, 'F': self.axialRapid}))
self.commandlist.append(Path.Command('G0', {'X': p['x'], 'Y': p['y'], 'F': self.horizRapid}))
self.commandlist.append(Path.Command('G1', {'Z': p['stkTop'], 'F': self.vertFeed}))
-
- # Perform and cancel canned drilling cycle
+
+ # Perform canned drilling cycle
self.commandlist.append(Path.Command(cmd, params))
+
+ # Cancel canned drilling cycle
self.commandlist.append(Path.Command('G80'))
self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value}))
-
-
# shift axis and angle values
if obj.EnableRotation != 'Off':
@@ -180,30 +173,28 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
self.commandlist.append(Path.Command('G0', {lastAxis: 0.0, 'F': self.axialRapid}))
-
def opSetDefaultValues(self, obj, job):
'''opSetDefaultValues(obj, job) ... set default value for RetractHeight'''
-
+
parentJob = PathUtils.findParentJob(obj)
if hasattr(parentJob.SetupSheet, 'RetractHeight'):
obj.RetractHeight = parentJob.SetupSheet.RetractHeight
elif self.applyExpression(obj, 'RetractHeight', 'OpStartDepth+1mm'):
obj.RetractHeight = 10
-
+
if hasattr(parentJob.SetupSheet, 'PeckDepth'):
obj.PeckDepth = parentJob.SetupSheet.PeckDepth
elif self.applyExpression(obj, 'PeckDepth', 'OpToolDiameter*0.75'):
obj.PeckDepth = 1
-
+
if hasattr(parentJob.SetupSheet, 'DwellTime'):
obj.DwellTime = parentJob.SetupSheet.DwellTime
else:
obj.DwellTime = 1
-
+
obj.ReverseDirection = False
obj.InverseAngle = False
- obj.B_AxisErrorOverride = False
obj.AttemptInverseAngle = False
obj.ExtraOffset = "None"
@@ -228,7 +219,6 @@ def SetupProperties():
setup.append("EnableRotation")
setup.append("ReverseDirection")
setup.append("InverseAngle")
- setup.append("B_AxisErrorOverride")
setup.append("AttemptInverseAngle")
return setup
@@ -237,7 +227,9 @@ def Create(name, obj=None):
'''Create(name) ... Creates and returns a Drilling operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
+
obj.Proxy = ObjectDrilling(obj, name)
if obj.Proxy:
obj.Proxy.findAllHoles(obj)
+
return obj
diff --git a/src/Mod/Path/PathScripts/PathPocketBase.py b/src/Mod/Path/PathScripts/PathPocketBase.py
index c3ac4512af..ba3582f6b8 100644
--- a/src/Mod/Path/PathScripts/PathPocketBase.py
+++ b/src/Mod/Path/PathScripts/PathPocketBase.py
@@ -3,6 +3,7 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 sliptonic *
+# * 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) *
@@ -34,12 +35,14 @@ __url__ = "http://www.freecadweb.org"
__doc__ = "Base class and implementation for Path pocket operations."
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+# PathLog.trackModule(PathLog.thisModule())
+
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
+
class ObjectPocket(PathAreaOp.ObjectOp):
'''Base class for proxy objects of all pocket operations.'''
@@ -130,6 +133,7 @@ class ObjectPocket(PathAreaOp.ObjectOp):
params['threshold'] = self.radius * 2
return params
+
def SetupProperties():
setup = []
setup.append('CutMode')
diff --git a/src/Mod/Path/PathScripts/PathPocketBaseGui.py b/src/Mod/Path/PathScripts/PathPocketBaseGui.py
index ad8dda997c..e9aae91d9d 100644
--- a/src/Mod/Path/PathScripts/PathPocketBaseGui.py
+++ b/src/Mod/Path/PathScripts/PathPocketBaseGui.py
@@ -104,6 +104,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
obj.StepOver = self.form.stepOverPercent.value()
if obj.OffsetPattern != str(self.form.offsetPattern.currentText()):
obj.OffsetPattern = str(self.form.offsetPattern.currentText())
+ if obj.EnableRotation != str(self.form.enableRotation.currentText()):
+ obj.EnableRotation = str(self.form.enableRotation.currentText())
PathGui.updateInputField(obj, 'ExtraOffset', self.form.extraOffset)
self.updateToolController(obj, self.form.toolController)
@@ -143,6 +145,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.selectInComboBox(obj.CutMode, self.form.cutMode)
self.setupToolController(obj, self.form.toolController)
self.setupCoolant(obj, self.form.coolantController)
+ self.selectInComboBox(obj.EnableRotation, self.form.enableRotation)
if FeatureFacing & self.pocketFeatures():
self.selectInComboBox(obj.BoundaryShape, self.form.boundaryShape)
@@ -162,6 +165,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
signals.append(self.form.useOutline.clicked)
signals.append(self.form.minTravel.clicked)
signals.append(self.form.coolantController.currentIndexChanged)
+ signals.append(self.form.enableRotation.currentIndexChanged)
if FeatureFacing & self.pocketFeatures():
signals.append(self.form.boundaryShape.currentIndexChanged)
diff --git a/src/Mod/Path/PathScripts/PathPocketShape.py b/src/Mod/Path/PathScripts/PathPocketShape.py
index f89a613870..16fb8035dc 100644
--- a/src/Mod/Path/PathScripts/PathPocketShape.py
+++ b/src/Mod/Path/PathScripts/PathPocketShape.py
@@ -3,6 +3,8 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 sliptonic *
+# * Copyright (c) 2020 russ4262 (Russell Johnson) *
+# * Copyright (c) 2020 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -31,6 +33,7 @@ import PathScripts.PathPocketBase as PathPocketBase
import PathScripts.PathUtils as PathUtils
import TechDraw
import math
+import Draft
from PySide import QtCore
@@ -38,12 +41,8 @@ __title__ = "Path Pocket Shape Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Class and implementation of shape based Pocket operation."
-__contributors__ = "russ4262 (Russell Johnson)"
-__created__ = "2017"
-__scriptVersion__ = "2i"
-__lastModified__ = "2020-02-13 17:01 CST"
-PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
+PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
# PathLog.trackModule(PathLog.thisModule())
@@ -63,11 +62,14 @@ def endPoints(edgeOrWire):
cnt = len([p2 for p2 in pts if PathGeom.pointsCoincide(p, p2)])
if 1 == cnt:
unique.append(p)
+
return unique
+
pfirst = edgeOrWire.valueAt(edgeOrWire.FirstParameter)
plast = edgeOrWire.valueAt(edgeOrWire.LastParameter)
if PathGeom.pointsCoincide(pfirst, plast):
return None
+
return [pfirst, plast]
@@ -76,6 +78,7 @@ def includesPoint(p, pts):
for pt in pts:
if PathGeom.pointsCoincide(p, pt):
return True
+
return False
@@ -86,8 +89,10 @@ def selectOffsetWire(feature, wires):
dist = feature.distToShape(w)[0]
if closest is None or dist > closest[0]: # pylint: disable=unsubscriptable-object
closest = (dist, w)
+
if closest is not None:
return closest[1]
+
return None
@@ -114,6 +119,7 @@ def extendWire(feature, wire, length):
edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[0])))
edges.extend(offset.Edges)
edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[1])))
+
return Part.Wire(edges)
return None
@@ -148,6 +154,7 @@ class Extension(object):
wire = Part.Wire([e0, e1, e2, e3])
self.wire = wire
return wire
+
return extendWire(feature, Part.Wire([e0]), self.length.Value)
def _getEdgeNumbers(self):
@@ -155,6 +162,7 @@ class Extension(object):
numbers = [nr for nr in self.sub[5:-1].split(',')]
else:
numbers = [self.sub[4:]]
+
PathLog.debug("_getEdgeNumbers() -> %s" % numbers)
return numbers
@@ -169,8 +177,10 @@ class Extension(object):
poffMinus = p0 - 0.01 * normal
if not self.obj.Shape.isInside(poffPlus, 0.005, True):
return normal
+
if not self.obj.Shape.isInside(poffMinus, 0.005, True):
return normal.negative()
+
return None
def _getDirection(self, wire):
@@ -181,6 +191,7 @@ class Extension(object):
normal = tangent.cross(FreeCAD.Vector(0, 0, 1))
if PathGeom.pointsCoincide(normal, FreeCAD.Vector(0, 0, 0)):
return None
+
return self._getDirectedNormal(e0.valueAt(midparam), normal.normalize())
def getWire(self):
@@ -209,6 +220,7 @@ class Extension(object):
r = circle.Radius - self.length.Value
else:
r = circle.Radius + self.length.Value
+
# assuming the offset produces a valid circle - go for it
if r > 0:
e3 = Part.makeCircle(r, circle.Center, circle.Axis, edge.FirstParameter * 180 / math.pi, edge.LastParameter * 180 / math.pi)
@@ -217,7 +229,9 @@ class Extension(object):
e0 = Part.makeLine(edge.valueAt(edge.FirstParameter), e3.valueAt(e3.FirstParameter))
e2 = Part.makeLine(edge.valueAt(edge.LastParameter), e3.valueAt(e3.LastParameter))
return Part.Wire([e0, edge, e2, e3])
+
return Part.Wire([e3])
+
# the extension is bigger than the hole - so let's just cover the whole hole
if endPoints(edge):
# if the resulting arc is smaller than the radius, create a pie slice
@@ -226,6 +240,7 @@ class Extension(object):
e0 = Part.makeLine(center, edge.valueAt(edge.FirstParameter))
e2 = Part.makeLine(edge.valueAt(edge.LastParameter), center)
return Part.Wire([e0, edge, e2])
+
PathLog.track()
return Part.Wire([edge])
@@ -234,8 +249,10 @@ class Extension(object):
direction = self._getDirection(sub)
if direction is None:
return None
+
# return self._extendEdge(feature, edge, direction)
return self._extendEdge(feature, edges[0], direction)
+
return extendWire(feature, sub, self.length.Value)
@@ -257,20 +274,41 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
obj.addProperty('App::PropertyBool', 'ExtensionCorners', 'Extension', QtCore.QT_TRANSLATE_NOOP('PathPocketShape', 'When enabled connected extension edges are combined to wires.'))
obj.ExtensionCorners = True
+ obj.setEditorMode('ExtensionFeature', 2)
+ self.initRotationOp(obj)
+
+ def initRotationOp(self, obj):
+ '''initRotationOp(obj) ... setup receiver for rotation'''
if not hasattr(obj, 'ReverseDirection'):
obj.addProperty('App::PropertyBool', 'ReverseDirection', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Reverse direction of pocket operation.'))
if not hasattr(obj, 'InverseAngle'):
obj.addProperty('App::PropertyBool', 'InverseAngle', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Inverse the angle. Example: -22.5 -> 22.5 degrees.'))
- if not hasattr(obj, 'B_AxisErrorOverride'):
- obj.addProperty('App::PropertyBool', 'B_AxisErrorOverride', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Match B rotations to model (error in FreeCAD rendering).'))
if not hasattr(obj, 'AttemptInverseAngle'):
obj.addProperty('App::PropertyBool', 'AttemptInverseAngle', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Attempt the inverse angle for face access if original rotation fails.'))
+ if not hasattr(obj, 'LimitDepthToFace'):
+ obj.addProperty('App::PropertyBool', 'LimitDepthToFace', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Enforce the Z-depth of the selected face as the lowest value for final depth. Higher user values will be observed.'))
- obj.setEditorMode('ExtensionFeature', 2)
+ def areaOpOnChanged(self, obj, prop):
+ '''areaOpOnChanged(obj, porp) ... process operation specific changes to properties.'''
+ if prop == 'EnableRotation':
+ self.setEditorProperties(obj)
+
+ def setEditorProperties(self, obj):
+ if obj.EnableRotation == 'Off':
+ obj.setEditorMode('ReverseDirection', 2)
+ obj.setEditorMode('InverseAngle', 2)
+ obj.setEditorMode('AttemptInverseAngle', 2)
+ obj.setEditorMode('LimitDepthToFace', 2)
+ else:
+ obj.setEditorMode('ReverseDirection', 0)
+ obj.setEditorMode('InverseAngle', 0)
+ obj.setEditorMode('AttemptInverseAngle', 0)
+ obj.setEditorMode('LimitDepthToFace', 0)
def areaOpOnDocumentRestored(self, obj):
- '''opOnDocumentRestored(obj) ... adds the UseOutline property if it doesn't exist.'''
+ '''opOnDocumentRestored(obj) ... adds the UseOutline property, others, if they doesn't exist.'''
self.initPocketOp(obj)
+ self.setEditorProperties(obj)
def pocketInvertExtraOffset(self):
return False
@@ -296,6 +334,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
PathLog.debug(' -e.isClosed()')
clsd.append(edg)
planar = True
+
# Attempt to create planar faces and select that with smallest area for use as pocket base
if planar is True:
planar = False
@@ -309,11 +348,14 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
else:
if trans is True:
mFF.translate(FreeCAD.Vector(0, 0, face.BoundBox.ZMin - mFF.BoundBox.ZMin))
+
if FreeCAD.ActiveDocument.getObject(fName):
FreeCAD.ActiveDocument.removeObject(fName)
+
tmpFace = FreeCAD.ActiveDocument.addObject('Part::Feature', fName).Shape = mFF
tmpFace = FreeCAD.ActiveDocument.getObject(fName)
tmpFace.purgeTouched()
+
if minArea == 0.0:
minArea = tmpFace.Shape.Face1.Area
useFace = fName
@@ -324,8 +366,10 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
useFace = fName
else:
FreeCAD.ActiveDocument.removeObject(fName)
+
if useFace != 'useFaceName':
self.useTempJobClones(useFace)
+
return (planar, useFace)
def clasifySub(self, bs, sub):
@@ -338,12 +382,15 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
# it's a flat horizontal face
self.horiz.append(face)
return True
+
elif PathGeom.isHorizontal(face.Surface.Axis):
PathLog.debug(' -isHorizontal()')
self.vert.append(face)
return True
+
else:
return False
+
elif type(face.Surface) == Part.Cylinder and PathGeom.isVertical(face.Surface.Axis):
PathLog.debug('type() == Part.Cylinder')
# vertical cylinder wall
@@ -355,11 +402,13 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
disk.translate(FreeCAD.Vector(0, 0, face.BoundBox.ZMin - disk.BoundBox.ZMin))
self.horiz.append(disk)
return True
+
else:
PathLog.debug(' -none isClosed()')
# partial cylinder wall
self.vert.append(face)
return True
+
elif type(face.Surface) == Part.SurfaceOfExtrusion:
# extrusion wall
PathLog.debug('type() == Part.SurfaceOfExtrusion')
@@ -378,6 +427,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
# self.guiMessage(title, msg, False)
else:
PathLog.error(translate("Path", "Failed to create a planar face from edges in {}.".format(sub)))
+
else:
PathLog.debug(' -type(face.Surface): {}'.format(type(face.Surface)))
return False
@@ -398,6 +448,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
# First, check all subs collectively for loop of faces
if len(subsList) > 2:
(isLoop, norm, surf) = self.checkForFacesLoop(base, subsList)
+
if isLoop is True:
PathLog.info("Common Surface.Axis or normalAt() value found for loop faces.")
rtn = False
@@ -418,12 +469,18 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
if type(face.Surface) == Part.Plane:
if not PathGeom.isHorizontal(face.Surface.Axis):
rtn = False
+ PathLog.warning(translate("PathPocketShape", "Face appears to NOT be horizontal AFTER rotation applied."))
break
if rtn is False:
- if obj.AttemptInverseAngle is True and obj.InverseAngle is False:
- (clnBase, clnStock, angle) = self.applyInverseAngle(obj, clnBase, clnStock, axis, angle)
- else:
- PathLog.info(translate("Path", "Consider toggling the InverseAngle property and recomputing the operation."))
+ 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."))
+
+ if angle < -180.0:
+ angle += 360.0
tup = clnBase, subsList, angle, axis, clnStock
else:
@@ -434,6 +491,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
stock = PathUtils.findParentJob(obj).Stock
tup = base, subsList, angle, axis, stock
# Eif
+
allTuples.append(tup)
baseSubsTuples.append(tup)
# Eif
@@ -468,15 +526,21 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
faceIA = clnBase.Shape.getElement(sub)
(norm, surf) = self.getFaceNormAndSurf(faceIA)
(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:
- (clnBase, clnStock, angle) = self.applyInverseAngle(obj, clnBase, clnStock, axis, angle)
- else:
- PathLog.info(translate("Path", "Consider toggling the InverseAngle property and recomputing the operation."))
+ 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."))
else:
PathLog.debug("Face appears to be oriented correctly.")
+ if angle < -180.0:
+ angle += 360.0
+
tup = clnBase, [sub], angle, axis, clnStock
else:
if self.warnDisabledAxis(obj, axis) is False:
@@ -506,7 +570,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
if clasifySub(self, subBase, sub) is False:
PathLog.error(translate('PathPocket', 'Pocket does not support shape %s.%s') % (subBase.Label, sub))
if obj.EnableRotation != 'Off':
- PathLog.info(translate('PathPocket', 'Face might not be within rotation accessibility limits.'))
+ PathLog.warning(translate('PathPocket', 'Face might not be within rotation accessibility limits.'))
# Determine final depth as highest value of bottom boundbox of vertical face,
# in case of uneven faces on bottom
@@ -545,30 +609,56 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
self.exts.append(face)
# move all horizontal faces to FinalDepth
- for f in self.horiz:
- finDep = obj.FinalDepth.Value # max(obj.FinalDepth.Value, f.BoundBox.ZMin)
- f.translate(FreeCAD.Vector(0, 0, finDep - f.BoundBox.ZMin))
+ # for f in self.horiz:
+ # f.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - f.BoundBox.ZMin))
# check all faces and see if they are touching/overlapping and combine those into a compound
self.horizontal = [] # pylint: disable=attribute-defined-outside-init
for shape in PathGeom.combineConnectedShapes(self.horiz):
shape.sewShape()
# shape.tessellate(0.1)
+ shpZMin = shape.BoundBox.ZMin
+ PathLog.debug('PathGeom.combineConnectedShapes shape.BoundBox.ZMin: {}'.format(shape.BoundBox.ZMin))
if obj.UseOutline:
wire = TechDraw.findShapeOutline(shape, 1, FreeCAD.Vector(0, 0, 1))
- wire.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - wire.BoundBox.ZMin))
- self.horizontal.append(Part.Face(wire))
+ wFace = Part.Face(wire)
+ if wFace.BoundBox.ZMin != shpZMin:
+ wFace.translate(FreeCAD.Vector(0, 0, shpZMin - wFace.BoundBox.ZMin))
+ self.horizontal.append(wFace)
+ PathLog.debug('PathGeom.combineConnectedShapes shape.BoundBox.ZMin: {}'.format(wFace.BoundBox.ZMin))
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)
+ clrnc = 0.5
for face in self.horizontal:
- self.removalshapes.append((face.removeSplitter().extrude(extent),
- False, 'pathPocketShape', angle, axis, sD, fD))
- PathLog.debug("Extent depths are str: {}, and fin: {}".format(sD, fD))
+ afD = fD
+ useAngle = angle
+ shpZMin = face.BoundBox.ZMin
+ PathLog.debug('self.horizontal shpZMin: {}'.format(shpZMin))
+ if self.isFaceUp(subBase, face) is False:
+ useAngle += 180.0
+ invZ = (-2 * shpZMin) - clrnc
+ face.translate(FreeCAD.Vector(0.0, 0.0, invZ))
+ shpZMin = -1 * shpZMin
+ else:
+ face.translate(FreeCAD.Vector(0.0, 0.0, -1 * clrnc))
+
+ if obj.LimitDepthToFace is True and obj.EnableRotation != 'Off':
+ if shpZMin > obj.FinalDepth.Value:
+ afD = shpZMin
+ if sD <= afD:
+ PathLog.error('Start Depth is lower than face depth.')
+ sD = afD + 1.0
+ else:
+ face.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - shpZMin))
+
+ extent = FreeCAD.Vector(0, 0, sD - afD + clrnc)
+ extShp = face.removeSplitter().extrude(extent)
+ self.removalshapes.append((extShp, False, 'pathPocketShape', useAngle, axis, sD, afD))
+ PathLog.debug("Extent values are strDep: {}, finDep: {}, extrd: {}".format(sD, afD, extent))
# Efor face
# Efor
@@ -604,8 +694,8 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
obj.UseOutline = False
obj.ReverseDirection = False
obj.InverseAngle = False
- obj.B_AxisErrorOverride = False
obj.AttemptInverseAngle = True
+ obj.LimitDepthToFace = True
obj.setExpression('ExtensionLengthDefault', 'OpToolDiameter / 2')
def createExtension(self, obj, extObj, extFeature, extSub):
@@ -792,8 +882,8 @@ def SetupProperties():
setup.append('ExtensionCorners')
setup.append("ReverseDirection")
setup.append("InverseAngle")
- setup.append("B_AxisErrorOverride")
setup.append("AttemptInverseAngle")
+ setup.append("LimitDepthToFace")
return setup
diff --git a/src/Mod/Path/PathScripts/PathProfileBase.py b/src/Mod/Path/PathScripts/PathProfileBase.py
index b406dd127b..07d7cb793d 100644
--- a/src/Mod/Path/PathScripts/PathProfileBase.py
+++ b/src/Mod/Path/PathScripts/PathProfileBase.py
@@ -3,6 +3,8 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 sliptonic *
+# * Copyright (c) 2020 Schildkroet *
+# * 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) *
@@ -28,12 +30,13 @@ import PathScripts.PathLog as PathLog
from PySide import QtCore
__title__ = "Base Path Profile Operation"
-__author__ = "sliptonic (Brad Collette)"
+__author__ = "sliptonic (Brad Collette), Schildkroet"
__url__ = "http://www.freecadweb.org"
__doc__ = "Base class and implementation for Path profile operations."
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-#PathLog.trackModule(PathLog.thisModule())
+# PathLog.trackModule(PathLog.thisModule())
+
# Qt translation handling
def translate(context, text, disambig=None):
@@ -74,9 +77,23 @@ class ObjectProfile(PathAreaOp.ObjectOp):
else:
obj.setEditorMode('MiterLimit', 2)
+ self.extraOpOnChanged(obj, prop)
+
+ def extraOpOnChanged(self, obj, prop):
+ '''otherOpOnChanged(obj, porp) ... overwrite to process onChange() events.
+ Can safely be overwritten by subclasses.'''
+ pass # pylint: disable=unnecessary-pass
+
+ def setOpEditorProperties(self, obj):
+ '''setOpEditorProperties(obj, porp) ... overwrite to process operation specific changes to properties.
+ Can safely be overwritten by subclasses.'''
+ pass # pylint: disable=unnecessary-pass
+
def areaOpOnDocumentRestored(self, obj):
for prop in ['UseComp', 'JoinType']:
self.areaOpOnChanged(obj, prop)
+
+ self.setOpEditorProperties(obj)
def areaOpAreaParams(self, obj, isHole):
'''areaOpAreaParams(obj, isHole) ... returns dictionary with area parameters.
@@ -118,6 +135,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
params['orientation'] = 0
else:
params['orientation'] = 1
+
if not obj.UseComp:
if direction == 'CCW':
params['orientation'] = 1
@@ -140,6 +158,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
obj.JoinType = "Round"
obj.MiterLimit = 0.1
+
def SetupProperties():
setup = []
setup.append('Side')
diff --git a/src/Mod/Path/PathScripts/PathProfileBaseGui.py b/src/Mod/Path/PathScripts/PathProfileBaseGui.py
index 22cdcd7699..350bef44fc 100644
--- a/src/Mod/Path/PathScripts/PathProfileBaseGui.py
+++ b/src/Mod/Path/PathScripts/PathProfileBaseGui.py
@@ -78,6 +78,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
obj.UseStartPoint = self.form.useStartPoint.isChecked()
if obj.Direction != str(self.form.direction.currentText()):
obj.Direction = str(self.form.direction.currentText())
+ if obj.EnableRotation != str(self.form.enableRotation.currentText()):
+ obj.EnableRotation = str(self.form.enableRotation.currentText())
self.updateToolController(obj, self.form.toolController)
self.updateCoolant(obj, self.form.coolantController)
@@ -103,6 +105,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.selectInComboBox(obj.Direction, self.form.direction)
self.setupToolController(obj, self.form.toolController)
self.setupCoolant(obj, self.form.coolantController)
+ self.selectInComboBox(obj.EnableRotation, self.form.enableRotation)
if FeatureSide & self.profileFeatures():
self.selectInComboBox(obj.Side, self.form.cutSide)
@@ -121,6 +124,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
signals.append(self.form.extraOffset.editingFinished)
signals.append(self.form.toolController.currentIndexChanged)
signals.append(self.form.coolantController.currentIndexChanged)
+ signals.append(self.form.enableRotation.currentIndexChanged)
if FeatureSide & self.profileFeatures():
signals.append(self.form.cutSide.currentIndexChanged)
diff --git a/src/Mod/Path/PathScripts/PathProfileFaces.py b/src/Mod/Path/PathScripts/PathProfileFaces.py
index 620a6196e9..ee57887332 100644
--- a/src/Mod/Path/PathScripts/PathProfileFaces.py
+++ b/src/Mod/Path/PathScripts/PathProfileFaces.py
@@ -3,6 +3,8 @@
# ***************************************************************************
# * *
# * Copyright (c) 2014 Yorik van Havre *
+# * Copyright (c) 2020 russ4262 (Russell Johnson) *
+# * Copyright (c) 2020 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -35,13 +37,9 @@ import numpy
from PySide import QtCore
__title__ = "Path Profile Faces Operation"
-__author__ = "sliptonic (Brad Collette)"
+__author__ = "sliptonic (Brad Collette), Schildkroet"
__url__ = "http://www.freecadweb.org"
__doc__ = "Path Profile operation based on faces."
-__contributors__ = "russ4262 (Russell Johnson, russ4262@gmail.com)"
-__created__ = "2014"
-__scriptVersion__ = "2j usable"
-__lastModified__ = "2019-07-25 14:48 CST"
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
@@ -71,20 +69,42 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
obj.addProperty("App::PropertyBool", "processPerimeter", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile the outline"))
obj.addProperty("App::PropertyBool", "processCircles", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile round holes"))
+ if not hasattr(obj, 'HandleMultipleFeatures'):
+ obj.addProperty('App::PropertyEnumeration', 'HandleMultipleFeatures', 'Profile', QtCore.QT_TRANSLATE_NOOP('PathPocket', 'Choose how to process multiple Base Geometry features.'))
+
+ obj.HandleMultipleFeatures = ['Collectively', 'Individually']
+
+ self.initRotationOp(obj)
+ self.baseObject().initAreaOp(obj)
+ self.setOpEditorProperties(obj)
+
+ def initRotationOp(self, obj):
+ '''initRotationOp(obj) ... setup receiver for rotation'''
if not hasattr(obj, 'ReverseDirection'):
obj.addProperty('App::PropertyBool', 'ReverseDirection', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Reverse direction of pocket operation.'))
if not hasattr(obj, 'InverseAngle'):
obj.addProperty('App::PropertyBool', 'InverseAngle', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Inverse the angle. Example: -22.5 -> 22.5 degrees.'))
- if not hasattr(obj, 'B_AxisErrorOverride'):
- obj.addProperty('App::PropertyBool', 'B_AxisErrorOverride', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Match B rotations to model (error in FreeCAD rendering).'))
if not hasattr(obj, 'AttemptInverseAngle'):
obj.addProperty('App::PropertyBool', 'AttemptInverseAngle', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Attempt the inverse angle for face access if original rotation fails.'))
+ if not hasattr(obj, 'LimitDepthToFace'):
+ obj.addProperty('App::PropertyBool', 'LimitDepthToFace', 'Rotation', QtCore.QT_TRANSLATE_NOOP('App::Property', 'Enforce the Z-depth of the selected face as the lowest value for final depth. Higher user values will be observed.'))
- if not hasattr(obj, 'HandleMultipleFeatures'):
- obj.addProperty('App::PropertyEnumeration', 'HandleMultipleFeatures', 'Profile', QtCore.QT_TRANSLATE_NOOP('PathPocket', 'Choose how to process multiple Base Geometry features.'))
- obj.HandleMultipleFeatures = ['Collectively', 'Individually']
+ def extraOpOnChanged(self, obj, prop):
+ '''extraOpOnChanged(obj, porp) ... process operation specific changes to properties.'''
+ if prop == 'EnableRotation':
+ self.setOpEditorProperties(obj)
- self.baseObject().initAreaOp(obj)
+ def setOpEditorProperties(self, obj):
+ if obj.EnableRotation == 'Off':
+ obj.setEditorMode('ReverseDirection', 2)
+ obj.setEditorMode('InverseAngle', 2)
+ obj.setEditorMode('AttemptInverseAngle', 2)
+ obj.setEditorMode('LimitDepthToFace', 2)
+ else:
+ obj.setEditorMode('ReverseDirection', 0)
+ obj.setEditorMode('InverseAngle', 0)
+ obj.setEditorMode('AttemptInverseAngle', 0)
+ obj.setEditorMode('LimitDepthToFace', 0)
def areaOpShapes(self, obj):
'''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.'''
@@ -138,17 +158,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
@@ -173,6 +197,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:
@@ -181,23 +206,15 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
PathLog.error(msg)
FreeCAD.Console.PrintWarning(msg)
- # Raise FinalDepth to lowest face in list on Inside profile ops
- finDep = obj.FinalDepth.Value
+ # 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)
-
- # Recalculate depthparams
- self.depthparams = PathUtils.depth_params( # pylint: disable=attribute-defined-outside-init
- clearance_height=obj.ClearanceHeight.Value,
- safe_height=obj.SafeHeight.Value,
- start_depth=strDep, # obj.StartDepth.Value,
- step_down=obj.StepDown.Value,
- z_finish_step=finish_step,
- final_depth=finDep, # obj.FinalDepth.Value,
- user_depths=None)
+ self.depthparams = self._customDepthParams(obj, strDep, finDep)
for shape, wire in holes:
f = Part.makeFace(wire, 'Part::FaceMakerSimple')
@@ -213,14 +230,20 @@ 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
try:
- env = PathUtils.getEnvelope(base.Shape, subshape=profileshape, depthparams=self.depthparams)
+ env = PathUtils.getEnvelope(base.Shape, subshape=profileshape, depthparams=custDepthparams)
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])
@@ -230,14 +253,8 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
if finalDep < shape.BoundBox.ZMin:
# Recalculate depthparams
finalDep = shape.BoundBox.ZMin
- custDepthparams = PathUtils.depth_params(
- clearance_height=obj.ClearanceHeight.Value,
- safe_height=obj.SafeHeight.Value,
- start_depth=strDep, # obj.StartDepth.Value,
- step_down=obj.StepDown.Value,
- z_finish_step=finish_step,
- final_depth=finalDep, # obj.FinalDepth.Value,
- user_depths=None)
+ custDepthparams = self._customDepthParams(obj, strDep, finalDep - 0.5)
+
env = PathUtils.getEnvelope(base.Shape, subshape=profShape, depthparams=custDepthparams)
tup = env, False, 'pathProfileFaces', angle, axis, strDep, finalDep
shapes.append(tup)
@@ -246,6 +263,7 @@ 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"):
@@ -284,7 +302,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile):
obj.ReverseDirection = False
obj.InverseAngle = False
obj.AttemptInverseAngle = True
- obj.B_AxisErrorOverride = False
+ obj.LimitDepthToFace = True
obj.HandleMultipleFeatures = 'Collectively'
@@ -295,7 +313,6 @@ def SetupProperties():
setup.append("processCircles")
setup.append("ReverseDirection")
setup.append("InverseAngle")
- setup.append("B_AxisErrorOverride")
setup.append("AttemptInverseAngle")
setup.append("HandleMultipleFeatures")
return setup
@@ -305,5 +322,6 @@ 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