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

@@ -53,7 +53,34 @@
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="3">
<item row="0" column="0">
<widget class="QLabel" name="algorithmSelect_label">
<property name="text">
<string>Algorithm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="algorithmSelect">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select the algorithm to use: OCL Dropcutter*, or Experimental (Not OCL based).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="boundBoxSelect_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>BoundBox</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="boundBoxSelect">
<property name="font">
<font>
@@ -65,20 +92,14 @@
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLineEdit" name="boundaryAdjustment">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Positive values push the cutter toward, or beyond, the boundary. Negative values retract the cutter away from the boundary.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<item row="2" column="0">
<widget class="QLabel" name="layerMode_label">
<property name="text">
<string>Layer Mode</string>
</property>
</widget>
</item>
<item row="2" column="3">
<item row="2" column="1">
<widget class="QComboBox" name="layerMode">
<property name="font">
<font>
@@ -90,20 +111,22 @@
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="algorithmSelect">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select the algorithm to use: OCL Dropcutter*, or Experimental (Not OCL based).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<item row="3" column="0">
<widget class="QLabel" name="cutPattern_label">
<property name="text">
<string>Cut Pattern</string>
</property>
</widget>
</item>
<item row="11" column="3">
<widget class="QCheckBox" name="optimizeEnabled">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable optimization of linear paths (co-linear points). Removes unnecessary co-linear points from G-Code output.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<item row="3" column="1">
<widget class="QComboBox" name="cutPattern">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Optimize Linear Paths</string>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the geometric clearing pattern to use for the operation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@@ -120,19 +143,24 @@
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="cutPattern">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<item row="4" column="1">
<widget class="Gui::InputField" name="boundaryAdjustment">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the geometric clearing pattern to use for the operation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the Z-axis depth offset from the target surface.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="8" column="3">
<item row="5" column="0">
<widget class="QLabel" name="stepOver_label">
<property name="text">
<string>Step over</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="stepOver">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@@ -151,34 +179,14 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="layerMode_label">
<item row="6" column="0">
<widget class="QLabel" name="sampleInterval_label">
<property name="text">
<string>Layer Mode</string>
<string>Sample interval</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="boundBoxSelect_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>BoundBox</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="stepOver_label">
<property name="text">
<string>Step over</string>
</property>
</widget>
</item>
<item row="9" column="3">
<item row="6" column="1">
<widget class="Gui::InputField" name="sampleInterval">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the sampling resolution. Smaller values quickly increase processing time.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@@ -188,24 +196,13 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="cutPattern_label">
<property name="text">
<string>Cut Pattern</string>
<item row="7" column="1">
<widget class="QCheckBox" name="optimizeEnabled">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable optimization of linear paths (co-linear points). Removes unnecessary co-linear points from G-Code output.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="sampleInterval_label">
<property name="text">
<string>Sample interval</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="algorithmSelect_label">
<property name="text">
<string>Algorithm</string>
<string>Optimize Linear Paths</string>
</property>
</widget>
</item>
@@ -241,7 +238,6 @@
<tabstop>boundBoxSelect</tabstop>
<tabstop>layerMode</tabstop>
<tabstop>cutPattern</tabstop>
<tabstop>boundaryAdjustment</tabstop>
<tabstop>stepOver</tabstop>
<tabstop>sampleInterval</tabstop>
<tabstop>optimizeEnabled</tabstop>

View File

@@ -39,6 +39,24 @@ else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
def populateCombobox(form, enumTups, comboBoxesPropertyMap):
"""fillComboboxes(form, comboBoxesPropertyMap) ... populate comboboxes with translated enumerations
** comboBoxesPropertyMap will be unnecessary if UI files use strict combobox naming protocol.
Args:
form = UI form
enumTups = list of (translated_text, data_string) tuples
comboBoxesPropertyMap = list of (translated_text, data_string) tuples
"""
PathLog.track(enumTups)
# Load appropriate enumerations in each combobox
for cb, prop in comboBoxesPropertyMap:
box = getattr(form, cb) # Get the combobox
box.clear() # clear the combobox
for text, data in enumTups[prop]: # load enumerations
box.addItem(text, data)
def updateInputField(obj, prop, widget, onBeforeChange=None):
"""updateInputField(obj, prop, widget) ... update obj's property prop with the value of widget.
The property's value is only assigned if the new value differs from the current value.
@@ -50,6 +68,7 @@ def updateInputField(obj, prop, widget, onBeforeChange=None):
"""
PathLog.track()
value = widget.property("rawValue")
PathLog.track("value: {}".format(value))
attr = PathUtil.getProperty(obj, prop)
attrValue = attr.Value if hasattr(attr, "Value") else attr

