Skip to content

Commit

Permalink
Merge pull request #3568 from Russ4262/3D_Surface_fixes_2
Browse files Browse the repository at this point in the history
[Path] 3D Surface and Waterline: FinalDepth guess and `InternalFeaturesCut` fixes
  • Loading branch information
sliptonic committed Jun 19, 2020
2 parents 7aa20e8 + 0f393e2 commit 7c3d004
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 37 deletions.
11 changes: 11 additions & 0 deletions src/Mod/Path/PathScripts/PathSurface.py
Expand Up @@ -436,6 +436,17 @@ def opUpdateDepths(self, obj):
except Part.OCCError as e:
PathLog.error(e)
obj.OpFinalDepth = zmin
elif self.job:
if hasattr(obj, 'BoundBox'):
if obj.BoundBox == 'BaseBoundBox':
models = self.job.Model.Group
zmin = models[0].Shape.BoundBox.ZMin
for M in models:
zmin = min(zmin, M.Shape.BoundBox.ZMin)
obj.OpFinalDepth = zmin
if obj.BoundBox == 'Stock':
models = self.job.Stock
obj.OpFinalDepth = self.job.Stock.Shape.BoundBox.ZMin

def opExecute(self, obj):
'''opExecute(obj) ... process surface operation'''
Expand Down
2 changes: 1 addition & 1 deletion src/Mod/Path/PathScripts/PathSurfaceGui.py
Expand Up @@ -40,7 +40,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
'''Page controller class for the Surface operation.'''

def initPage(self, obj):
self.setTitle("3D Surface")
self.setTitle("3D Surface - " + obj.Label)
# self.updateVisibility()
# retrieve property enumerations
self.propEnums = PathSurface.ObjectSurface.opPropertyEnumerations(False)
Expand Down
99 changes: 64 additions & 35 deletions src/Mod/Path/PathScripts/PathSurfaceSupport.py
Expand Up @@ -664,7 +664,9 @@ def _preProcessFacesAndVoids(self, base, FCS, VDS):
FUR.setTempGroup(self.tempGroup)
outFCS = FUR.getUnifiedRegions()
if not self.obj.InternalFeaturesCut:
ifL.extend(FUR.getInternalFeatures())
gIF = FUR.getInternalFeatures()
if gIF:
ifL.extend(gIF)

PathLog.debug('Attempting to get cross-section of collective faces.')
if len(outFCS) == 0:
Expand Down Expand Up @@ -740,7 +742,9 @@ def _preProcessFacesAndVoids(self, base, FCS, VDS):
if len(gUR) > 0:
outerFace = gUR[0]
if not self.obj.InternalFeaturesCut:
ifL = FUR.getInternalFeatures()
gIF = FUR.getInternalFeatures()
if gIF:
ifL = gIF

if outerFace:
PathLog.debug('Attempting to create offset face of Face{}'.format(fNum))
Expand Down Expand Up @@ -804,9 +808,13 @@ def _preProcessFacesAndVoids(self, base, FCS, VDS):
FUR = FindUnifiedRegions([(fcshp, fcIdx)], self.JOB.GeometryTolerance.Value)
if self.showDebugObjects:
FUR.setTempGroup(self.tempGroup)
outFCS.extend(FUR.getUnifiedRegions())
gUR = FUR.getUnifiedRegions()
if len(gUR) > 0:
outFCS.extend(gUR)
if not self.obj.InternalFeaturesCut:
intFEAT.extend(FUR.getInternalFeatures())
gIF = FUR.getInternalFeatures()
if gIF:
intFEAT.extend(gIF)

lenOtFcs = len(outFCS)
if lenOtFcs == 0:
Expand Down Expand Up @@ -1773,10 +1781,11 @@ def __init__(self, facesList, geomToler):
self.noSharedEdges = True
self.topWires = list()
self.REGIONS = list()
self.INTERNALS = False
self.INTERNALS = list()
self.idGroups = list()
self.sharedEdgeIdxs = list()
self.fusedFaces = None
self.internalsReady = False

