Merge pull request #4797 from Russ4262/feature/tile_job

[Path] GUI scripting support and other improvements
This commit is contained in:
sliptonic
2021-08-14 09:26:25 -05:00
committed by GitHub
25 changed files with 232 additions and 159 deletions

View File

@@ -737,9 +737,19 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def SetupProperties():
setup = ["Side", "OperationType", "Tolerance", "StepOver",
"LiftDistance", "KeepToolDownRatio", "StockToLeave",
"ForceInsideOut", "FinishingProfile", "Stopped",
"StopProcessing", "UseHelixArcs", "AdaptiveInputState",
"AdaptiveOutputState", "HelixAngle", "HelixConeAngle",
"HelixDiameterLimit", "UseOutline"]
return setup
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Adaptive operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = PathAdaptive(obj, name)
obj.Proxy = PathAdaptive(obj, name, parentJob)
return obj

View File

@@ -70,9 +70,9 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Custom operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
proxy = ObjectCustom(obj, name)
obj.Proxy = ObjectCustom(obj, name, parentJob)
return obj

View File

@@ -291,10 +291,9 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Deburr operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectDeburr(obj, name)
obj.Proxy = ObjectDeburr(obj, name, parentJob)
return obj

View File

@@ -35,6 +35,11 @@ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# PathLog.trackModule(PathLog.thisModule())
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
def _vstr(v):
if v:
return "(%.2f, %.2f, %.2f)" % (v.x, v.y, v.z)
@@ -77,7 +82,29 @@ class DressupPathBoundary(object):
obj.Stock = None
return True
def boundaryCommands(self, obj, begin, end, verticalFeed):
def execute(self, obj):
pb = PathBoundary(obj.Base, obj.Stock.Shape, obj.Inside)
obj.Path = pb.execute()
# Eclass
class PathBoundary:
"""class PathBoundary...
This class requires a base operation, boundary shape, and optional inside boolean (default is True).
The `execute()` method returns a Path object with path commands limited to cut paths inside or outside
the provided boundary shape.
"""
def __init__(self, baseOp, boundaryShape, inside=True):
self.baseOp = baseOp
self.boundary = boundaryShape
self.inside = inside
self.safeHeight = None
self.clearanceHeight = None
self.strG1ZsafeHeight = None
self.strG0ZclearanceHeight = None
def boundaryCommands(self, begin, end, verticalFeed):
PathLog.track(_vstr(begin), _vstr(end))
if end and PathGeom.pointsCoincide(begin, end):
return []
@@ -94,117 +121,117 @@ class DressupPathBoundary(object):
cmds.append(Path.Command('G1', {'Z': end.z, 'F': verticalFeed}))
return cmds
def execute(self, obj):
if not obj.Base or not obj.Base.isDerivedFrom('Path::Feature') or not obj.Base.Path:
return
def execute(self):
if not self.baseOp or not self.baseOp.isDerivedFrom('Path::Feature') or not self.baseOp.Path:
return None
tc = PathDressup.toolController(obj.Base)
if len(self.baseOp.Path.Commands) == 0:
PathLog.warning("No Path Commands for %s" % self.baseOp.Label)
return []
if len(obj.Base.Path.Commands) > 0:
self.safeHeight = float(PathUtil.opProperty(obj.Base, 'SafeHeight'))
self.clearanceHeight = float(PathUtil.opProperty(obj.Base, 'ClearanceHeight'))
self.strG1ZsafeHeight = Path.Command('G1', {'Z': self.safeHeight, 'F': tc.VertFeed.Value})
self.strG0ZclearanceHeight = Path.Command('G0', {'Z': self.clearanceHeight})
tc = PathDressup.toolController(self.baseOp)
boundary = obj.Stock.Shape
cmd = obj.Base.Path.Commands[0]
pos = cmd.Placement.Base # bogus m/c position to create first edge
bogusX = True
bogusY = True
commands = [cmd]
lastExit = None
for cmd in obj.Base.Path.Commands[1:]:
if cmd.Name in PathGeom.CmdMoveAll:
if bogusX == True :
bogusX = ( 'X' not in cmd.Parameters )
if bogusY :
bogusY = ( 'Y' not in cmd.Parameters )
edge = PathGeom.edgeForCmd(cmd, pos)
if edge:
inside = edge.common(boundary).Edges
outside = edge.cut(boundary).Edges
if not obj.Inside: # UI "inside boundary" param
tmp = inside
inside = outside
outside = tmp
# it's really a shame that one cannot trust the sequence and/or
# orientation of edges
if 1 == len(inside) and 0 == len(outside):
PathLog.track(_vstr(pos), _vstr(lastExit), ' + ', cmd)
# cmd fully included by boundary
if lastExit:
self.safeHeight = float(PathUtil.opProperty(self.baseOp, 'SafeHeight'))
self.clearanceHeight = float(PathUtil.opProperty(self.baseOp, 'ClearanceHeight'))
self.strG1ZsafeHeight = Path.Command('G1', {'Z': self.safeHeight, 'F': tc.VertFeed.Value})
self.strG0ZclearanceHeight = Path.Command('G0', {'Z': self.clearanceHeight})
cmd = self.baseOp.Path.Commands[0]
pos = cmd.Placement.Base # bogus m/c position to create first edge
bogusX = True
bogusY = True
commands = [cmd]
lastExit = None
for cmd in self.baseOp.Path.Commands[1:]:
if cmd.Name in PathGeom.CmdMoveAll:
if bogusX == True :
bogusX = ( 'X' not in cmd.Parameters )
if bogusY :
bogusY = ( 'Y' not in cmd.Parameters )
edge = PathGeom.edgeForCmd(cmd, pos)
if edge:
inside = edge.common(self.boundary).Edges
outside = edge.cut(self.boundary).Edges
if not self.inside: # UI "inside boundary" param
tmp = inside
inside = outside
outside = tmp
# it's really a shame that one cannot trust the sequence and/or
# orientation of edges
if 1 == len(inside) and 0 == len(outside):
PathLog.track(_vstr(pos), _vstr(lastExit), ' + ', cmd)
# cmd fully included by boundary
if lastExit:
if not ( bogusX or bogusY ) : # don't insert false paths based on bogus m/c position
commands.extend(self.boundaryCommands(lastExit, pos, tc.VertFeed.Value))
lastExit = None
commands.append(cmd)
pos = PathGeom.commandEndPoint(cmd, pos)
elif 0 == len(inside) and 1 == len(outside):
PathLog.track(_vstr(pos), _vstr(lastExit), ' - ', cmd)
# cmd fully excluded by boundary
if not lastExit:
lastExit = pos
pos = PathGeom.commandEndPoint(cmd, pos)
else:
PathLog.track(_vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd)
# cmd pierces boundary
while inside or outside:
ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)]
PathLog.track(ie)
if ie:
e = ie[0]
LastPt = e.valueAt(e.LastParameter)
flip = PathGeom.pointsCoincide(pos, LastPt)
newPos = e.valueAt(e.FirstParameter) if flip else LastPt
# inside edges are taken at this point (see swap of inside/outside
# above - so we can just connect the dots ...
if lastExit:
if not ( bogusX or bogusY ) : commands.extend(self.boundaryCommands(lastExit, pos, tc.VertFeed.Value))
lastExit = None
PathLog.track(e, flip)
if not ( bogusX or bogusY ) : # don't insert false paths based on bogus m/c position
commands.extend(self.boundaryCommands(obj, lastExit, pos, tc.VertFeed.Value))
lastExit = None
commands.append(cmd)
pos = PathGeom.commandEndPoint(cmd, pos)
elif 0 == len(inside) and 1 == len(outside):
PathLog.track(_vstr(pos), _vstr(lastExit), ' - ', cmd)
# cmd fully excluded by boundary
if not lastExit:
lastExit = pos
pos = PathGeom.commandEndPoint(cmd, pos)
else:
PathLog.track(_vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd)
# cmd pierces boundary
while inside or outside:
ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)]
PathLog.track(ie)
if ie:
e = ie[0]
LastPt = e.valueAt(e.LastParameter)
flip = PathGeom.pointsCoincide(pos, LastPt)
newPos = e.valueAt(e.FirstParameter) if flip else LastPt
# inside edges are taken at this point (see swap of inside/outside
# above - so we can just connect the dots ...
if lastExit:
if not ( bogusX or bogusY ) : commands.extend(self.boundaryCommands(obj, lastExit, pos, tc.VertFeed.Value))
lastExit = None
PathLog.track(e, flip)
if not ( bogusX or bogusY ) : # don't insert false paths based on bogus m/c position
commands.extend(PathGeom.cmdsForEdge(e, flip, False, 50, tc.HorizFeed.Value, tc.VertFeed.Value))
inside.remove(e)
commands.extend(PathGeom.cmdsForEdge(e, flip, False, 50, tc.HorizFeed.Value, tc.VertFeed.Value))
inside.remove(e)
pos = newPos
lastExit = newPos
else:
oe = [e for e in outside if PathGeom.edgeConnectsTo(e, pos)]
PathLog.track(oe)
if oe:
e = oe[0]
ptL = e.valueAt(e.LastParameter)
flip = PathGeom.pointsCoincide(pos, ptL)
newPos = e.valueAt(e.FirstParameter) if flip else ptL
# outside edges are never taken at this point (see swap of
# inside/outside above) - so just move along ...
outside.remove(e)
pos = newPos
lastExit = newPos
else:
oe = [e for e in outside if PathGeom.edgeConnectsTo(e, pos)]
PathLog.track(oe)
if oe:
e = oe[0]
ptL = e.valueAt(e.LastParameter)
flip = PathGeom.pointsCoincide(pos, ptL)
newPos = e.valueAt(e.FirstParameter) if flip else ptL
# outside edges are never taken at this point (see swap of
# inside/outside above) - so just move along ...
outside.remove(e)
pos = newPos
else:
PathLog.error('huh?')
import Part
Part.show(Part.Vertex(pos), 'pos')
for e in inside:
Part.show(e, 'ei')
for e in outside:
Part.show(e, 'eo')
raise Exception('This is not supposed to happen')
# Eif
PathLog.error('huh?')
import Part
Part.show(Part.Vertex(pos), 'pos')
for e in inside:
Part.show(e, 'ei')
for e in outside:
Part.show(e, 'eo')
raise Exception('This is not supposed to happen')
# Eif
# Ewhile
# Eif
# pos = PathGeom.commandEndPoint(cmd, pos)
# Eif
# Ewhile
# Eif
else:
PathLog.track('no-move', cmd)
commands.append(cmd)
if lastExit:
commands.extend(self.boundaryCommands(obj, lastExit, None, tc.VertFeed.Value))
lastExit = None
else:
PathLog.warning("No Path Commands for %s" % obj.Base.Label)
commands = []
PathLog.track(commands)
obj.Path = Path.Path(commands)
# pos = PathGeom.commandEndPoint(cmd, pos)
# Eif
else:
PathLog.track('no-move', cmd)
commands.append(cmd)
if lastExit:
commands.extend(self.boundaryCommands(lastExit, None, tc.VertFeed.Value))
lastExit = None
PathLog.track(commands)
return Path.Path(commands)
# Eclass
def Create(base, name='DressupPathBoundary'):
'''Create(base, name='DressupPathBoundary') ... creates a dressup limiting base's Path to a boundary.'''