View File

@@ -107,6 +107,8 @@ def _log(level, module_line_func, msg):
def debug(msg):
"""(message)"""
module, line, func = _caller()
msg = "({}) - {}".format(line, msg)
return _log(Level.DEBUG, _caller(), msg)
def info(msg):
"""(message)"""

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

View File

@@ -51,7 +51,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.setTitle("3D Surface - " + obj.Label)
# self.updateVisibility()
# retrieve property enumerations
self.propEnums = PathSurface.ObjectSurface.opPropertyEnumerations(False)
# self.propEnums = PathSurface.ObjectSurface.opPropertyEnumerations(False)
self.propEnums = PathSurface.ObjectSurface.propertyEnumerations(False)
def getForm(self):
"""getForm() ... returns UI"""
@@ -59,29 +60,16 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
comboToPropertyMap = [
("boundBoxSelect", "BoundBox"),
("scanType", "ScanType"),
("cutPattern", "CutPattern"),
("profileEdges", "ProfileEdges"),
("layerMode", "LayerMode"),
("dropCutterDirSelect", "DropCutterDir"),
]
enumTups = PathSurface.ObjectSurface.propertyEnumerations(dataType="raw")
self.populateCombobox(form, enumTups, comboToPropertyMap)
PathGui.populateCombobox(form, enumTups, comboToPropertyMap)
return form
def populateCombobox(self, form, enumTups, comboBoxesPropertyMap):
"""fillComboboxes(form, comboBoxesPropertyMap) ... populate comboboxes with translated enumerations
** comboBoxesPropertyMap will be unnecessary if UI files use strict combobox naming protocol.
Args:
form = UI form
enumTups = list of (translated_text, data_string) tuples
comboBoxesPropertyMap = list of (translated_text, data_string) tuples
"""
# Load appropriate enumerations in each combobox
for cb, prop in comboBoxesPropertyMap:
box = getattr(form, cb) # Get the combobox
box.clear() # clear the combobox
for text, data in enumTups[prop]: # load enumerations
box.addItem(text, data)
def getFields(self, obj):
"""getFields(obj) ... transfers values from UI to obj's proprties"""
self.updateToolController(obj, self.form.toolController)
@@ -108,13 +96,16 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
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["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
# val = self.propEnums["ProfileEdges"][self.form.profileEdges.currentIndex()]
# if obj.ProfileEdges != val:
# obj.ProfileEdges = val
obj.CutPattern = self.form.cutPattern.currentData()
obj.ProfileEdges = self.form.profileEdges.currentData()
if obj.AvoidLastX_Faces != self.form.avoidLastX_Faces.value():
obj.AvoidLastX_Faces = self.form.avoidLastX_Faces.value()
@@ -169,12 +160,12 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
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)
# 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(
@@ -287,7 +278,7 @@ Command = PathOpGui.SetupOperation(
"Surface",
PathSurface.Create,
TaskPanelOpPage,
"Path_Surface",
"Path_3DSurface",
QtCore.QT_TRANSLATE_NOOP("Path_Surface", "3D Surface"),
QtCore.QT_TRANSLATE_NOOP(
"Path_Surface", "Create a 3D Surface Operation from a model"

View File

@@ -1207,11 +1207,9 @@ def getSliceFromEnvelope(env):
def _prepareModelSTLs(self, JOB, obj, m, ocl):
"""Tessellate model shapes or copy existing meshes into ocl.STLSurf
objects"""
PathLog.debug("_prepareModelSTLs()")
if self.modelSTLs[m] is True:
model = JOB.Model.Group[m]
if self.modelSTLs[m] is True:
self.modelSTLs[m] = _makeSTL(model, obj, ocl, self.modelTypes[m])
self.modelSTLs[m] = _makeSTL(model, obj, ocl, self.modelTypes[m])
def _makeSafeSTL(self, JOB, obj, mdlIdx, faceShapes, voidShapes, ocl):

View File

@@ -22,6 +22,8 @@
# ***************************************************************************
from __future__ import print_function
from PySide import QtCore
import FreeCAD
__title__ = "Path Waterline Operation"
__author__ = "russ4262 (Russell Johnson), sliptonic (Brad Collette)"
@@ -29,28 +31,24 @@ __url__ = "http://www.freecadweb.org"
__doc__ = "Class and implementation of Waterline operation."
__contributors__ = ""
import FreeCAD
from PySide import QtCore
# OCL must be installed
try:
import ocl
except ImportError:
msg = QtCore.QCoreApplication.translate(
"PathWaterline", "This operation requires OpenCamLib to be installed."
"path_waterline", "This operation requires OpenCamLib to be installed."
)
FreeCAD.Console.PrintError(msg + "\n")
raise ImportError
# import sys
# sys.exit(msg)
import Path
import PathScripts.PathLog as PathLog
import PathScripts.PathUtils as PathUtils
import PathScripts.PathOp as PathOp
import PathScripts.PathSurfaceSupport as PathSurfaceSupport
import time
import PathScripts.PathUtils as PathUtils
import math
import time
from PySide.QtCore import QT_TRANSLATE_NOOP
# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader
@@ -60,13 +58,13 @@ Part = LazyLoader("Part", globals(), "Part")
if FreeCAD.GuiUp:
import FreeCADGui
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# PathLog.trackModule(PathLog.thisModule())
if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
translate = FreeCAD.Qt.translate
class ObjectWaterline(PathOp.ObjectOp):
@@ -83,6 +81,79 @@ class ObjectWaterline(PathOp.ObjectOp):
| PathOp.FeatureBaseFaces
)
@classmethod
def propertyEnumerations(self, dataType="data"):
"""propertyEnumerations(dataType="data")... return property enumeration lists of specified dataType.
Args:
dataType = 'data', 'raw', 'translated'
Notes:
'data' is list of internal string literals used in code
'raw' is list of (translated_text, data_string) tuples
'translated' is list of translated string literals
"""
# Enumeration lists for App::PropertyEnumeration properties
enums = {
"Algorithm": [
(translate("path_waterline", "OCL Dropcutter"), "OCL Dropcutter"),
(translate("path_waterline", "Experimental"), "Experimental"),
],
"BoundBox": [
(translate("path_waterline", "BaseBoundBox"), "BaseBoundBox"),
(translate("path_waterline", "Stock"), "Stock"),
],
"PatternCenterAt": [
(translate("path_waterline", "CenterOfMass"), "CenterOfMass"),
(translate("path_waterline", "CenterOfBoundBox"), "CenterOfBoundBox"),
(translate("path_waterline", "XminYmin"), "XminYmin"),
(translate("path_waterline", "Custom"), "Custom"),
],
"ClearLastLayer": [
(translate("path_waterline", "Off"), "Off"),
(translate("path_waterline", "Circular"), "Circular"),
(translate("path_waterline", "CircularZigZag"), "CircularZigZag"),
(translate("path_waterline", "Line"), "Line"),
(translate("path_waterline", "Offset"), "Offset"),
(translate("path_waterline", "Spiral"), "Spiral"),
(translate("path_waterline", "ZigZag"), "ZigZag"),
],
"CutMode": [
(translate("path_waterline", "Conventional"), "Conventional"),
(translate("path_waterline", "Climb"), "Climb"),
],
"CutPattern": [
(translate("path_waterline", "None"), "None"),
(translate("path_waterline", "Circular"), "Circular"),
(translate("path_waterline", "CircularZigZag"), "CircularZigZag"),
(translate("path_waterline", "Line"), "Line"),
(translate("path_waterline", "Offset"), "Offset"),
(translate("path_waterline", "Spiral"), "Spiral"),
(translate("path_waterline", "ZigZag"), "ZigZag"),
],
"HandleMultipleFeatures": [
(translate("path_waterline", "Collectively"), "Collectively"),
(translate("path_waterline", "Individually"), "Individually"),
],
"LayerMode": [
(translate("path_waterline", "Single-pass"), "Single-pass"),
(translate("path_waterline", "Multi-pass"), "Multi-pass"),
],
}
if dataType == "raw":
return enums
data = list()
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 initOperation(self, obj):
"""initOperation(obj) ... Initialize the operation by
managing property creation and property editor status."""
@@ -108,10 +179,10 @@ class ObjectWaterline(PathOp.ObjectOp):
# Set enumeration lists for enumeration properties
if len(self.addNewProps) > 0:
ENUMS = self.opPropertyEnumerations()
ENUMS = self.propertyEnumerations()
for n in ENUMS:
if n in self.addNewProps:
setattr(obj, n, ENUMS[n])
if n[0] in self.addNewProps:
setattr(obj, n[0], n[1])
if warn:
newPropMsg = translate("PathWaterline", "New property added to")
@@ -128,7 +199,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"ShowTempObjects",
"Debug",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Show the temporary path construction objects when module is in DEBUG mode.",
),
@@ -137,7 +208,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"AngularDeflection",
"Mesh Conversion",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Smaller values yield a finer, more accurate the mesh. Smaller values increase processing time a lot.",
),
@@ -146,7 +217,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"LinearDeflection",
"Mesh Conversion",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Smaller values yield a finer, more accurate the mesh. Smaller values do not increase processing time much.",
),
@@ -155,7 +226,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyInteger",
"AvoidLastX_Faces",
"Selected Geometry Settings",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Avoid cutting the last 'N' faces in the Base Geometry list of selected faces.",
),
@@ -164,7 +235,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"AvoidLastX_InternalFeatures",
"Selected Geometry Settings",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property", "Do not cut internal features on avoided faces."
),
),
@@ -172,7 +243,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"BoundaryAdjustment",
"Selected Geometry Settings",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Positive values push the cutter toward, or beyond, the boundary. Negative values retract the cutter away from the boundary.",
),
@@ -181,7 +252,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"BoundaryEnforcement",
"Selected Geometry Settings",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"If true, the cutter will remain inside the boundaries of the model or selected face(s).",
),
@@ -190,7 +261,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"HandleMultipleFeatures",
"Selected Geometry Settings",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Choose how to process multiple Base Geometry features.",
),
@@ -199,7 +270,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"InternalFeaturesAdjustment",
"Selected Geometry Settings",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Positive values push the cutter toward, or into, the feature. Negative values retract the cutter away from the feature.",
),
@@ -208,7 +279,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"InternalFeaturesCut",
"Selected Geometry Settings",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Cut internal feature areas within a larger selected face.",
),
@@ -217,7 +288,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"Algorithm",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Select the algorithm to use: OCL Dropcutter*, or Experimental (Not OCL based).",
),
@@ -226,7 +297,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"BoundBox",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property", "Select the overall boundary for the operation."
),
),
@@ -234,7 +305,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"ClearLastLayer",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Set to clear last layer in a `Multi-pass` operation.",
),
@@ -243,7 +314,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"CutMode",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Set the direction for the cutting tool to engage the material: Climb (ClockWise) or Conventional (CounterClockWise)",
),
@@ -252,7 +323,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"CutPattern",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Set the geometric clearing pattern to use for the operation.",
),
@@ -261,7 +332,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyFloat",
"CutPatternAngle",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property", "The yaw angle used for certain clearing patterns"
),
),
@@ -269,7 +340,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"CutPatternReversed",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Reverse the cut order of the stepover paths. For circular cut patterns, begin at the outside and work toward the center.",
),
@@ -278,7 +349,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"DepthOffset",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Set the Z-axis depth offset from the target surface.",
),
@@ -287,7 +358,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"IgnoreOuterAbove",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property", "Ignore outer waterlines above this height."
),
),
@@ -295,7 +366,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"LayerMode",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Complete the operation in a single pass at depth, or mulitiple passes to final depth.",
),
@@ -304,7 +375,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyVectorDistance",
"PatternCenterCustom",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property", "Set the start point for the cut pattern."
),
),
@@ -312,7 +383,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyEnumeration",
"PatternCenterAt",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Choose location of the center point for starting the cut pattern.",
),
@@ -321,7 +392,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"SampleInterval",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Set the sampling resolution. Smaller values quickly increase processing time.",
),
@@ -330,7 +401,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyFloat",
"StepOver",
"Clearing Options",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Set the stepover percentage, based on the tool's diameter.",
),
@@ -339,7 +410,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"OptimizeLinearPaths",
"Optimization",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Enable optimization of linear paths (co-linear points). Removes unnecessary co-linear points from G-Code output.",
),
@@ -348,7 +419,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"OptimizeStepOverTransitions",
"Optimization",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Enable separate optimization of transitions between, and breaks within, each step over path.",
),
@@ -357,7 +428,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyDistance",
"GapThreshold",
"Optimization",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Collinear and co-radial artifact gaps that are smaller than this threshold are closed in the path.",
),
@@ -366,7 +437,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyString",
"GapSizes",
"Optimization",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"Feedback: three smallest gaps identified in the path geometry.",
),
@@ -375,7 +446,7 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyVectorDistance",
"StartPoint",
"Start Point",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property",
"The custom start point for the path of this operation",
),
@@ -384,46 +455,12 @@ class ObjectWaterline(PathOp.ObjectOp):
"App::PropertyBool",
"UseStartPoint",
"Start Point",
QtCore.QT_TRANSLATE_NOOP(
QT_TRANSLATE_NOOP(
"App::Property", "Make True, if specifying a Start Point"
),
),
]
def opPropertyEnumerations(self):
# Enumeration lists for App::PropertyEnumeration properties
return {
"Algorithm": ["OCL Dropcutter", "Experimental"],
"BoundBox": ["BaseBoundBox", "Stock"],
"PatternCenterAt": [
"CenterOfMass",
"CenterOfBoundBox",
"XminYmin",
"Custom",
],
"ClearLastLayer": [
"Off",
"Circular",
"CircularZigZag",
"Line",
"Offset",
"Spiral",
"ZigZag",
],
"CutMode": ["Conventional", "Climb"],
"CutPattern": [
"None",
"Circular",
"CircularZigZag",
"Line",
"Offset",
"Spiral",
"ZigZag",
], # Additional goals ['Offset', 'Spiral', 'ZigZagOffset', 'Grid', 'Triangle']
"HandleMultipleFeatures": ["Collectively", "Individually"],
"LayerMode": ["Single-pass", "Multi-pass"],
}
def opPropertyDefaults(self, obj, job):
"""opPropertyDefaults(obj, job) ... returns a dictionary
of default values for the operation's properties."""
@@ -543,15 +580,16 @@ class ObjectWaterline(PathOp.ObjectOp):
obj.setEditorMode("ShowTempObjects", mode)
# Repopulate enumerations in case of changes
ENUMS = self.opPropertyEnumerations()
ENUMS = self.propertyEnumerations()
for n in ENUMS:
restore = False
if hasattr(obj, n):
val = obj.getPropertyByName(n)
if hasattr(obj, n[0]):
val = obj.getPropertyByName(n[0])
restore = True
setattr(obj, n, ENUMS[n])
setattr(obj, n[0], n[1])
if restore:
setattr(obj, n, val)
setattr(obj, n[0], val)
self.setEditorProperties(obj)