if self.geomToler == 0.0:
self.geomToler = 0.00001
Expand Down Expand Up @@ -1807,37 +1816,43 @@ def _extractTopFaces(self):
cutBox.translate(FreeCAD.Vector(efBB.XMin - 1.0, efBB.YMin - 1.0, zHght))
base = ef.cut(cutBox)

# Identify top face of base
fIdx = 0
zMin = base.Faces[fIdx].BoundBox.ZMin
for bfi in range(0, len(base.Faces)):
fzmin = base.Faces[bfi].BoundBox.ZMin
if fzmin > zMin:
fIdx = bfi
zMin = fzmin

# Translate top face to Z=0.0 and save to topFaces list
topFace = base.Faces[fIdx]
# self._showShape(topFace, 'topFace_{}'.format(fNum))
tfBB = topFace.BoundBox
tfBB_Area = tfBB.XLength * tfBB.YLength
fBB_Area = fBB.XLength * fBB.YLength
if tfBB_Area < (fBB_Area * 0.9):
# attempt alternate methods
topFace = self._getCompleteCrossSection(ef)
if base.Volume == 0:
PathLog.debug('Ignoring Face{}. It is likely vertical with no horizontal exposure.'.format(fcIdx))
cont = False

if cont:
# Identify top face of base
fIdx = 0
zMin = base.Faces[fIdx].BoundBox.ZMin
for bfi in range(0, len(base.Faces)):
fzmin = base.Faces[bfi].BoundBox.ZMin
if fzmin > zMin:
fIdx = bfi
zMin = fzmin

# Translate top face to Z=0.0 and save to topFaces list
topFace = base.Faces[fIdx]
# self._showShape(topFace, 'topFace_{}'.format(fNum))
tfBB = topFace.BoundBox
tfBB_Area = tfBB.XLength * tfBB.YLength
# self._showShape(topFace, 'topFaceAlt_1_{}'.format(fNum))
fBB_Area = fBB.XLength * fBB.YLength
if tfBB_Area < (fBB_Area * 0.9):
topFace = getShapeSlice(ef)
# attempt alternate methods
topFace = self._getCompleteCrossSection(ef)
tfBB = topFace.BoundBox
tfBB_Area = tfBB.XLength * tfBB.YLength
# self._showShape(topFace, 'topFaceAlt_2_{}'.format(fNum))
# self._showShape(topFace, 'topFaceAlt_1_{}'.format(fNum))
if tfBB_Area < (fBB_Area * 0.9):
msg = translate('PathSurfaceSupport',
'Faild to extract processing region for Face')
FreeCAD.Console.PrintError(msg + '{}.\n'.format(fNum))
cont = False
topFace = getShapeSlice(ef)
tfBB = topFace.BoundBox
tfBB_Area = tfBB.XLength * tfBB.YLength
# self._showShape(topFace, 'topFaceAlt_2_{}'.format(fNum))
if tfBB_Area < (fBB_Area * 0.9):
msg = translate('PathSurfaceSupport',
'Faild to extract processing region for Face')
FreeCAD.Console.PrintError(msg + '{}.\n'.format(fNum))
cont = False
# Eif

if cont:
topFace.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - zMin))
Expand Down Expand Up @@ -2157,7 +2172,6 @@ def _processNestedRegions(self):
# if True action here
if isTrue:
self.REGIONS[hi] = high.cut(low)
# self.INTERNALS.append(low)
remList.append(li)
else:
hold.append(hi)
Expand Down Expand Up @@ -2233,7 +2247,6 @@ def getUnifiedRegions(self):
'''getUnifiedRegions()... Returns a list of unified regions from list
of tuples (faceShape, faceIndex) received at instantiation of the class object.'''
PathLog.debug('getUnifiedRegions()')
self.INTERNALS = list()
if len(self.FACES) == 0:
msg = translate('PathSurfaceSupport',
'No FACE data tuples received at instantiation of class.')
Expand All @@ -2255,6 +2268,7 @@ def getUnifiedRegions(self):
for w in range(1, lenWrs):
wr = topFace.Wires[w]
self.INTERNALS.append(Part.Face(wr))
self.internalsReady = True
# Flatten face and extract outer wire, then convert to face
extWire = getExtrudedShape(topFace)
wCS = getCrossSection(extWire)
Expand All @@ -2281,7 +2295,17 @@ def getUnifiedRegions(self):