View File

@@ -159,12 +159,13 @@ def SetupProperties():
setup.append("RetractHeight")
return setup
def Create(name, obj = None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Drilling operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectDrilling(obj, name)
obj.Proxy = ObjectDrilling(obj, name, parentJob)
if obj.Proxy:
obj.Proxy.findAllHoles(obj)

View File

@@ -48,8 +48,8 @@ def translate(context, text, disambig=None):
class ObjectEngrave(PathEngraveBase.ObjectOp):
'''Proxy class for Engrave operation.'''
def __init__(self, obj, name):
super(ObjectEngrave, self).__init__(obj, name)
def __init__(self, obj, name, parentJob):
super(ObjectEngrave, self).__init__(obj, name, parentJob)
self.wires = []
def opFeatures(self, obj):
@@ -144,9 +144,9 @@ def SetupProperties():
return ["StartVertex"]
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns an Engrave operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectEngrave(obj, name)
obj.Proxy = ObjectEngrave(obj, name, parentJob)
return obj

View File

@@ -214,11 +214,11 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Helix operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectHelix(obj, name)
obj.Proxy = ObjectHelix(obj, name, parentJob)
if obj.Proxy:
obj.Proxy.findAllHoles(obj)
return obj

View File

@@ -175,8 +175,8 @@ class ViewProvider:
FreeCADGui.Control.closeDialog()
FreeCADGui.Control.showDialog(self.taskPanel)
self.taskPanel.setupUi(activate)
self.deleteOnReject = False
self.showOriginAxis(True)
self.deleteOnReject = False
def resetTaskPanel(self):
self.showOriginAxis(False)

View File

@@ -304,9 +304,9 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Mill Facing operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectFace(obj, name)
obj.Proxy = ObjectFace(obj, name, parentJob)
return obj

View File

@@ -119,7 +119,7 @@ class ObjectOp(object):
obj.addProperty("App::PropertyDistance", "OpStockZMin", "Op Values", QtCore.QT_TRANSLATE_NOOP("PathOp", "Holds the min Z value of Stock"))
obj.setEditorMode('OpStockZMin', 1) # read-only
def __init__(self, obj, name):
def __init__(self, obj, name, parentJob=None):
PathLog.track()
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("PathOp", "Make False, to prevent operation from generating code"))
@@ -190,6 +190,8 @@ class ObjectOp(object):
self.initOperation(obj)
if not hasattr(obj, 'DoNotSetDefaultValues') or not obj.DoNotSetDefaultValues:
if parentJob:
self.job = PathUtils.addToJob(obj, jobname=parentJob.Name)
job = self.setDefaultValues(obj)
if job:
job.SetupSheet.Proxy.setOperationProperties(obj, name)
@@ -322,7 +324,10 @@ class ObjectOp(object):
def setDefaultValues(self, obj):
'''setDefaultValues(obj) ... base implementation.
Do not overwrite, overwrite opSetDefaultValues() instead.'''
job = PathUtils.addToJob(obj)
if self.job:
job = self.job
else:
job = PathUtils.addToJob(obj)
obj.Active = True
@@ -622,5 +627,3 @@ class ObjectOp(object):
This function can safely be overwritten by subclasses.'''
return True

View File

@@ -1287,12 +1287,12 @@ def Create(res):
this function directly, but calls the Activated() function of the Command object
that is created in each operations Gui implementation.'''
FreeCAD.ActiveDocument.openTransaction("Create %s" % res.name)
obj = res.objFactory(res.name)
obj = res.objFactory(res.name, obj=None, parentJob=res.job)
if obj.Proxy:
obj.ViewObject.Proxy = ViewProvider(obj.ViewObject, res)
obj.ViewObject.Visibility = False
FreeCAD.ActiveDocument.commitTransaction()
obj.ViewObject.Document.setEdit(obj.ViewObject, 0)
return obj
FreeCAD.ActiveDocument.abortTransaction()
@@ -1336,6 +1336,7 @@ class CommandResources:
self.menuText = menuText
self.accelKey = accelKey
self.toolTip = toolTip
self.job = None
def SetupOperation(name,

View File

@@ -717,9 +717,9 @@ def SetupProperties():
return PathPocketBase.SetupProperties() + ["HandleMultipleFeatures"]
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Pocket operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectPocket(obj, name)
obj.Proxy = ObjectPocket(obj, name, parentJob)
return obj

View File

@@ -244,11 +244,11 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Pocket operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject('Path::FeaturePython', name)
obj.Proxy = ObjectPocket(obj, name)
obj.Proxy = ObjectPocket(obj, name, parentJob)
return obj
return obj

View File

@@ -97,9 +97,9 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Probing operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
proxy = ObjectProbing(obj, name)
proxy = ObjectProbing(obj, name, parentJob)
return obj

View File

@@ -1301,9 +1301,9 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Profile based on faces operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectProfile(obj, name)
obj.Proxy = ObjectProfile(obj, name, parentJob)
return obj

View File

@@ -42,9 +42,9 @@ def SetupProperties():
return PathProfile.SetupProperties()
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Profile operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectContour(obj, name)
obj.Proxy = ObjectContour(obj, name, parentJob)
return obj

View File

@@ -43,9 +43,9 @@ def SetupProperties():
return PathProfile.SetupProperties()
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Profile operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectProfile(obj, name)
obj.Proxy = ObjectProfile(obj, name, parentJob)
return obj

View File

@@ -44,9 +44,9 @@ def SetupProperties():
return PathProfile.SetupProperties()
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Profile operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectProfile(obj, name)
obj.Proxy = ObjectProfile(obj, name, parentJob)
return obj

View File

@@ -34,7 +34,7 @@ __doc__ = "A container for all default values and job specific configuration val
_RegisteredOps = {}
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# PathLog.trackModule(PathLog.thisModule())

View File

@@ -27,6 +27,7 @@ import PathScripts.PathDressup as PathDressup
import PathScripts.PathGeom as PathGeom
import PathScripts.PathLog as PathLog
import PathScripts.PathUtil as PathUtil
import PathScripts.PathJob as PathJob
import PathSimulator
import math
import os
@@ -75,6 +76,7 @@ class PathSimulation:
self.simperiod = 20
self.accuracy = 0.1
self.resetSimulation = False
self.jobs = []
def Connect(self, but, sig):
QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), sig)
@@ -96,13 +98,9 @@ class PathSimulation:
self.onSpeedBarChange()
form.sliderAccuracy.valueChanged.connect(self.onAccuracyBarChange)
self.onAccuracyBarChange()
self._populateJobSelection(form)
form.comboJobs.currentIndexChanged.connect(self.onJobChange)
jobList = FreeCAD.ActiveDocument.findObjects("Path::FeaturePython", "Job.*")
form.comboJobs.clear()
self.jobs = []
for j in jobList:
self.jobs.append(j)
form.comboJobs.addItem(j.ViewObject.Icon, j.Label)
self.onJobChange()
FreeCADGui.Control.showDialog(self.taskForm)
self.disableAnim = False
self.isVoxel = True
@@ -111,6 +109,40 @@ class PathSimulation:
self.SimulateMill()
self.initdone = True
def _populateJobSelection(self, form):
# Make Job selection combobox
setJobIdx = 0
jobName = ''
jIdx = 0
# Get list of Job objects in active document
jobList = FreeCAD.ActiveDocument.findObjects("Path::FeaturePython", "Job.*")
jCnt = len(jobList)
# Check if user has selected a specific job for simulation
guiSelection = FreeCADGui.Selection.getSelectionEx()
if guiSelection: # Identify job selected by user
sel = guiSelection[0]
if hasattr(sel.Object, "Proxy") and isinstance(sel.Object.Proxy, PathJob.ObjectJob):
jobName = sel.Object.Name
FreeCADGui.Selection.clearSelection()
# populate the job selection combobox
form.comboJobs.blockSignals(True)
form.comboJobs.clear()
form.comboJobs.blockSignals(False)
for j in jobList:
form.comboJobs.addItem(j.ViewObject.Icon, j.Label)
self.jobs.append(j)
if j.Name == jobName or jCnt == 1:
setJobIdx = jIdx
jIdx += 1
# Pre-select GUI-selected job in the combobox
if jobName or jCnt == 1:
form.comboJobs.setCurrentIndex(setJobIdx)
else:
form.comboJobs.setCurrentIndex(0)
def SetupSimulation(self):
form = self.taskForm.form
self.activeOps = []