View File

@@ -21,20 +21,28 @@
# * *
# ***************************************************************************
from PySide import QtCore
from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD
import FreeCADGui
import PathGui as PGui # ensure Path/Gui/Resources are loaded
import PathScripts.PathWaterline as PathWaterline
import PathScripts.PathLog as PathLog
import PathScripts.PathGui as PathGui
import PathScripts.PathOpGui as PathOpGui
from PySide import QtCore
import PathScripts.PathWaterline as PathWaterline
__title__ = "Path Waterline Operation UI"
__author__ = "sliptonic (Brad Collette), russ4262 (Russell Johnson)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Waterline operation page controller and command implementation."
translate = FreeCAD.Qt.translate
if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
class TaskPanelOpPage(PathOpGui.TaskPanelPage):
"""Page controller class for the Waterline operation."""
@@ -45,24 +53,33 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
def getForm(self):
"""getForm() ... returns UI"""
return FreeCADGui.PySideUic.loadUi(":/panels/PageOpWaterlineEdit.ui")
form = FreeCADGui.PySideUic.loadUi(":/panels/PageOpWaterlineEdit.ui")
comboToPropertyMap = [
("algorithmSelect", "Algorithm"),
("boundBoxSelect", "BoundBox"),
("layerMode", "LayerMode"),
("cutPattern", "CutPattern"),
]
enumTups = PathWaterline.ObjectWaterline.propertyEnumerations(dataType="raw")
PathGui.populateCombobox(form, enumTups, comboToPropertyMap)
return form
def getFields(self, obj):
"""getFields(obj) ... transfers values from UI to obj's proprties"""
self.updateToolController(obj, self.form.toolController)
self.updateCoolant(obj, self.form.coolantController)
if obj.Algorithm != str(self.form.algorithmSelect.currentText()):
obj.Algorithm = str(self.form.algorithmSelect.currentText())
if obj.Algorithm != str(self.form.algorithmSelect.currentData()):
obj.Algorithm = str(self.form.algorithmSelect.currentData())
if obj.BoundBox != str(self.form.boundBoxSelect.currentText()):
obj.BoundBox = str(self.form.boundBoxSelect.currentText())
if obj.BoundBox != str(self.form.boundBoxSelect.currentData()):
obj.BoundBox = str(self.form.boundBoxSelect.currentData())
if obj.LayerMode != str(self.form.layerMode.currentText()):
obj.LayerMode = str(self.form.layerMode.currentText())
if obj.LayerMode != str(self.form.layerMode.currentData()):
obj.LayerMode = str(self.form.layerMode.currentData())
if obj.CutPattern != str(self.form.cutPattern.currentText()):
obj.CutPattern = str(self.form.cutPattern.currentText())
if obj.CutPattern != str(self.form.cutPattern.currentData()):
obj.CutPattern = str(self.form.cutPattern.currentData())
PathGui.updateInputField(
obj, "BoundaryAdjustment", self.form.boundaryAdjustment
@@ -121,7 +138,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
def updateVisibility(self, sentObj=None):
"""updateVisibility(sentObj=None)... Updates visibility of Tasks panel objects."""
Algorithm = self.form.algorithmSelect.currentText()
Algorithm = self.form.algorithmSelect.currentData()
self.form.optimizeEnabled.hide() # Has no independent QLabel object
if Algorithm == "OCL Dropcutter":
@@ -138,7 +155,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.form.boundaryAdjustment.show()
self.form.cutPattern_label.show()
self.form.boundaryAdjustment_label.show()
if self.form.cutPattern.currentText() == "None":
if self.form.cutPattern.currentData() == "None":
self.form.stepOver.hide()
self.form.stepOver_label.hide()
else:
@@ -157,10 +174,8 @@ Command = PathOpGui.SetupOperation(
PathWaterline.Create,
TaskPanelOpPage,
"Path_Waterline",
QtCore.QT_TRANSLATE_NOOP("Path_Waterline", "Waterline"),
QtCore.QT_TRANSLATE_NOOP(
"Path_Waterline", "Create a Waterline Operation from a model"
),
QT_TRANSLATE_NOOP("Path_Waterline", "Waterline"),
QT_TRANSLATE_NOOP("Path_Waterline", "Create a Waterline Operation from a model"),
PathWaterline.SetupProperties,
)