From 421e50ae87456232fac341035332eb9e845dcdda Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Fri, 1 Nov 2019 20:01:50 -0700 Subject: [PATCH] PathBoundary editor filled with life. --- .../Resources/panels/DressupPathBoundary.ui | 54 +++++------ .../PathScripts/PathDressupPathBoundary.py | 27 +++--- .../PathScripts/PathDressupPathBoundaryGui.py | 90 +++++++++++++++++-- src/Mod/Path/PathScripts/PathJob.py | 4 +- src/Mod/Path/PathScripts/PathJobGui.py | 12 ++- src/Mod/Path/PathScripts/PathStock.py | 19 +++- 6 files changed, 153 insertions(+), 53 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/DressupPathBoundary.ui b/src/Mod/Path/Gui/Resources/panels/DressupPathBoundary.ui index e206339278..f3d2d3254c 100644 --- a/src/Mod/Path/Gui/Resources/panels/DressupPathBoundary.ui +++ b/src/Mod/Path/Gui/Resources/panels/DressupPathBoundary.ui @@ -15,7 +15,7 @@ - + Boundary Body @@ -27,7 +27,7 @@ - + 0 @@ -76,29 +76,29 @@ - + - + - + - + - + Ext. X - + 0 @@ -108,52 +108,52 @@ - + Ext. Y - + - + Ext. Z - + - + - + - + - + - + - + Radius - + Height @@ -163,33 +163,33 @@ - + - + Length - + Width - + - + - + - + Height @@ -202,7 +202,7 @@ - + Constrained to Inside diff --git a/src/Mod/Path/PathScripts/PathDressupPathBoundary.py b/src/Mod/Path/PathScripts/PathDressupPathBoundary.py index f45d3acb46..f20ec72dde 100644 --- a/src/Mod/Path/PathScripts/PathDressupPathBoundary.py +++ b/src/Mod/Path/PathScripts/PathDressupPathBoundary.py @@ -32,8 +32,8 @@ import PathScripts.PathUtils as PathUtils from PySide import QtCore -PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) -PathLog.trackModule(PathLog.thisModule()) +PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +#PathLog.trackModule(PathLog.thisModule()) def _vstr(v): if v: @@ -45,8 +45,8 @@ class DressupPathBoundary(object): def __init__(self, obj, base, job): obj.addProperty("App::PropertyLink", "Base", "Base", QtCore.QT_TRANSLATE_NOOP("Path_DressupPathBoundary", "The base path to modify")) obj.Base = base - obj.addProperty("App::PropertyLink", "Boundary", "Boundary", QtCore.QT_TRANSLATE_NOOP("Path_DressupPathBoundary", "Solid object to be used to limit the generated Path.")) - obj.Boundary = PathStock.CreateFromBase(job) + obj.addProperty("App::PropertyLink", "Stock", "Boundary", QtCore.QT_TRANSLATE_NOOP("Path_DressupPathBoundary", "Solid object to be used to limit the generated Path.")) + obj.Stock = PathStock.CreateFromBase(job) obj.addProperty("App::PropertyBool", "Inside", "Boundary", QtCore.QT_TRANSLATE_NOOP("Path_DressupPathBoundary", "Determines if Boundary describes an inclusion or exclusion mask.")) obj.Inside = True @@ -63,9 +63,16 @@ class DressupPathBoundary(object): self.obj = obj def onDelete(self, obj, args): - if obj.Boundary: - obj.Document.removeObject(obj.Boundary.Name) - obj.Boundary = None + if obj.Base: + job = PathUtils.findParentJob(obj) + job.Proxy.addOperation(obj.Base, obj) + if obj.Base.ViewObject: + ob.Base.ViewObject.Visibility = True + obj.Base = None + if obj.Stock: + obj.Document.removeObject(obj.Stock.Name) + obj.Stock = None + return True def boundaryCommands(self, obj, begin, end): PathLog.track(_vstr(begin), _vstr(end)) @@ -92,7 +99,7 @@ class DressupPathBoundary(object): self.safeHeight = float(PathUtil.opProperty(obj.Base, 'SafeHeight')) self.clearanceHeight = float(PathUtil.opProperty(obj.Base, 'ClearanceHeight')) - boundary = obj.Boundary.Shape + boundary = obj.Stock.Shape cmd = obj.Base.Path.Commands[0] pos = cmd.Placement.Base commands = [cmd] @@ -124,7 +131,7 @@ class DressupPathBoundary(object): pos = PathGeom.commandEndPoint(cmd, pos) else: PathLog.track(_vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd) - # cmd pierces Boundary + # cmd pierces boundary while inside or outside: ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)] PathLog.track(ie) @@ -188,5 +195,5 @@ def Create(base, name='DressupPathBoundary'): obj = FreeCAD.ActiveDocument.addObject('Path::FeaturePython', name) job = PathUtils.findParentJob(base) obj.Proxy = DressupPathBoundary(obj, base, job) - job.Proxy.addOperation(obj, base) + job.Proxy.addOperation(obj, base, True) return obj diff --git a/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py b/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py index 27541e4f52..1e17ffad0b 100644 --- a/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py +++ b/src/Mod/Path/PathScripts/PathDressupPathBoundaryGui.py @@ -24,6 +24,7 @@ import FreeCAD import FreeCADGui import PathScripts.PathDressupPathBoundary as PathDressupPathBoundary +import PathScripts.PathJobGui as PathJobGui import PathScripts.PathLog as PathLog from PySide import QtGui, QtCore @@ -42,12 +43,26 @@ class TaskPanel(object): self.obj = obj self.viewProvider = viewProvider self.form = FreeCADGui.PySideUic.loadUi(':/panels/DressupPathBoundary.ui') - self.visibilityBase = obj.Base.ViewObject.Visibility if obj.Base else None - self.visibilityBoundary = obj.Boundary.ViewObject.Visibility if obj.Boundary else None + if obj.Stock: + self.visibilityBoundary = obj.Stock.ViewObject.Visibility + obj.Stock.ViewObject.Visibility = True + else: + self.visibilityBoundary = False + + self.stockFromBase = None + self.stockFromExisting = None + self.stockCreateBox = None + self.stockCreateCylinder = None + self.stockEdit = None def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel) + def clicked(self, button): + # callback for standard buttons + if button == QtGui.QDialogButtonBox.Apply: + self.obj.Proxy.execute(self.obj) + def abort(self): FreeCAD.ActiveDocument.abortTransaction() self.cleanup(False) @@ -69,18 +84,74 @@ class TaskPanel(object): FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() - if self.obj.Base: - self.obj.Base.ViewObject.Visibility = self.visibilityBase - if self.obj.Boundary: - self.obj.Boundary.ViewObject.Visibility = self.visibilityBoundary + if self.obj.Stock: + self.obj.Stock.ViewObject.Visibility = self.visibilityBoundary def getFields(self): pass def setFields(self): pass + def updateStockEditor(self, index, force=False): + import PathScripts.PathStock as PathStock + + def setupFromBaseEdit(): + PathLog.track(index, force) + if force or not self.stockFromBase: + self.stockFromBase = PathJobGui.StockFromBaseBoundBoxEdit(self.obj, self.form, force) + self.stockEdit = self.stockFromBase + + def setupCreateBoxEdit(): + PathLog.track(index, force) + if force or not self.stockCreateBox: + self.stockCreateBox = PathJobGui.StockCreateBoxEdit(self.obj, self.form, force) + self.stockEdit = self.stockCreateBox + + def setupCreateCylinderEdit(): + PathLog.track(index, force) + if force or not self.stockCreateCylinder: + self.stockCreateCylinder = PathJobGui.StockCreateCylinderEdit(self.obj, self.form, force) + self.stockEdit = self.stockCreateCylinder + + def setupFromExisting(): + PathLog.track(index, force) + if force or not self.stockFromExisting: + self.stockFromExisting = PathJobGui.StockFromExistingEdit(self.obj, self.form, force) + if self.stockFromExisting.candidates(self.obj): + self.stockEdit = self.stockFromExisting + return True + return False + + if index == -1: + if self.obj.Stock is None or PathJobGui.StockFromBaseBoundBoxEdit.IsStock(self.obj): + setupFromBaseEdit() + elif PathJobGui.StockCreateBoxEdit.IsStock(self.obj): + setupCreateBoxEdit() + elif PathJobGui.StockCreateCylinderEdit.IsStock(self.obj): + setupCreateCylinderEdit() + elif PathJobGui.StockFromExistingEdit.IsStock(self.obj): + setupFromExisting() + else: + PathLog.error(translate('PathJob', "Unsupported stock object %s") % self.obj.Stock.Label) + else: + if index == PathJobGui.StockFromBaseBoundBoxEdit.Index: + setupFromBaseEdit() + elif index == PathJobGui.StockCreateBoxEdit.Index: + setupCreateBoxEdit() + elif index == PathJobGui.StockCreateCylinderEdit.Index: + setupCreateCylinderEdit() + elif index == PathJobGui.StockFromExistingEdit.Index: + if not setupFromExisting(): + setupFromBaseEdit() + index = -1 + else: + PathLog.error(translate('PathJob', "Unsupported stock type %s (%d)") % (self.form.stock.currentText(), index)) + self.stockEdit.activate(self.obj, index == -1) + def setupUi(self): - pass + self.updateStockEditor(-1, False) + + self.form.stock.currentIndexChanged.connect(self.updateStockEditor) class DressupPathBoundaryViewProvider(object): @@ -100,10 +171,11 @@ class DressupPathBoundaryViewProvider(object): self.panel = None def claimChildren(self): - return [self.obj.Base, self.obj.Boundary] + return [self.obj.Base, self.obj.Stock] def onDelete(self, vobj, args=None): vobj.Object.Proxy.onDelete(vobj.Object, args) + return True def setEdit(self, vobj, mode=0): panel = TaskPanel(vobj.Object, self) @@ -128,6 +200,8 @@ def Create(base, name='DressupPathBoundary'): FreeCAD.ActiveDocument.openTransaction(translate('Path_DressupPathBoundary', 'Create a Boundary dressup')) obj = PathDressupPathBoundary.Create(base, name) obj.ViewObject.Proxy = DressupPathBoundaryViewProvider(obj.ViewObject) + obj.Base.ViewObject.Visibility = False + obj.Stock.ViewObject.Visibility = False FreeCAD.ActiveDocument.commitTransaction() obj.ViewObject.Document.setEdit(obj.ViewObject, 0) return obj diff --git a/src/Mod/Path/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py index 9d559d6f09..509bb7d72b 100644 --- a/src/Mod/Path/PathScripts/PathJob.py +++ b/src/Mod/Path/PathScripts/PathJob.py @@ -344,12 +344,14 @@ class ObjectJob: def execute(self, obj): obj.Path = obj.Operations.Path - def addOperation(self, op, before = None): + def addOperation(self, op, before = None, removeBefore = False): group = self.obj.Operations.Group if op not in group: if before: try: group.insert(group.index(before), op) + if removeBefore: + group.remove(before) except Exception as e: # pylint: disable=broad-except PathLog.error(e) group.append(op) diff --git a/src/Mod/Path/PathScripts/PathJobGui.py b/src/Mod/Path/PathScripts/PathJobGui.py index 2c6107d711..186b2066bd 100644 --- a/src/Mod/Path/PathScripts/PathJobGui.py +++ b/src/Mod/Path/PathScripts/PathJobGui.py @@ -527,12 +527,16 @@ class StockFromExistingEdit(StockEdit): def candidates(self, obj): solids = [o for o in obj.Document.Objects if PathUtil.isSolid(o)] - for base in obj.Model.Group: - if base in solids and PathJob.isResourceClone(obj, base, 'Model'): + if hasattr(obj, 'Model'): + job = obj + else: + job = PathUtils.findParentJob(obj) + for base in job.Model.Group: + if base in solids and PathJob.isResourceClone(job, base, 'Model'): solids.remove(base) - if obj.Stock in solids: + if job.Stock in solids: # regardless, what stock is/was, it's not a valid choice - solids.remove(obj.Stock) + solids.remove(job.Stock) return sorted(solids, key=lambda c: c.Label) def setFields(self, obj): diff --git a/src/Mod/Path/PathScripts/PathStock.py b/src/Mod/Path/PathScripts/PathStock.py index 50e4e96e43..7cabb4f7ff 100644 --- a/src/Mod/Path/PathScripts/PathStock.py +++ b/src/Mod/Path/PathScripts/PathStock.py @@ -233,9 +233,22 @@ def SetupStockObject(obj, stockType): obj.ViewObject.Transparency = 90 obj.ViewObject.DisplayMode = 'Wireframe' +class FakeJob(object): + def __init__(self, base): + self.Group = [base] + +def _getBase(job): + if job and hasattr(job, 'Model'): + return job.Model + if job: + import PathScripts.PathUtils as PathUtils + job = PathUtils.findParentJob(job) + return job.Model if job else None + return None + def CreateFromBase(job, neg=None, pos=None, placement=None): PathLog.track(job.Label, neg, pos, placement) - base = job.Model if job else None + base = _getBase(job) obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Stock') obj.Proxy = StockFromBase(obj, base) @@ -258,7 +271,7 @@ def CreateFromBase(job, neg=None, pos=None, placement=None): return obj def CreateBox(job, extent=None, placement=None): - base = job.Model if job else None + base = _getBase(job) obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Stock') obj.Proxy = StockCreateBox(obj) @@ -283,7 +296,7 @@ def CreateBox(job, extent=None, placement=None): return obj def CreateCylinder(job, radius=None, height=None, placement=None): - base = job.Model if job else None + base = _getBase(job) obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Stock') obj.Proxy = StockCreateCylinder(obj)