Merge pull request #3556 from Russ4262/3D_Surface_Waterline_Fixes
Path: 3D Surface and Waterline fixes per forum identification
This commit is contained in:
@@ -156,7 +156,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<widget class="QComboBox" name="profileEdges">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Profile the edges of the selection.</p></body></html></string>
|
||||
</property>
|
||||
|
||||
@@ -165,16 +165,6 @@
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Line</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ZigZag</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Circular</string>
|
||||
@@ -185,6 +175,26 @@
|
||||
<string>CircularZigZag</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Line</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Spiral</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ZigZag</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="3">
|
||||
|
||||
@@ -38,7 +38,8 @@ from PySide import QtCore
|
||||
try:
|
||||
import ocl
|
||||
except ImportError:
|
||||
msg = QtCore.QCoreApplication.translate("PathSurface", "This operation requires OpenCamLib to be installed.")
|
||||
msg = QtCore.QCoreApplication.translate("PathSurface",
|
||||
"This operation requires OpenCamLib to be installed.")
|
||||
FreeCAD.Console.PrintError(msg + "\n")
|
||||
raise ImportError
|
||||
# import sys
|
||||
@@ -206,7 +207,7 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
'BoundBox': ['BaseBoundBox', 'Stock'],
|
||||
'PatternCenterAt': ['CenterOfMass', 'CenterOfBoundBox', 'XminYmin', 'Custom'],
|
||||
'CutMode': ['Conventional', 'Climb'],
|
||||
'CutPattern': ['Line', 'Circular', 'CircularZigZag', 'Offset', 'Spiral', 'ZigZag'], # Additional goals ['Offset', 'ZigZagOffset', 'Grid', 'Triangle']
|
||||
'CutPattern': ['Circular', 'CircularZigZag', 'Line', 'Offset', 'Spiral', 'ZigZag'], # Additional goals ['Offset', 'ZigZagOffset', 'Grid', 'Triangle']
|
||||
'DropCutterDir': ['X', 'Y'],
|
||||
'HandleMultipleFeatures': ['Collectively', 'Individually'],
|
||||
'LayerMode': ['Single-pass', 'Multi-pass'],
|
||||
@@ -575,18 +576,18 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
PathSurfaceSupport._prepareModelSTLs(self, JOB, obj, m, ocl)
|
||||
|
||||
Mdl = JOB.Model.Group[m]
|
||||
if FACES[m] is False:
|
||||
PathLog.error('No data for model base: {}'.format(JOB.Model.Group[m].Label))
|
||||
else:
|
||||
if FACES[m]:
|
||||
PathLog.debug('Working on Model.Group[{}]: {}'.format(m, Mdl.Label))
|
||||
if m > 0:
|
||||
# Raise to clearance between models
|
||||
CMDS.append(Path.Command('N (Transition to base: {}.)'.format(Mdl.Label)))
|
||||
CMDS.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
|
||||
PathLog.info('Working on Model.Group[{}]: {}'.format(m, Mdl.Label))
|
||||
# make stock-model-voidShapes STL model for avoidance detection on transitions
|
||||
PathSurfaceSupport._makeSafeSTL(self, JOB, obj, m, FACES[m], VOIDS[m], ocl)
|
||||
# Process model/faces - OCL objects must be ready
|
||||
CMDS.extend(self._processCutAreas(JOB, obj, m, FACES[m], VOIDS[m]))
|
||||
else:
|
||||
PathLog.debug('No data for model base: {}'.format(JOB.Model.Group[m].Label))
|
||||
|
||||
# Save gcode produced
|
||||
self.commandlist.extend(CMDS)
|
||||
@@ -659,7 +660,8 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
exTime = str(tMins) + ' min. ' + str(round(tSecs, 5)) + ' sec.'
|
||||
else:
|
||||
exTime = str(round(execTime, 5)) + ' sec.'
|
||||
FreeCAD.Console.PrintMessage('3D Surface operation time is {}\n'.format(exTime))
|
||||
msg = translate('PathSurface', 'operation time is')
|
||||
FreeCAD.Console.PrintMessage('3D Surface ' + msg + '{}\n'.format(exTime))
|
||||
|
||||
if self.cancelOperation:
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("PathSurface", "Canceled 3D Surface operation."))
|
||||
@@ -751,27 +753,21 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
if obj.ProfileEdges != 'None':
|
||||
prflShp = self.profileShapes[mdlIdx][fsi]
|
||||
if prflShp is False:
|
||||
PathLog.error('No profile shape is False.')
|
||||
msg = translate('PathSurface', 'No profile geometry shape returned.')
|
||||
PathLog.error(msg)
|
||||
return list()
|
||||
if self.showDebugObjects:
|
||||
P = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpNewProfileShape')
|
||||
P.Shape = prflShp
|
||||
P.purgeTouched()
|
||||
self.tempGroup.addObject(P)
|
||||
self.showDebugObject(prflShp, 'NewProfileShape')
|
||||
# get offset path geometry and perform OCL scan with that geometry
|
||||
pathOffsetGeom = self._offsetFacesToPointData(obj, prflShp)
|
||||
if pathOffsetGeom is False:
|
||||
PathLog.error('No profile geometry returned.')
|
||||
msg = translate('PathSurface', 'No profile path geometry returned.')
|
||||
PathLog.error(msg)
|
||||
return list()
|
||||
profScan = [self._planarPerformOclScan(obj, pdc, pathOffsetGeom, True)]
|
||||
|
||||
geoScan = list()
|
||||
if obj.ProfileEdges != 'Only':
|
||||
if self.showDebugObjects:
|
||||
F = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpCutArea')
|
||||
F.Shape = cmpdShp
|
||||
F.purgeTouched()
|
||||
self.tempGroup.addObject(F)
|
||||
self.showDebugObject(cmpdShp, 'CutArea')
|
||||
# get internal path geometry and perform OCL scan with that geometry
|
||||
PGG = PathSurfaceSupport.PathGeometryGenerator(obj, cmpdShp, obj.CutPattern)
|
||||
if self.showDebugObjects:
|
||||
@@ -779,12 +775,14 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
self.tmpCOM = PGG.getCenterOfPattern()
|
||||
pathGeom = PGG.generatePathGeometry()
|
||||
if pathGeom is False:
|
||||
PathLog.error('No path geometry returned.')
|
||||
msg = translate('PathSurface', 'No clearing shape returned.')
|
||||
PathLog.error(msg)
|
||||
return list()
|
||||
if obj.CutPattern == 'Offset':
|
||||
useGeom = self._offsetFacesToPointData(obj, pathGeom, profile=False)
|
||||
if useGeom is False:
|
||||
PathLog.error('No profile geometry returned.')
|
||||
msg = translate('PathSurface', 'No clearing path geometry returned.')
|
||||
PathLog.error(msg)
|
||||
return list()
|
||||
geoScan = [self._planarPerformOclScan(obj, pdc, useGeom, True)]
|
||||
else:
|
||||
@@ -803,7 +801,8 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
SCANDATA.extend(profScan)
|
||||
|
||||
if len(SCANDATA) == 0:
|
||||
PathLog.error('No scan data to convert to Gcode.')
|
||||
msg = translate('PathSuface', 'No scan data to convert to Gcode.')
|
||||
PathLog.error(msg)
|
||||
return list()
|
||||
|
||||
# Apply depth offset
|
||||
@@ -1173,7 +1172,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
|
||||
# Manage step over transition and CircularZigZag direction
|
||||
if so > 0:
|
||||
# PathLog.debug(' stepover index: {}'.format(so))
|
||||
# Control ZigZag direction
|
||||
if obj.CutPattern == 'CircularZigZag':
|
||||
if odd is True:
|
||||
@@ -1195,7 +1193,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
for i in range(0, lenAdjPrts):
|
||||
prt = ADJPRTS[i]
|
||||
lenPrt = len(prt)
|
||||
# PathLog.debug(' adj parts index - lenPrt: {} - {}'.format(i, lenPrt))
|
||||
if prt == 'BRK' and prtsHasCmds is True:
|
||||
nxtStart = ADJPRTS[i + 1][0]
|
||||
minSTH = self._getMinSafeTravelHeight(safePDC, last, nxtStart, minDep=None) # Check safe travel height against fullSTL
|
||||
@@ -2108,6 +2105,13 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
zMax = minDep
|
||||
return zMax
|
||||
|
||||
def showDebugObject(self, objShape, objName):
|
||||
if self.showDebugObjects:
|
||||
do = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmp_' + objName)
|
||||
do.Shape = objShape
|
||||
do.purgeTouched()
|
||||
self.tempGroup.addObject(do)
|
||||
|
||||
|
||||
def SetupProperties():
|
||||
''' SetupProperties() ... Return list of properties required for operation.'''
|
||||
|
||||
@@ -42,6 +42,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
def initPage(self, obj):
|
||||
self.setTitle("3D Surface")
|
||||
# self.updateVisibility()
|
||||
# retrieve property enumerations
|
||||
self.propEnums = PathSurface.ObjectSurface.opPropertyEnumerations(False)
|
||||
|
||||
def getForm(self):
|
||||
'''getForm() ... returns UI'''
|
||||
@@ -52,23 +54,37 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
self.updateToolController(obj, self.form.toolController)
|
||||
self.updateCoolant(obj, self.form.coolantController)
|
||||
|
||||
PathGui.updateInputField(obj, 'DepthOffset', self.form.depthOffset)
|
||||
PathGui.updateInputField(obj, 'SampleInterval', self.form.sampleInterval)
|
||||
|
||||
if obj.BoundBox != str(self.form.boundBoxSelect.currentText()):
|
||||
obj.BoundBox = str(self.form.boundBoxSelect.currentText())
|
||||
|
||||
if obj.ScanType != str(self.form.scanType.currentText()):
|
||||
obj.ScanType = str(self.form.scanType.currentText())
|
||||
|
||||
if obj.StepOver != self.form.stepOver.value():
|
||||
obj.StepOver = self.form.stepOver.value()
|
||||
|
||||
if obj.LayerMode != str(self.form.layerMode.currentText()):
|
||||
obj.LayerMode = str(self.form.layerMode.currentText())
|
||||
|
||||
if obj.CutPattern != str(self.form.cutPattern.currentText()):
|
||||
obj.CutPattern = str(self.form.cutPattern.currentText())
|
||||
"""
|
||||
The following method of getting values from the UI form
|
||||
allows for translations of combobox options in the UI.
|
||||
The requirement is that the enumeration lists must
|
||||
be in the same order in both the opPropertyEnumerations() method
|
||||
and the UI panel QComboBox list.
|
||||
Another step to ensure sychronization of the two lists is to
|
||||
populate the list dynamically in this Gui module in `initPage()`
|
||||
using the property enumerations list when loading the UI panel.
|
||||
This type of dynamic combobox population is done for the
|
||||
Tool Controller selection.
|
||||
"""
|
||||
val = self.propEnums['CutPattern'][self.form.cutPattern.currentIndex()]
|
||||
if obj.CutPattern != val:
|
||||
obj.CutPattern = val
|
||||
|
||||
val = self.propEnums['ProfileEdges'][self.form.profileEdges.currentIndex()]
|
||||
if obj.ProfileEdges != val:
|
||||
obj.ProfileEdges = val
|
||||
|
||||
if obj.AvoidLastX_Faces != self.form.avoidLastX_Faces.value():
|
||||
obj.AvoidLastX_Faces = self.form.avoidLastX_Faces.value()
|
||||
|
||||
obj.DropCutterExtraOffset.x = FreeCAD.Units.Quantity(self.form.boundBoxExtraOffsetX.text()).Value
|
||||
obj.DropCutterExtraOffset.y = FreeCAD.Units.Quantity(self.form.boundBoxExtraOffsetY.text()).Value
|
||||
@@ -77,6 +93,10 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
obj.DropCutterDir = str(self.form.dropCutterDirSelect.currentText())
|
||||
|
||||
PathGui.updateInputField(obj, 'DepthOffset', self.form.depthOffset)
|
||||
|
||||
if obj.StepOver != self.form.stepOver.value():
|
||||
obj.StepOver = self.form.stepOver.value()
|
||||
|
||||
PathGui.updateInputField(obj, 'SampleInterval', self.form.sampleInterval)
|
||||
|
||||
if obj.UseStartPoint != self.form.useStartPoint.isChecked():
|
||||
@@ -95,7 +115,23 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
self.selectInComboBox(obj.BoundBox, self.form.boundBoxSelect)
|
||||
self.selectInComboBox(obj.ScanType, self.form.scanType)
|
||||
self.selectInComboBox(obj.LayerMode, self.form.layerMode)
|
||||
self.selectInComboBox(obj.CutPattern, self.form.cutPattern)
|
||||
|
||||
"""
|
||||
The following method of setting values in the UI form
|
||||
allows for translations of combobox options in the UI.
|
||||
The requirement is that the enumeration lists must
|
||||
be in the same order in both the opPropertyEnumerations() method
|
||||
and the UI panel QComboBox list.
|
||||
The original method is commented out below.
|
||||
"""
|
||||
idx = self.propEnums['CutPattern'].index(obj.CutPattern)
|
||||
self.form.cutPattern.setCurrentIndex(idx)
|
||||
idx = self.propEnums['ProfileEdges'].index(obj.ProfileEdges)
|
||||
self.form.profileEdges.setCurrentIndex(idx)
|
||||
# self.selectInComboBox(obj.CutPattern, self.form.cutPattern)
|
||||
# self.selectInComboBox(obj.ProfileEdges, self.form.profileEdges)
|
||||
|
||||
self.form.avoidLastX_Faces.setValue(obj.AvoidLastX_Faces)
|
||||
self.form.boundBoxExtraOffsetX.setText(FreeCAD.Units.Quantity(obj.DropCutterExtraOffset.x, FreeCAD.Units.Length).UserString)
|
||||
self.form.boundBoxExtraOffsetY.setText(FreeCAD.Units.Quantity(obj.DropCutterExtraOffset.y, FreeCAD.Units.Length).UserString)
|
||||
self.selectInComboBox(obj.DropCutterDir, self.form.dropCutterDirSelect)
|
||||
@@ -129,6 +165,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
signals.append(self.form.scanType.currentIndexChanged)
|
||||
signals.append(self.form.layerMode.currentIndexChanged)
|
||||
signals.append(self.form.cutPattern.currentIndexChanged)
|
||||
signals.append(self.form.profileEdges.currentIndexChanged)
|
||||
signals.append(self.form.avoidLastX_Faces.editingFinished)
|
||||
signals.append(self.form.boundBoxExtraOffsetX.editingFinished)
|
||||
signals.append(self.form.boundBoxExtraOffsetY.editingFinished)
|
||||
signals.append(self.form.dropCutterDirSelect.currentIndexChanged)
|
||||
|
||||
@@ -91,12 +91,14 @@ class PathGeometryGenerator:
|
||||
|
||||
if shape.BoundBox.ZMin != 0.0:
|
||||
shape.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - shape.BoundBox.ZMin))
|
||||
if shape.BoundBox.ZLength == 0.0:
|
||||
self.shape = shape
|
||||
if shape.BoundBox.ZLength > 1.0e-8:
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Shape appears to not be horizontal planar.')
|
||||
msg += ' ZMax == {} mm.\n'.format(shape.BoundBox.ZMax)
|
||||
FreeCAD.Console.PrintWarning(msg)
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning('Shape appears to not be horizontal planar. ZMax is {}.\n'.format(shape.BoundBox.ZMax))
|
||||
|
||||
self._prepareConstants()
|
||||
self.shape = shape
|
||||
self._prepareConstants()
|
||||
|
||||
def _prepareConstants(self):
|
||||
# Apply drop cutter extra offset and set the max and min XY area of the operation
|
||||
@@ -118,8 +120,11 @@ class PathGeometryGenerator:
|
||||
fCnt += 1
|
||||
zeroCOM = zeroCOM.add(FreeCAD.Vector(comF.x, comF.y, 0.0).multiply(areaF))
|
||||
if fCnt == 0:
|
||||
msg = translate(self.module, 'Cannot calculate the Center Of Mass. Using Center of Boundbox instead.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Cannot calculate the Center Of Mass.')
|
||||
msg += ' ' + translate('PathSurfaceSupport',
|
||||
'Using Center of Boundbox instead.') + '\n'
|
||||
FreeCAD.Console.PrintError(msg)
|
||||
bbC = self.shape.BoundBox.Center
|
||||
zeroCOM = FreeCAD.Vector(bbC.x, bbC.y, 0.0)
|
||||
else:
|
||||
@@ -156,11 +161,9 @@ class PathGeometryGenerator:
|
||||
'''generatePathGeometry()...
|
||||
Call this function to obtain the path geometry shape, generated by this class.'''
|
||||
if self.pattern == 'None':
|
||||
# FreeCAD.Console.PrintWarning('PGG: No pattern set.\n')
|
||||
return False
|
||||
|
||||
if self.shape is None:
|
||||
# FreeCAD.Console.PrintWarning('PGG: No shape set.\n')
|
||||
return False
|
||||
|
||||
cmd = 'self._' + self.pattern + '()'
|
||||
@@ -408,7 +411,6 @@ class PathGeometryGenerator:
|
||||
while cont:
|
||||
ofstArea = self._getFaceOffset(shape, ofst)
|
||||
if not ofstArea:
|
||||
# FreeCAD.Console.PrintWarning('PGG: No offset clearing area returned.\n')
|
||||
cont = False
|
||||
True if cont else False # cont used for LGTM
|
||||
break
|
||||
@@ -426,9 +428,8 @@ class PathGeometryGenerator:
|
||||
'''_getFaceOffset(shape, offset) ... internal function.
|
||||
Original _buildPathArea() version copied from PathAreaOp.py module. This version is modified.
|
||||
Adjustments made based on notes by @sliptonic at this webpage: https://github.com/sliptonic/FreeCAD/wiki/PathArea-notes.'''
|
||||
PathLog.debug('_getFaceOffset()')
|
||||
|
||||
areaParams = {}
|
||||
|
||||
areaParams['Offset'] = offset
|
||||
areaParams['Fill'] = 1 # 1
|
||||
areaParams['Coplanar'] = 0
|
||||
@@ -439,7 +440,6 @@ class PathGeometryGenerator:
|
||||
areaParams['Project'] = True
|
||||
|
||||
area = Path.Area() # Create instance of Area() class object
|
||||
# area.setPlane(PathUtils.makeWorkplane(shape)) # Set working plane
|
||||
area.setPlane(PathUtils.makeWorkplane(self.wpc)) # Set working plane to normal at Z=1
|
||||
area.add(shape)
|
||||
area.setParams(**areaParams) # set parameters
|
||||
@@ -475,7 +475,10 @@ class ProcessSelectedFaces:
|
||||
self.module = None
|
||||
self.radius = None
|
||||
self.depthParams = None
|
||||
self.msgNoFaces = translate(self.module, 'Face selection is unavailable for Rotational scans. Ignoring selected faces.') + '\n'
|
||||
self.msgNoFaces = translate('PathSurfaceSupport',
|
||||
'Face selection is unavailable for Rotational scans.') + '\n'
|
||||
self.msgNoFaces += ' ' + translate('PathSurfaceSupport',
|
||||
'Ignoring selected faces.') + '\n'
|
||||
self.JOB = JOB
|
||||
self.obj = obj
|
||||
self.profileEdges = 'None'
|
||||
@@ -558,9 +561,8 @@ class ProcessSelectedFaces:
|
||||
self.modelSTLs[m] = True
|
||||
|
||||
# Process each model base, as a whole, as needed
|
||||
# PathLog.debug(' -Pre-processing all models in Job.')
|
||||
for m in range(0, lenGRP):
|
||||
if fShapes[m] is False:
|
||||
if self.modelSTLs[m] and not fShapes[m]:
|
||||
PathLog.debug(' -Pre-processing {} as a whole.'.format(GRP[m].Label))
|
||||
if self.obj.BoundBox == 'BaseBoundBox':
|
||||
base = GRP[m]
|
||||
@@ -569,7 +571,9 @@ class ProcessSelectedFaces:
|
||||
|
||||
pPEB = self._preProcessEntireBase(base, m)
|
||||
if pPEB is False:
|
||||
FreeCAD.Console.PrintError(' -Failed to pre-process base as a whole.\n')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Failed to pre-process base as a whole.') + '\n'
|
||||
FreeCAD.Console.PrintError(msg)
|
||||
else:
|
||||
(fcShp, prflShp) = pPEB
|
||||
if fcShp is not False:
|
||||
@@ -646,11 +650,13 @@ class ProcessSelectedFaces:
|
||||
if F[m] is False:
|
||||
F[m] = list()
|
||||
F[m].append((shape, faceIdx))
|
||||
PathLog.debug('.. Cutting {}'.format(sub))
|
||||
hasFace = True
|
||||
else:
|
||||
if V[m] is False:
|
||||
V[m] = list()
|
||||
V[m].append((shape, faceIdx))
|
||||
PathLog.debug('.. Avoiding {}'.format(sub))
|
||||
hasVoid = True
|
||||
return (hasFace, hasVoid)
|
||||
|
||||
@@ -678,14 +684,16 @@ class ProcessSelectedFaces:
|
||||
|
||||
PathLog.debug('Attempting to get cross-section of collective faces.')
|
||||
if len(outFCS) == 0:
|
||||
msg = translate('PathSurfaceSupport', 'Cannot process selected faces. Check horizontal surface exposure.')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Cannot process selected faces. Check horizontal surface exposure.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
cont = False
|
||||
else:
|
||||
cfsL = Part.makeCompound(outFCS)
|
||||
|
||||
# Handle profile edges request
|
||||
if cont is True and self.profileEdges != 'None':
|
||||
if cont and self.profileEdges != 'None':
|
||||
PathLog.debug('.. include Profile Edge')
|
||||
ofstVal = self._calculateOffsetValue(isHole)
|
||||
psOfst = extractFaceOffset(cfsL, ofstVal, self.wpc)
|
||||
if psOfst is not False:
|
||||
@@ -694,7 +702,6 @@ class ProcessSelectedFaces:
|
||||
mFS = True
|
||||
cont = False
|
||||
else:
|
||||
# FreeCAD.Console.PrintError(' -Failed to create profile geometry for selected faces.\n')
|
||||
cont = False
|
||||
|
||||
if cont:
|
||||
@@ -706,8 +713,10 @@ class ProcessSelectedFaces:
|
||||
|
||||
ofstVal = self._calculateOffsetValue(isHole)
|
||||
faceOfstShp = extractFaceOffset(cfsL, ofstVal, self.wpc)
|
||||
if faceOfstShp is False:
|
||||
FreeCAD.Console.PrintError(' -Failed to create offset face.\n')
|
||||
if not faceOfstShp:
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Failed to create offset face.') + '\n'
|
||||
FreeCAD.Console.PrintError(msg)
|
||||
cont = False
|
||||
|
||||
if cont:
|
||||
@@ -764,7 +773,6 @@ class ProcessSelectedFaces:
|
||||
mFS.append(True)
|
||||
cont = False
|
||||
else:
|
||||
# PathLog.error(' -Failed to create profile geometry for Face{}.'.format(fNum))
|
||||
cont = False
|
||||
|
||||
if cont:
|
||||
@@ -825,7 +833,6 @@ class ProcessSelectedFaces:
|
||||
avoid = Part.makeCompound(outFCS)
|
||||
|
||||
if self.showDebugObjects:
|
||||
PathLog.debug('*** tmpAvoidArea')
|
||||
P = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpVoidEnvelope')
|
||||
P.Shape = avoid
|
||||
P.purgeTouched()
|
||||
@@ -833,7 +840,6 @@ class ProcessSelectedFaces:
|
||||
|
||||
if cont:
|
||||
if self.showDebugObjects:
|
||||
PathLog.debug('*** tmpVoidCompound')
|
||||
P = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpVoidCompound')
|
||||
P.Shape = avoid
|
||||
P.purgeTouched()
|
||||
@@ -841,13 +847,15 @@ class ProcessSelectedFaces:
|
||||
ofstVal = self._calculateOffsetValue(isHole, isVoid=True)
|
||||
avdOfstShp = extractFaceOffset(avoid, ofstVal, self.wpc)
|
||||
if avdOfstShp is False:
|
||||
FreeCAD.Console.PrintError('Failed to create collective offset avoid face.\n')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Failed to create collective offset avoid face.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
cont = False
|
||||
|
||||
if cont:
|
||||
avdShp = avdOfstShp
|
||||
|
||||
if self.obj.AvoidLastX_InternalFeatures is False and len(intFEAT) > 0:
|
||||
if not self.obj.AvoidLastX_InternalFeatures and len(intFEAT) > 0:
|
||||
if len(intFEAT) > 1:
|
||||
ifc = Part.makeCompound(intFEAT)
|
||||
else:
|
||||
@@ -855,7 +863,9 @@ class ProcessSelectedFaces:
|
||||
ofstVal = self._calculateOffsetValue(isHole=True)
|
||||
ifOfstShp = extractFaceOffset(ifc, ofstVal, self.wpc)
|
||||
if ifOfstShp is False:
|
||||
FreeCAD.Console.PrintError('Failed to create collective offset avoid internal features.\n')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Failed to create collective offset avoid internal features.') + '\n'
|
||||
FreeCAD.Console.PrintError(msg)
|
||||
else:
|
||||
avdShp = avdOfstShp.cut(ifOfstShp)
|
||||
|
||||
@@ -891,10 +901,10 @@ class ProcessSelectedFaces:
|
||||
if csFaceShape is False:
|
||||
csFaceShape = getSliceFromEnvelope(baseEnv)
|
||||
if csFaceShape is False:
|
||||
PathLog.error('Failed to slice baseEnv shape.')
|
||||
PathLog.debug('Failed to slice baseEnv shape.')
|
||||
cont = False
|
||||
|
||||
if cont is True and self.profileEdges != 'None':
|
||||
if cont and self.profileEdges != 'None':
|
||||
PathLog.debug(' -Attempting profile geometry for model base.')
|
||||
ofstVal = self._calculateOffsetValue(isHole)
|
||||
psOfst = extractFaceOffset(csFaceShape, ofstVal, self.wpc)
|
||||
@@ -903,14 +913,13 @@ class ProcessSelectedFaces:
|
||||
return (True, psOfst)
|
||||
prflShp = psOfst
|
||||
else:
|
||||
# FreeCAD.Console.PrintError(' -Failed to create profile geometry.\n')
|
||||
cont = False
|
||||
|
||||
if cont:
|
||||
ofstVal = self._calculateOffsetValue(isHole)
|
||||
faceOffsetShape = extractFaceOffset(csFaceShape, ofstVal, self.wpc)
|
||||
if faceOffsetShape is False:
|
||||
PathLog.error('extractFaceOffset() failed for entire base.')
|
||||
PathLog.debug('extractFaceOffset() failed for entire base.')
|
||||
else:
|
||||
faceOffsetShape.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - faceOffsetShape.BoundBox.ZMin))
|
||||
return (faceOffsetShape, prflShp)
|
||||
@@ -1024,7 +1033,6 @@ def getProjectedFace(tempGroup, wire):
|
||||
else:
|
||||
pWire = Part.Wire(prj.Shape.Edges)
|
||||
if pWire.isClosed() is False:
|
||||
# PathLog.debug(' -pWire.isClosed() is False')
|
||||
return False
|
||||
slc = Part.Face(pWire)
|
||||
slc.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - slc.BoundBox.ZMin))
|
||||
@@ -1069,7 +1077,7 @@ def getShapeEnvelope(shape):
|
||||
try:
|
||||
env = PathUtils.getEnvelope(partshape=shape, depthparams=dep_par) # Produces .Shape
|
||||
except Exception as ee:
|
||||
FreeCAD.Console.PrintError('try: PathUtils.getEnvelope() failed.\n' + str(ee) + '\n')
|
||||
FreeCAD.Console.PrintError('PathUtils.getEnvelope() failed.\n' + str(ee) + '\n')
|
||||
return False
|
||||
else:
|
||||
return env
|
||||
@@ -1196,7 +1204,9 @@ def _makeSafeSTL(self, JOB, obj, mdlIdx, faceShapes, voidShapes, ocl):
|
||||
adjStckWst = stckWst
|
||||
fuseShapes.append(adjStckWst)
|
||||
else:
|
||||
PathLog.warning('Path transitions might not avoid the model. Verify paths.')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Path transitions might not avoid the model. Verify paths.')
|
||||
FreeCAD.Console.PrintWarning(msg + '\n')
|
||||
else:
|
||||
# If boundbox is Job.Stock, add hidden pad under stock as base plate
|
||||
toolDiam = self.cutter.getDiameter()
|
||||
@@ -1319,7 +1329,6 @@ def pathGeomToLinesPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps
|
||||
closedGap = True
|
||||
True if closedGap else False # used closedGap for LGTM
|
||||
else:
|
||||
# PathLog.debug('---- Gap: {} mm'.format(gap))
|
||||
gap = round(gap, 6)
|
||||
if gap < gaps[0]:
|
||||
gaps.insert(0, gap)
|
||||
@@ -1348,9 +1357,9 @@ def pathGeomToLinesPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps
|
||||
|
||||
isEven = lnCnt % 2
|
||||
if isEven == 0:
|
||||
PathLog.debug('Line count is ODD.')
|
||||
PathLog.debug('Line count is ODD: {}.'.format(lnCnt))
|
||||
else:
|
||||
PathLog.debug('Line count is even.')
|
||||
PathLog.debug('Line count is even: {}.'.format(lnCnt))
|
||||
|
||||
return LINES
|
||||
|
||||
@@ -1432,9 +1441,9 @@ def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gap
|
||||
# Fix directional issue with LAST line when line count is even
|
||||
isEven = lnCnt % 2
|
||||
if isEven == 0: # Changed to != with 90 degree CutPatternAngle
|
||||
PathLog.debug('Line count is even.')
|
||||
PathLog.debug('Line count is even: {}.'.format(lnCnt))
|
||||
else:
|
||||
PathLog.debug('Line count is ODD.')
|
||||
PathLog.debug('Line count is ODD: {}.'.format(lnCnt))
|
||||
dirFlg = -1 * dirFlg
|
||||
if not obj.CutPatternReversed:
|
||||
if cutClimb:
|
||||
@@ -1652,7 +1661,6 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g
|
||||
arc = (vA, arc[1], vC)
|
||||
closedGap = True
|
||||
else:
|
||||
# PathLog.debug('---- Gap: {} mm'.format(gap))
|
||||
gap = round(gap, 6)
|
||||
if gap < gaps[0]:
|
||||
gaps.insert(0, gap)
|
||||
@@ -1838,7 +1846,9 @@ class FindUnifiedRegions:
|
||||
tfBB_Area = tfBB.XLength * tfBB.YLength
|
||||
# self._showShape(topFace, 'topFaceAlt_2_{}'.format(fNum))
|
||||
if tfBB_Area < (fBB_Area * 0.9):
|
||||
FreeCAD.Console.PrintError('Faild to extract processing region for Face{}.\n'.format(fNum))
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'Faild to extract processing region for Face')
|
||||
FreeCAD.Console.PrintError(msg + '{}.\n'.format(fNum))
|
||||
cont = False
|
||||
|
||||
if cont:
|
||||
@@ -2104,7 +2114,7 @@ class FindUnifiedRegions:
|
||||
remList.append(s)
|
||||
break
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning(' - No common area.\n')
|
||||
PathLog.debug(' - No common area.\n')
|
||||
|
||||
remList.sort(reverse=True)
|
||||
for ri in remList:
|
||||
@@ -2214,29 +2224,41 @@ class FindUnifiedRegions:
|
||||
of tuples (faceShape, faceIndex) received at instantiation of the class object.'''
|
||||
self.INTERNALS = list()
|
||||
if len(self.FACES) == 0:
|
||||
FreeCAD.Console.PrintError('No (faceShp, faceIdx) tuples received at instantiation of class.')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'No FACE data tuples received at instantiation of class.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
return []
|
||||
|
||||
self._extractTopFaces()
|
||||
lenFaces = len(self.topFaces)
|
||||
PathLog.debug('getUnifiedRegions() lenFaces: {}.'.format(lenFaces))
|
||||
if lenFaces == 0:
|
||||
return []
|
||||
|
||||
# if single topFace, return it
|
||||
if lenFaces == 1:
|
||||
topFace = self.topFaces[0][0]
|
||||
# self._showShape(topFace, 'TopFace')
|
||||
self._showShape(topFace, 'TopFace')
|
||||
# prepare inner wires as faces for internal features
|
||||
lenWrs = len(topFace.Wires)
|
||||
if lenWrs > 1:
|
||||
for w in range(1, lenWrs):
|
||||
self.INTERNALS.append(Part.Face(topFace.Wires[w]))
|
||||
# prepare outer wire as face for return value in list
|
||||
if hasattr(topFace, 'OuterWire'):
|
||||
ow = topFace.OuterWire
|
||||
else:
|
||||
ow = topFace.Wires[0]
|
||||
face = Part.Face(ow)
|
||||
# Any internal wires need to be flattened
|
||||
# before appending to self.INTERNALS
|
||||
# A problem exists that inner wires are not all recognized as wires.
|
||||
# Some are single circular edges.
|
||||
# Face.Edges.__len_() - Face.OuterWire.Edges.__len__() = edges for inner wire(s)
|
||||
|
||||
# extWire = getExtrudedShape(wr)
|
||||
# wCS = getCrossSection(extWire)
|
||||
# wCS.translate(FreeCAD.Vector(0.0, 0.0, wr.BoundBox.ZMin))
|
||||
wr = topFace.Wires[w]
|
||||
self.INTERNALS.append(Part.Face(wr))
|
||||
# Flatten face and extract outer wire, then convert to face
|
||||
extWire = getExtrudedShape(topFace)
|
||||
wCS = getCrossSection(extWire)
|
||||
wCS.translate(FreeCAD.Vector(0.0, 0.0, topFace.BoundBox.ZMin))
|
||||
face = Part.Face(wCS)
|
||||
return [face]
|
||||
|
||||
# process multiple top faces, unifying if possible
|
||||
@@ -2254,11 +2276,8 @@ class FindUnifiedRegions:
|
||||
return [topFace for (topFace, fcIdx) in self.topFaces]
|
||||
else:
|
||||
# Delete shared edges from edgeData list
|
||||
# FreeCAD.Console.PrintWarning('self.sharedEdgeIdxs: {}\n'.format(self.sharedEdgeIdxs))
|
||||
self.sharedEdgeIdxs.sort(reverse=True)
|
||||
for se in self.sharedEdgeIdxs:
|
||||
# seShp = self.edgeData[se][2]
|
||||
# self._showShape(seShp, 'SharedEdge')
|
||||
self.edgeData.pop(se)
|
||||
|
||||
self._extractWiresFromEdges()
|
||||
@@ -2274,6 +2293,8 @@ class FindUnifiedRegions:
|
||||
after calling getUnifiedRegions().'''
|
||||
if self.INTERNALS:
|
||||
return self.INTERNALS
|
||||
FreeCAD.Console.PrintError('getUnifiedRegions() must be called before getInternalFeatures().\n')
|
||||
msg = translate('PathSurfaceSupport',
|
||||
'getUnifiedRegions() must be called before getInternalFeatures().')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
return False
|
||||
# Eclass
|
||||
|
||||
@@ -191,9 +191,9 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
'Algorithm': ['OCL Dropcutter', 'Experimental'],
|
||||
'BoundBox': ['BaseBoundBox', 'Stock'],
|
||||
'PatternCenterAt': ['CenterOfMass', 'CenterOfBoundBox', 'XminYmin', 'Custom'],
|
||||
'ClearLastLayer': ['Off', 'Line', 'Circular', 'CircularZigZag', 'Offset', 'Spiral', 'ZigZag'],
|
||||
'ClearLastLayer': ['Off', 'Circular', 'CircularZigZag', 'Line', 'Offset', 'Spiral', 'ZigZag'],
|
||||
'CutMode': ['Conventional', 'Climb'],
|
||||
'CutPattern': ['None', 'Line', 'Circular', 'CircularZigZag', 'Offset', 'Spiral', 'ZigZag'], # Additional goals ['Offset', 'Spiral', 'ZigZagOffset', 'Grid', 'Triangle']
|
||||
'CutPattern': ['None', 'Circular', 'CircularZigZag', 'Line', 'Offset', 'Spiral', 'ZigZag'], # Additional goals ['Offset', 'Spiral', 'ZigZagOffset', 'Grid', 'Triangle']
|
||||
'HandleMultipleFeatures': ['Collectively', 'Individually'],
|
||||
'LayerMode': ['Single-pass', 'Multi-pass'],
|
||||
}
|
||||
@@ -488,7 +488,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
self.opApplyPropertyLimits(obj)
|
||||
|
||||
# Create temporary group for temporary objects, removing existing
|
||||
# if self.showDebugObjects is True:
|
||||
tempGroupName = 'tempPathWaterlineGroup'
|
||||
if FCAD.getObject(tempGroupName):
|
||||
for to in FCAD.getObject(tempGroupName).Group:
|
||||
@@ -576,7 +575,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
self.modelSTLs = PSF.modelSTLs
|
||||
self.profileShapes = PSF.profileShapes
|
||||
|
||||
|
||||
for m in range(0, len(JOB.Model.Group)):
|
||||
# Create OCL.stl model objects
|
||||
if obj.Algorithm == 'OCL Dropcutter':
|
||||
@@ -662,7 +660,8 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
del self.midDep
|
||||
|
||||
execTime = time.time() - startTime
|
||||
PathLog.info('Operation time: {} sec.'.format(execTime))
|
||||
msg = translate('PathWaterline', 'operation time is')
|
||||
PathLog.info('Waterline ' + msg + ' {} sec.'.format(execTime))
|
||||
|
||||
return True
|
||||
|
||||
@@ -1238,11 +1237,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
bbFace = PathSurfaceSupport.getCrossSection(baseEnv) # returned at Z=0.0
|
||||
|
||||
trimFace = borderFace.cut(bbFace)
|
||||
if self.showDebugObjects is True:
|
||||
TF = FreeCAD.ActiveDocument.addObject('Part::Feature', 'trimFace')
|
||||
TF.Shape = trimFace
|
||||
TF.purgeTouched()
|
||||
self.tempGroup.addObject(TF)
|
||||
self.showDebugObject(trimFace, 'TrimFace')
|
||||
|
||||
# Cycle through layer depths
|
||||
CUTAREAS = self._getCutAreas(base.Shape, depthparams, bbFace, trimFace, borderFace)
|
||||
@@ -1267,11 +1262,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
if area.Area > 0.0:
|
||||
cont = True
|
||||
caWireCnt = len(area.Wires) - 1 # first wire is boundFace wire
|
||||
if self.showDebugObjects:
|
||||
CA = FreeCAD.ActiveDocument.addObject('Part::Feature', 'cutArea_{}'.format(caCnt))
|
||||
CA.Shape = area
|
||||
CA.purgeTouched()
|
||||
self.tempGroup.addObject(CA)
|
||||
self.showDebugObject(area, 'CutArea_{}'.format(caCnt))
|
||||
else:
|
||||
data = FreeCAD.Units.Quantity(csHght, FreeCAD.Units.Length).UserString
|
||||
PathLog.debug('Cut area at {} is zero.'.format(data))
|
||||
@@ -1281,11 +1272,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
area.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - area.BoundBox.ZMin))
|
||||
activeArea = area.cut(trimFace)
|
||||
activeAreaWireCnt = len(activeArea.Wires) # first wire is boundFace wire
|
||||
if self.showDebugObjects:
|
||||
CA = FreeCAD.ActiveDocument.addObject('Part::Feature', 'activeArea_{}'.format(caCnt))
|
||||
CA.Shape = activeArea
|
||||
CA.purgeTouched()
|
||||
self.tempGroup.addObject(CA)
|
||||
self.showDebugObject(activeArea, 'ActiveArea_{}'.format(caCnt))
|
||||
ofstArea = PathSurfaceSupport.extractFaceOffset(activeArea, ofst, self.wpc, makeComp=False)
|
||||
if not ofstArea:
|
||||
data = FreeCAD.Units.Quantity(csHght, FreeCAD.Units.Length).UserString
|
||||
@@ -1294,20 +1281,21 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
|
||||
if cont:
|
||||
# Identify solid areas in the offset data
|
||||
ofstSolidFacesList = self._getSolidAreasFromPlanarFaces(ofstArea)
|
||||
if ofstSolidFacesList:
|
||||
clearArea = Part.makeCompound(ofstSolidFacesList)
|
||||
if self.showDebugObjects is True:
|
||||
CA = FreeCAD.ActiveDocument.addObject('Part::Feature', 'clearArea_{}'.format(caCnt))
|
||||
CA.Shape = clearArea
|
||||
CA.purgeTouched()
|
||||
self.tempGroup.addObject(CA)
|
||||
if obj.CutPattern == 'Offset' or obj.CutPattern == 'None':
|
||||
ofstSolidFacesList = self._getSolidAreasFromPlanarFaces(ofstArea)
|
||||
if ofstSolidFacesList:
|
||||
clearArea = Part.makeCompound(ofstSolidFacesList)
|
||||
self.showDebugObject(clearArea, 'ClearArea_{}'.format(caCnt))
|
||||
else:
|
||||
cont = False
|
||||
data = FreeCAD.Units.Quantity(csHght, FreeCAD.Units.Length).UserString
|
||||
PathLog.error('Could not determine solid faces at {}.'.format(data))
|
||||
else:
|
||||
cont = False
|
||||
data = FreeCAD.Units.Quantity(csHght, FreeCAD.Units.Length).UserString
|
||||
PathLog.error('Could not determine solid faces at {}.'.format(data))
|
||||
clearArea = activeArea
|
||||
|
||||
if cont:
|
||||
data = FreeCAD.Units.Quantity(csHght, FreeCAD.Units.Length).UserString
|
||||
PathLog.debug('... Clearning area at {}.'.format(data))
|
||||
# Make waterline path for current CUTAREA depth (csHght)
|
||||
commands.extend(self._wiresToWaterlinePath(obj, clearArea, csHght))
|
||||
clearArea.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - clearArea.BoundBox.ZMin))
|
||||
@@ -1325,7 +1313,8 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
commands.extend(self._makeCutPatternLayerPaths(JOB, obj, clearArea, csHght, cutPattern))
|
||||
# Efor
|
||||
|
||||
if clearLastLayer:
|
||||
if clearLastLayer and obj.ClearLastLayer != 'Off':
|
||||
PathLog.debug('... Clearning last layer')
|
||||
(clrLyr, cLL) = self._clearLayer(obj, 1, 1, False)
|
||||
lastClearArea.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - lastClearArea.BoundBox.ZMin))
|
||||
if clrLyr == 'Offset':
|
||||
@@ -1333,7 +1322,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
elif clrLyr:
|
||||
commands.extend(self._makeCutPatternLayerPaths(JOB, obj, lastClearArea, lastCsHght, obj.ClearLastLayer))
|
||||
|
||||
PathLog.info("Waterline: All layer scans combined took " + str(time.time() - t_begin) + " s")
|
||||
return commands
|
||||
|
||||
def _getCutAreas(self, shape, depthparams, bbFace, trimFace, borderFace):
|
||||
@@ -1363,13 +1351,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
|
||||
if useFaces:
|
||||
compAdjFaces = Part.makeCompound(useFaces)
|
||||
|
||||
if self.showDebugObjects is True:
|
||||
CA = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpSolids_{}'.format(dp + 1))
|
||||
CA.Shape = compAdjFaces
|
||||
CA.purgeTouched()
|
||||
self.tempGroup.addObject(CA)
|
||||
|
||||
self.showDebugObject(compAdjFaces, 'Solids_{}'.format(dp + 1))
|
||||
if isFirst:
|
||||
allPrevComp = compAdjFaces
|
||||
cutArea = borderFace.cut(compAdjFaces)
|
||||
@@ -1395,11 +1377,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
|
||||
# Translate path geometry to layer height
|
||||
ofstPlnrShp.translate(FreeCAD.Vector(0.0, 0.0, csHght - ofstPlnrShp.BoundBox.ZMin))
|
||||
if self.showDebugObjects is True:
|
||||
OA = FreeCAD.ActiveDocument.addObject('Part::Feature', 'waterlinePathArea_{}'.format(round(csHght, 2)))
|
||||
OA.Shape = ofstPlnrShp
|
||||
OA.purgeTouched()
|
||||
self.tempGroup.addObject(OA)
|
||||
self.showDebugObject(ofstPlnrShp, 'WaterlinePathArea_{}'.format(round(csHght, 2)))
|
||||
|
||||
commands.append(Path.Command('N (Cut Area {}.)'.format(round(csHght, 2))))
|
||||
start = 1
|
||||
@@ -1442,11 +1420,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
return commands
|
||||
pathGeom.translate(FreeCAD.Vector(0.0, 0.0, csHght - pathGeom.BoundBox.ZMin))
|
||||
|
||||
if self.showDebugObjects is True:
|
||||
OA = FreeCAD.ActiveDocument.addObject('Part::Feature', 'pathGeom_{}'.format(round(csHght, 2)))
|
||||
OA.Shape = pathGeom
|
||||
OA.purgeTouched()
|
||||
self.tempGroup.addObject(OA)
|
||||
self.showDebugObject(pathGeom, 'PathGeom_{}'.format(round(csHght, 2)))
|
||||
|
||||
if cutPattern == 'Line':
|
||||
pntSet = PathSurfaceSupport.pathGeomToLinesPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps)
|
||||
@@ -1481,6 +1455,8 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
if cnt == 0:
|
||||
ofst = 0.0 - self.cutOut
|
||||
cnt += 1
|
||||
PathLog.debug(' -Offset path count: {} at height: {}'.format(cnt, round(csHght, 2)))
|
||||
|
||||
return cmds
|
||||
|
||||
def _clearGeomToPaths(self, JOB, obj, safePDC, stpOVRS, cutPattern):
|
||||
@@ -1855,6 +1831,13 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
PathLog.warning("Defaulting cutter to standard end mill.")
|
||||
return ocl.CylCutter(diam_1, (CEH + lenOfst))
|
||||
|
||||
def showDebugObject(self, objShape, objName):
|
||||
if self.showDebugObjects:
|
||||
do = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmp_' + objName)
|
||||
do.Shape = objShape
|
||||
do.purgeTouched()
|
||||
self.tempGroup.addObject(do)
|
||||
|
||||
|
||||
def SetupProperties():
|
||||
''' SetupProperties() ... Return list of properties required for operation.'''
|
||||
|
||||
Reference in New Issue
Block a user