3D Pocket: Upgrade to collective face processing!

New property added: `HandleMultipleFeatures`.
New property and related code allows for improved, and expected, 3D Pocket operations.
Improvement combines faces selected to create one envelope to be processed as the path shape ('collectively' setting).
Old behavior is available with 'Individually' setting.
Enjoy!
This commit is contained in:
Russell Johnson
2019-06-30 12:55:59 -05:00
parent 67d426efd0
commit e2d04ec991

View File

@@ -21,6 +21,12 @@
# * USA * # * USA *
# * * # * *
# *************************************************************************** # ***************************************************************************
# * *
# * Additional modifications and contributions beginning 2019 *
# * Focus: improve 3D facial pockets *
# * by Russell Johnson <russ4262@gmail.com> *
# * *
# ***************************************************************************
import FreeCAD import FreeCAD
import Part import Part
@@ -31,7 +37,14 @@ import PathScripts.PathUtils as PathUtils
from PySide import QtCore from PySide import QtCore
__doc__ = "Class and implementation of the Pocket operation." __title__ = "Path 3D Pocket Operation"
__author__ = "Yorik van Havre <yorik@uncreated.net>"
__url__ = "http://www.freecadweb.org"
__doc__ = "Class and implementation of the 3D Pocket operation."
__contributors__ = "russ4262 (Russell Johnson)"
__created__ = "2014"
__scriptVersion__ = "1a testing"
__lastModified__ = "2019-06-28 23:45 CST"
LOGLEVEL = False LOGLEVEL = False
@@ -41,6 +54,7 @@ if LOGLEVEL:
else: else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# Qt translation handling # Qt translation handling
def translate(context, text, disambig=None): def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig) return QtCore.QCoreApplication.translate(context, text, disambig)
@@ -54,31 +68,58 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
def initPocketOp(self, obj): def initPocketOp(self, obj):
'''initPocketOp(obj) ... setup receiver''' '''initPocketOp(obj) ... setup receiver'''
if not hasattr(obj, 'HandleMultipleFeatures'):
obj.addProperty('App::PropertyEnumeration', 'HandleMultipleFeatures', 'Pocket', QtCore.QT_TRANSLATE_NOOP('PathPocket', 'Choose how to process multiple Base Geometry features.'))
obj.HandleMultipleFeatures = ['Collectively', 'Individually']
pass pass
def opOnDocumentRestored(self, obj):
'''opOnDocumentRestored(obj) ... adds the properties if they doesn't exist.'''
self.initPocketOp(obj)
def pocketInvertExtraOffset(self): def pocketInvertExtraOffset(self):
return False return False
def areaOpShapes(self, obj): def areaOpShapes(self, obj):
'''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' '''areaOpShapes(obj) ... return shapes representing the solids to be removed.'''
PathLog.track() PathLog.track()
PathLog.info("----- areaOpShapes() in PathPocket.py")
removalshapes = [] removalshapes = []
if obj.Base: if obj.Base:
PathLog.debug("base items exist. Processing...") PathLog.debug("base items exist. Processing...")
for base in obj.Base: for base in obj.Base:
PathLog.debug("Base item: {}".format(base)) PathLog.debug("Base item: {}".format(base))
# Check if all subs are faces
allFaceSubs = True
Faces = []
for sub in base[1]: for sub in base[1]:
if "Face" in sub: if "Face" in sub:
shape = Part.makeCompound([getattr(base[0].Shape, sub)]) Faces.append(getattr(base[0].Shape, sub))
else: else:
edges = [getattr(base[0].Shape, sub) for sub in base[1]] allFaceSubs = False
shape = Part.makeFace(edges, 'Part::FaceMakerSimple') break
if allFaceSubs is True and obj.HandleMultipleFeatures == 'Collectively':
shape = Part.makeCompound(Faces)
env = PathUtils.getEnvelope(base[0].Shape, subshape=shape, depthparams=self.depthparams) env = PathUtils.getEnvelope(base[0].Shape, subshape=shape, depthparams=self.depthparams)
obj.removalshape = env.cut(base[0].Shape) obj.removalshape = env.cut(base[0].Shape)
obj.removalshape.tessellate(0.1) obj.removalshape.tessellate(0.1)
removalshapes.append((obj.removalshape, False)) removalshapes.append((obj.removalshape, False))
else:
for sub in base[1]:
if "Face" in sub:
shape = Part.makeCompound([getattr(base[0].Shape, sub)])
else:
edges = [getattr(base[0].Shape, sub) for sub in base[1]]
shape = Part.makeFace(edges, 'Part::FaceMakerSimple')
env = PathUtils.getEnvelope(base[0].Shape, subshape=shape, depthparams=self.depthparams)
obj.removalshape = env.cut(base[0].Shape)
obj.removalshape.tessellate(0.1)
removalshapes.append((obj.removalshape, False))
else: # process the job base object as a whole else: # process the job base object as a whole
PathLog.debug("processing the whole job base object") PathLog.debug("processing the whole job base object")
for base in self.model: for base in self.model:
@@ -92,11 +133,14 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
'''areaOpSetDefaultValues(obj, job) ... set default values''' '''areaOpSetDefaultValues(obj, job) ... set default values'''
obj.StepOver = 100 obj.StepOver = 100
obj.ZigZagAngle = 45 obj.ZigZagAngle = 45
obj.HandleMultipleFeatures = 'Collectively'
def SetupProperties(): def SetupProperties():
return PathPocketBase.SetupProperties() return PathPocketBase.SetupProperties().append("HandleMultipleFeatures")
def Create(name, obj = None):
def Create(name, obj=None):
'''Create(name) ... Creates and returns a Pocket operation.''' '''Create(name) ... Creates and returns a Pocket operation.'''
if obj is None: if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)