surface and waterline translation

This commit is contained in:
sliptonic
2022-01-25 15:24:49 -06:00
parent bb1cde0c3a
commit 69e7a2e9fd
8 changed files with 346 additions and 316 deletions

View File

@@ -101,7 +101,7 @@ class ObjectSurface(PathOp.ObjectOp):
def initOpProperties(self, obj, warn=False):
"""initOpProperties(obj) ... create operation specific properties"""
self.addNewProps = list()
self.addNewProps = []
for (prtyp, nm, grp, tt) in self.opPropertyDefinitions():
if not hasattr(obj, nm):
@@ -453,19 +453,19 @@ class ObjectSurface(PathOp.ObjectOp):
# Enumeration lists for App::PropertyEnumeration properties
enums = {
"BoundBox": [
(translate("Path_Surface", "Outside"), "Outside"),
(translate("Path_Surface", "Inside"), "Inside"),
], # this is the direction that the profile runs
(translate("Path_Surface", "BaseBoundBox"), "BaseBoundBox"),
(translate("Path_Surface", "Stock"), "Stock"),
],
"PatternCenterAt": [
(translate("Path_Surface", "CenterOfMass"), "CenterOfMass"),
(translate("Path_Surface", "CenterOfBoundBox"), "CenterOfBoundBox"),
(translate("Path_Surface", "XminYmin"), "XminYmin"),
(translate("Path_Surface", "Custom"), "Custom"),
], # side of profile that cutter is on in relation to direction of profile
],
"CutMode": [
(translate("Path_Surface", "Conventional"), "Conventional"),
(translate("Path_Surface", "Climb"), "Climb"),
], # side of profile that cutter is on in relation to direction of profile
],
"CutPattern": [
(translate("Path_Surface", "Circular"), "Circular"),
(translate("Path_Surface", "CircularZigZag"), "CircularZigZag"),
@@ -473,76 +473,46 @@ class ObjectSurface(PathOp.ObjectOp):
(translate("Path_Surface", "Offset"), "Offset"),
(translate("Path_Surface", "Spiral"), "Spiral"),
(translate("Path_Surface", "ZigZag"), "ZigZag"),
], # side of profile that cutter is on in relation to direction of profile
],
"DropCutterDir": [
(translate("Path_Surface", "X"), "X"),
(translate("Path_Surface", "Y"), "Y"),
], # side of profile that cutter is on in relation to direction of profile
],
"HandleMultipleFeatures": [
(translate("Path_Surface", "Collectively"), "Collectively"),
(translate("Path_Surface", "Individually"), "Individually"),
], # side of profile that cutter is on in relation to direction of profile
],
"LayerMode": [
(translate("Path_Surface", "Single-pass"), "Single-pass"),
(translate("Path_Surface", "Multi-pass"), "Multi-pass"),
], # side of profile that cutter is on in relation to direction of profile
],
"ProfileEdges": [
(translate("Path_Surface", "None"), "None"),
(translate("Path_Surface", "Only"), "Only"),
(translate("Path_Surface", "First"), "First"),
(translate("Path_Surface", "Last"), "Last"),
], # side of profile that cutter is on in relation to direction of profile
],
"RotationAxis": [
(translate("Path_Surface", "X"), "X"),
(translate("Path_Surface", "Y"), "Y"),
], # side of profile that cutter is on in relation to direction of profile
],
"ScanType": [
(translate("Path_Surface", "Planar"), "Planar"),
(translate("Path_Surface", "Rotational"), "Rotational"),
], # side of profile that cutter is on in relation to direction of profile
],
}
if dataType == "raw":
return enums
data = list()
data = []
idx = 0 if dataType == "translated" else 1
PathLog.debug(enums)
for k, v in enumerate(enums):
data.append((v, [tup[idx] for tup in enums[v]]))
PathLog.debug(data)
return data
# def opPropertyEnumerations(self):
# # Enumeration lists for App::PropertyEnumeration properties
# return {
# "BoundBox": ["BaseBoundBox", "Stock"],
# "PatternCenterAt": [
# "CenterOfMass",
# "CenterOfBoundBox",
# "XminYmin",
# "Custom",
# ],
# "CutMode": ["Conventional", "Climb"],
# "CutPattern": [
# "Circular",
# "CircularZigZag",
# "Line",
# "Offset",
# "Spiral",
# "ZigZag",
# ], # Additional goals ['Offset', 'ZigZagOffset', 'Grid', 'Triangle']
# "DropCutterDir": ["X", "Y"],
# "HandleMultipleFeatures": ["Collectively", "Individually"],
# "LayerMode": ["Single-pass", "Multi-pass"],
# "ProfileEdges": ["None", "Only", "First", "Last"],
# "RotationAxis": ["X", "Y"],
# "ScanType": ["Planar", "Rotational"],
# }
def opPropertyDefaults(self, obj, job):
"""opPropertyDefaults(obj, job) ... returns a dictionary of default values
for the operation's properties."""
@@ -781,22 +751,22 @@ class ObjectSurface(PathOp.ObjectOp):
"""opExecute(obj) ... process surface operation"""
PathLog.track()
self.modelSTLs = list()
self.safeSTLs = list()
self.modelTypes = list()
self.boundBoxes = list()
self.profileShapes = list()
self.collectiveShapes = list()
self.individualShapes = list()
self.avoidShapes = list()
self.modelSTLs = []
self.safeSTLs = []
self.modelTypes = []
self.boundBoxes = []
self.profileShapes = []
self.collectiveShapes = []
self.individualShapes = []
self.avoidShapes = []
self.tempGroup = None
self.CutClimb = False
self.closedGap = False
self.tmpCOM = None
self.gaps = [0.1, 0.2, 0.3]
self.cancelOperation = False
CMDS = list()
modelVisibility = list()
CMDS = []
modelVisibility = []
FCAD = FreeCAD.ActiveDocument
try:
@@ -931,26 +901,25 @@ class ObjectSurface(PathOp.ObjectOp):
# Save model visibilities for restoration
if FreeCAD.GuiUp:
for m in range(0, len(JOB.Model.Group)):
mNm = JOB.Model.Group[m].Name
for model in JOB.Model.Group:
mNm = model.Name
modelVisibility.append(
FreeCADGui.ActiveDocument.getObject(mNm).Visibility
)
# Setup STL, model type, and bound box containers for each model in Job
for m in range(0, len(JOB.Model.Group)):
M = JOB.Model.Group[m]
for model in JOB.Model.Group:
self.modelSTLs.append(False)
self.safeSTLs.append(False)
self.profileShapes.append(False)
# Set bound box
if obj.BoundBox == "BaseBoundBox":
if M.TypeId.startswith("Mesh"):
if model.TypeId.startswith("Mesh"):
self.modelTypes.append("M") # Mesh
self.boundBoxes.append(M.Mesh.BoundBox)
self.boundBoxes.append(model.Mesh.BoundBox)
else:
self.modelTypes.append("S") # Solid
self.boundBoxes.append(M.Shape.BoundBox)
self.boundBoxes.append(model.Shape.BoundBox)
elif obj.BoundBox == "Stock":
self.modelTypes.append("S") # Solid
self.boundBoxes.append(JOB.Stock.Shape.BoundBox)
@@ -971,18 +940,20 @@ class ObjectSurface(PathOp.ObjectOp):
self.modelSTLs = PSF.modelSTLs
self.profileShapes = PSF.profileShapes
for m in range(0, len(JOB.Model.Group)):
for idx, model in enumerate(JOB.Model.Group):
PathLog.debug(idx)
# Create OCL.stl model objects
PathSurfaceSupport._prepareModelSTLs(self, JOB, obj, m, ocl)
PathSurfaceSupport._prepareModelSTLs(self, JOB, obj, idx, ocl)
Mdl = JOB.Model.Group[m]
if FACES[m]:
PathLog.debug("Working on Model.Group[{}]: {}".format(m, Mdl.Label))
if m > 0:
if FACES[idx]:
PathLog.debug(
"Working on Model.Group[{}]: {}".format(idx, model.Label)
)
if idx > 0:
# Raise to clearance between models
CMDS.append(
Path.Command(
"N (Transition to base: {}.)".format(Mdl.Label)
"N (Transition to base: {}.)".format(model.Label)
)
)
CMDS.append(
@@ -993,14 +964,14 @@ class ObjectSurface(PathOp.ObjectOp):
)
# make stock-model-voidShapes STL model for avoidance detection on transitions
PathSurfaceSupport._makeSafeSTL(
self, JOB, obj, m, FACES[m], VOIDS[m], ocl
self, JOB, obj, idx, FACES[idx], VOIDS[idx], 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)
CMDS.extend(
self._processCutAreas(JOB, obj, idx, FACES[idx], VOIDS[idx])
)
else:
PathLog.debug("No data for model base: {}".format(model.Label))
# Save gcode produced
self.commandlist.extend(CMDS)
@@ -1031,7 +1002,7 @@ class ObjectSurface(PathOp.ObjectOp):
tempGroup.purgeTouched()
# Provide user feedback for gap sizes
gaps = list()
gaps = []
for g in self.gaps:
if g != self.toolDiam:
gaps.append(g)
@@ -1094,7 +1065,7 @@ class ObjectSurface(PathOp.ObjectOp):
It then calls the correct scan method depending on the ScanType property."""
PathLog.debug("_processCutAreas()")
final = list()
final = []
# Process faces Collectively or Individually
if obj.HandleMultipleFeatures == "Collectively":
@@ -1146,8 +1117,8 @@ class ObjectSurface(PathOp.ObjectOp):
It calls the correct Single or Multi-pass method as needed.
It returns the gcode for the operation."""
PathLog.debug("_processPlanarOp()")
final = list()
SCANDATA = list()
final = []
SCANDATA = []
def getTransition(two):
first = two[0][0][0] # [step][item][point]
@@ -1176,23 +1147,23 @@ class ObjectSurface(PathOp.ObjectOp):
self.cutter,
)
profScan = list()
profScan = []
if obj.ProfileEdges != "None":
prflShp = self.profileShapes[mdlIdx][fsi]
if prflShp is False:
msg = translate("PathSurface", "No profile geometry shape returned.")
PathLog.error(msg)
return list()
return []
self.showDebugObject(prflShp, "NewProfileShape")
# get offset path geometry and perform OCL scan with that geometry
pathOffsetGeom = self._offsetFacesToPointData(obj, prflShp)
if pathOffsetGeom is False:
msg = translate("PathSurface", "No profile path geometry returned.")
PathLog.error(msg)
return list()
return []
profScan = [self._planarPerformOclScan(obj, pdc, pathOffsetGeom, True)]
geoScan = list()
geoScan = []
if obj.ProfileEdges != "Only":
self.showDebugObject(cmpdShp, "CutArea")
# get internal path geometry and perform OCL scan with that geometry
@@ -1204,7 +1175,7 @@ class ObjectSurface(PathOp.ObjectOp):
if pathGeom is False:
msg = translate("PathSurface", "No clearing shape returned.")
PathLog.error(msg)
return list()
return []
if obj.CutPattern == "Offset":
useGeom = self._offsetFacesToPointData(obj, pathGeom, profile=False)
if useGeom is False:
@@ -1212,7 +1183,7 @@ class ObjectSurface(PathOp.ObjectOp):
"PathSurface", "No clearing path geometry returned."
)
PathLog.error(msg)
return list()
return []
geoScan = [self._planarPerformOclScan(obj, pdc, useGeom, True)]
else:
geoScan = self._planarPerformOclScan(obj, pdc, pathGeom, False)
@@ -1232,7 +1203,7 @@ class ObjectSurface(PathOp.ObjectOp):
if len(SCANDATA) == 0:
msg = translate("PathSurface", "No scan data to convert to Gcode.")
PathLog.error(msg)
return list()
return []
# Apply depth offset
if obj.DepthOffset.Value != 0.0:
@@ -1269,7 +1240,7 @@ class ObjectSurface(PathOp.ObjectOp):
def _offsetFacesToPointData(self, obj, subShp, profile=True):
PathLog.debug("_offsetFacesToPointData()")
offsetLists = list()
offsetLists = []
dist = obj.SampleInterval.Value / 5.0
# defl = obj.SampleInterval.Value / 5.0
@@ -1301,18 +1272,18 @@ class ObjectSurface(PathOp.ObjectOp):
Switching function for calling the appropriate path-geometry to OCL points conversion function
for the various cut patterns."""
PathLog.debug("_planarPerformOclScan()")
SCANS = list()
SCANS = []
if offsetPoints or obj.CutPattern == "Offset":
PNTSET = PathSurfaceSupport.pathGeomToOffsetPointSet(obj, pathGeom)
for D in PNTSET:
stpOvr = list()
ofst = list()
stpOvr = []
ofst = []
for I in D:
if I == "BRK":
stpOvr.append(ofst)
stpOvr.append(I)
ofst = list()
ofst = []
else:
# D format is ((p1, p2), (p3, p4))
(A, B) = I
@@ -1321,7 +1292,7 @@ class ObjectSurface(PathOp.ObjectOp):
stpOvr.append(ofst)
SCANS.extend(stpOvr)
elif obj.CutPattern in ["Line", "Spiral", "ZigZag"]:
stpOvr = list()
stpOvr = []
if obj.CutPattern == "Line":
# PNTSET = PathSurfaceSupport.pathGeomToLinesPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps)
PNTSET = PathSurfaceSupport.pathGeomToLinesPointSet(self, obj, pathGeom)
@@ -1342,7 +1313,7 @@ class ObjectSurface(PathOp.ObjectOp):
(A, B) = LN
stpOvr.append(self._planarDropCutScan(pdc, A, B))
SCANS.append(stpOvr)
stpOvr = list()
stpOvr = []
elif obj.CutPattern in ["Circular", "CircularZigZag"]:
# PNTSET is list, by stepover.
# Each stepover is a list containing arc/loop descriptions, (sp, ep, cp)
@@ -1350,7 +1321,7 @@ class ObjectSurface(PathOp.ObjectOp):
PNTSET = PathSurfaceSupport.pathGeomToCircularPointSet(self, obj, pathGeom)
for so in range(0, len(PNTSET)):
stpOvr = list()
stpOvr = []
erFlg = False
(aTyp, dirFlg, ARCS) = PNTSET[so]
@@ -1441,7 +1412,7 @@ class ObjectSurface(PathOp.ObjectOp):
odd = True
lstStpEnd = None
for so in range(0, lenSCANDATA):
cmds = list()
cmds = []
PRTS = SCANDATA[so]
lenPRTS = len(PRTS)
first = PRTS[0][0] # first point of arc/line stepover group
@@ -1544,7 +1515,7 @@ class ObjectSurface(PathOp.ObjectOp):
odd = True # ZigZag directional switch
lyrHasCmds = False
actvSteps = 0
LYR = list()
LYR = []
# if lyr > 0:
# if prvStpLast is not None:
# lastPrvStpLast = prvStpLast
@@ -1558,8 +1529,8 @@ class ObjectSurface(PathOp.ObjectOp):
lenSO = len(SO)
# Pre-process step-over parts for layer depth and holds
ADJPRTS = list()
LMAX = list()
ADJPRTS = []
LMAX = []
soHasPnts = False
brkFlg = False
for i in range(0, lenSO):
@@ -1585,9 +1556,9 @@ class ObjectSurface(PathOp.ObjectOp):
# Process existing parts within current step over
prtsHasCmds = False
stepHasCmds = False
prtsCmds = list()
stpOvrCmds = list()
transCmds = list()
prtsCmds = []
stpOvrCmds = []
transCmds = []
if soHasPnts is True:
first = ADJPRTS[0][0] # first point of arc/line stepover group
last = None
@@ -1712,8 +1683,8 @@ class ObjectSurface(PathOp.ObjectOp):
return GCODE
def _planarMultipassPreProcess(self, obj, LN, prvDep, layDep):
ALL = list()
PTS = list()
ALL = []
PTS = []
optLinTrans = obj.OptimizeStepOverTransitions
safe = math.ceil(obj.SafeHeight.Value)
@@ -1740,7 +1711,7 @@ class ObjectSurface(PathOp.ObjectOp):
if optLinTrans is True:
# Remove leading and trailing Hold Points
popList = list()
popList = []
for i in range(0, len(PTS)): # identify leading string
if PTS[i].z == safe:
popList.append(i)
@@ -1750,7 +1721,7 @@ class ObjectSurface(PathOp.ObjectOp):
for p in popList: # Remove hold points
PTS.pop(p)
ALL.pop(p)
popList = list()
popList = []
for i in range(len(PTS) - 1, -1, -1): # identify trailing string
if PTS[i].z == safe:
popList.append(i)
@@ -1772,7 +1743,7 @@ class ObjectSurface(PathOp.ObjectOp):
return (PTS, lMax)
def _planarMultipassProcess(self, obj, PNTS, lMax):
output = list()
output = []
optimize = obj.OptimizeLinearPaths
safe = math.ceil(obj.SafeHeight.Value)
lenPNTS = len(PNTS)
@@ -1855,7 +1826,7 @@ class ObjectSurface(PathOp.ObjectOp):
passes, as well as other kinds of breaks. When
OptimizeStepOverTransitions is enabled, uses safePDC to safely optimize
short (~order of cutter diameter) transitions."""
cmds = list()
cmds = []
rtpd = False
height = obj.SafeHeight.Value
# Allow cutter-down transitions with a distance up to 2x cutter
@@ -1924,7 +1895,7 @@ class ObjectSurface(PathOp.ObjectOp):
return cmds
def _arcsToG2G3(self, LN, numPts, odd, gDIR, tolrnc):
cmds = list()
cmds = []
strtPnt = LN[0]
endPnt = LN[numPts - 1]
strtHght = strtPnt.z