surface and waterline translation
This commit is contained in:
@@ -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><html><head/><body><p>Select the algorithm to use: OCL Dropcutter*, or Experimental (Not OCL based).</p></body></html></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><html><head/><body><p>Positive values push the cutter toward, or beyond, the boundary. Negative values retract the cutter away from the boundary.</p></body></html></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><html><head/><body><p>Select the algorithm to use: OCL Dropcutter*, or Experimental (Not OCL based).</p></body></html></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><html><head/><body><p>Enable optimization of linear paths (co-linear points). Removes unnecessary co-linear points from G-Code output.</p></body></html></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><html><head/><body><p>Set the geometric clearing pattern to use for the operation.</p></body></html></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><html><head/><body><p>Set the geometric clearing pattern to use for the operation.</p></body></html></string>
|
||||
<string><html><head/><body><p>Set the Z-axis depth offset from the target surface.</p></body></html></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><html><head/><body><p>Set the sampling resolution. Smaller values quickly increase processing time.</p></body></html></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><html><head/><body><p>Enable optimization of linear paths (co-linear points). Removes unnecessary co-linear points from G-Code output.</p></body></html></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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user