if self.noSharedEdges:
PathLog.debug('No shared edges by length detected.')
return [topFace for (topFace, fcIdx) in self.topFaces]
allTopFaces = list()
for (topFace, fcIdx) in self.topFaces:
allTopFaces.append(topFace)
# Identify internal features
lenWrs = len(topFace.Wires)
if lenWrs > 1:
for w in range(1, lenWrs):
wr = topFace.Wires[w]
self.INTERNALS.append(Part.Face(wr))
self.internalsReady = True
return allTopFaces
else:
# Delete shared edges from edgeData list
self.sharedEdgeIdxs.sort(reverse=True)
Expand All @@ -2294,13 +2318,18 @@ def getUnifiedRegions(self):
# for ri in range(0, len(self.REGIONS)):
# self._showShape(self.REGIONS[ri], 'UnifiedRegion_{}'.format(ri))

self.internalsReady = True
return self.REGIONS

def getInternalFeatures(self):
'''getInternalFeatures()... Returns internal features identified
after calling getUnifiedRegions().'''
if self.INTERNALS:
return self.INTERNALS
if self.internalsReady:
if len(self.INTERNALS) > 0:
return self.INTERNALS
else:
return False

msg = translate('PathSurfaceSupport',
'getUnifiedRegions() must be called before getInternalFeatures().')
FreeCAD.Console.PrintError(msg + '\n')
Expand Down
25 changes: 25 additions & 0 deletions src/Mod/Path/PathScripts/PathWaterline.py
Expand Up @@ -406,6 +406,31 @@ def opApplyPropertyLimits(self, obj):
obj.AvoidLastX_Faces = 100
PathLog.error(translate('PathWaterline', 'AvoidLastX_Faces: Avoid last X faces count limited to 100.'))

def opUpdateDepths(self, obj):
if hasattr(obj, 'Base') and obj.Base:
base, sublist = obj.Base[0]
fbb = base.Shape.getElement(sublist[0]).BoundBox
zmin = fbb.ZMax
for base, sublist in obj.Base:
for sub in sublist:
try:
fbb = base.Shape.getElement(sub).BoundBox
zmin = min(zmin, fbb.ZMin)
except Part.OCCError as e:
PathLog.error(e)
obj.OpFinalDepth = zmin
elif self.job:
if hasattr(obj, 'BoundBox'):
if obj.BoundBox == 'BaseBoundBox':
models = self.job.Model.Group
zmin = models[0].Shape.BoundBox.ZMin
for M in models:
zmin = min(zmin, M.Shape.BoundBox.ZMin)
obj.OpFinalDepth = zmin
if obj.BoundBox == 'Stock':
models = self.job.Stock
obj.OpFinalDepth = self.job.Stock.Shape.BoundBox.ZMin

def opExecute(self, obj):
'''opExecute(obj) ... process surface operation'''
PathLog.track()
Expand Down
2 changes: 1 addition & 1 deletion src/Mod/Path/PathScripts/PathWaterlineGui.py
Expand Up @@ -41,7 +41,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
'''Page controller class for the Waterline operation.'''

def initPage(self, obj):
# self.setTitle("Waterline")
self.setTitle("Waterline - " + obj.Label)
self.updateVisibility()

def getForm(self):
Expand Down

0 comments on commit 7c3d004

Please sign in to comment.