View File

@@ -1767,9 +1767,9 @@ def SetupProperties():
return [tup[1] for tup in ObjectSlot.opPropertyDefinitions(False)]
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Slot operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectSlot(obj, name)
obj.Proxy = ObjectSlot(obj, name, parentJob)
return obj

View File

@@ -2124,9 +2124,9 @@ def SetupProperties():
return [tup[1] for tup in ObjectSurface.opPropertyDefinitions(False)]
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Surface operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectSurface(obj, name)
obj.Proxy = ObjectSurface(obj, name, parentJob)
return obj

View File

@@ -327,11 +327,11 @@ def SetupProperties():
return setup
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a thread milling operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectThreadMilling(obj, name)
obj.Proxy = ObjectThreadMilling(obj, name, parentJob)
if obj.Proxy:
obj.Proxy.findAllHoles(obj)
return obj

View File

@@ -363,9 +363,9 @@ def SetupProperties():
return ["Discretize"]
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Vcarve operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
ObjectVcarve(obj, name)
obj.Proxy = ObjectVcarve(obj, name, parentJob)
return obj

View File

@@ -1814,9 +1814,9 @@ def SetupProperties():
return [tup[1] for tup in ObjectWaterline.opPropertyDefinitions(False)]
def Create(name, obj=None):
def Create(name, obj=None, parentJob=None):
'''Create(name) ... Creates and returns a Waterline operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectWaterline(obj, name)
obj.Proxy = ObjectWaterline(obj, name, parentJob)
return obj