From a796427f706b5aa5ab5cd4d2228441d093996ba9 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Fri, 22 Sep 2017 16:40:55 -0700 Subject: [PATCH] Added manual locking of start and final depths - and automatic updated if not. --- .../Gui/Resources/panels/PageDepthsEdit.ui | 128 +++++++++++------- src/Mod/Path/PathScripts/PathAreaOp.py | 45 ++---- src/Mod/Path/PathScripts/PathOp.py | 54 ++++++-- src/Mod/Path/PathScripts/PathOpGui.py | 38 +++++- 4 files changed, 164 insertions(+), 101 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui index fc838f466f..d44736b3f2 100644 --- a/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui @@ -14,27 +14,20 @@ Form - - - - Start Depth + + + + <html><head/><body><p>Start Depth of the operation. The highest point in Z-axis the operation needs to process.</p></body></html> - + <html><head/><body><p>The depth of the operation which corresponds to the lowest value in Z-axis the operation needs to process.</p></body></html> - - - - <html><head/><body><p>Depth of the final cut of the operation. Can be used to produce a cleaner finish.</p></body></html> - - - @@ -42,6 +35,62 @@ + + + + <html><head/><body><p>Depth of the final cut of the operation. Can be used to produce a cleaner finish.</p></body></html> + + + + + + + ... + + + + :/icons/button_left.svg:/icons/button_left.svg + + + + + + + ... + + + + :/icons/button_left.svg:/icons/button_left.svg + + + + + + + Start Depth + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>The depth in Z-axis the operation moves downwards between layers.</p><p><br/></p><p>This value depends on the tool being used, the material to be cut, available cooling and many other factors. Please consult the tool manufacturers data sheets for the proper value.</p></body></html> + + + @@ -56,55 +105,32 @@ - - + + - <html><head/><body><p>The depth in Z-axis the operation moves downwards between layers.</p><p><br/></p><p>This value depends on the tool being used, the material to be cut, available cooling and many other factors. Please consult the tool manufacturers data sheets for the proper value.</p></body></html> + <html><head/><body><p>Lock Start Depth to specified value, prevent automatic recalculation.</p></body></html> + + + + + + false - + - <html><head/><body><p>Start Depth of the operation. The highest point in Z-axis the operation needs to process.</p></body></html> + <html><head/><body><p>Lock Start Depth to specified value, prevent automatic recalculation.</p></body></html> - - - - - ... + - - - :/icons/button_left.svg:/icons/button_left.svg + + false - - - - ... - - - - :/icons/button_left.svg:/icons/button_left.svg - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -119,6 +145,10 @@ finalDepth finishDepth stepDown + startDepthSet + finalDepthSet + startDepthLock + finalDepthLock diff --git a/src/Mod/Path/PathScripts/PathAreaOp.py b/src/Mod/Path/PathScripts/PathAreaOp.py index 92588986e8..47d56b611d 100644 --- a/src/Mod/Path/PathScripts/PathAreaOp.py +++ b/src/Mod/Path/PathScripts/PathAreaOp.py @@ -112,42 +112,17 @@ class ObjectOp(PathOp.ObjectOp): if prop in ['AreaParams', 'PathParams', 'removalshape']: obj.setEditorMode(prop, 2) - if PathOp.FeatureBaseGeometry & self.opFeatures(obj): - if prop == 'Base' and len(obj.Base) == 1: - PathLog.debug("opOnChanged(%s, %s)" % (obj.Label, prop)) - try: - (base, sub) = obj.Base[0] - bb = base.Shape.BoundBox # parent boundbox - subobj = base.Shape.getElement(sub[0]) - fbb = subobj.BoundBox # feature boundbox - obj.StartDepth = bb.ZMax - obj.ClearanceHeight = bb.ZMax + 5.0 - obj.SafeHeight = bb.ZMax + 3.0 + if prop == 'Base' and len(obj.Base) == 1: + (base, sub) = obj.Base[0] + bb = base.Shape.BoundBox # parent boundbox + subobj = base.Shape.getElement(sub[0]) + fbb = subobj.BoundBox # feature boundbox - if fbb.ZMax == fbb.ZMin and fbb.ZMax == bb.ZMax: # top face - obj.FinalDepth = bb.ZMin - elif fbb.ZMax > fbb.ZMin and fbb.ZMax == bb.ZMax: # vertical face, full cut - obj.FinalDepth = fbb.ZMin - elif fbb.ZMax > fbb.ZMin and fbb.ZMin > bb.ZMin: # internal vertical wall - obj.FinalDepth = fbb.ZMin - elif fbb.ZMax == fbb.ZMin and fbb.ZMax > bb.ZMin: # face/shelf - obj.FinalDepth = fbb.ZMin - else: # catch all - obj.FinalDepth = bb.ZMin - - if hasattr(obj, 'Side'): - if bb.XLength == fbb.XLength and bb.YLength == fbb.YLength: - obj.Side = "Outside" - else: - obj.Side = "Inside" - - except Exception as e: - PathLog.error(translate("PatArea", "Error in calculating depths: %s") % e) - obj.StartDepth = 5.0 - obj.ClearanceHeight = 10.0 - obj.SafeHeight = 8.0 - if hasattr(obj, 'Side'): - obj.Side = "Outside" + if hasattr(obj, 'Side'): + if bb.XLength == fbb.XLength and bb.YLength == fbb.YLength: + obj.Side = "Outside" + else: + obj.Side = "Inside" self.areaOpOnChanged(obj, prop) diff --git a/src/Mod/Path/PathScripts/PathOp.py b/src/Mod/Path/PathScripts/PathOp.py index 1b11895da3..2b8459d5ad 100644 --- a/src/Mod/Path/PathScripts/PathOp.py +++ b/src/Mod/Path/PathScripts/PathOp.py @@ -117,6 +117,8 @@ class ObjectOp(object): if FeatureDepths & features: obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Starting Depth of Tool- first cut depth in Z")) obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Final Depth of Tool- lowest value in Z")) + obj.addProperty("App::PropertyBool", "StartDepthLock", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "If enabled Start Depth will not be automatically updated when geometry changes")) + obj.addProperty("App::PropertyBool", "FinalDepthLock", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "If enabled Final Depth will not be automatically updated when geometry changes")) if FeatureNoFinalDepth & features: obj.setEditorMode('FinalDepth', 2) # hide @@ -148,6 +150,13 @@ class ObjectOp(object): obj.Base = base obj.touch() obj.Document.recompute() + if FeatureDepths & self.opFeatures(ojb): + if not hasattr(obj, 'StartDepthLock'): + obj.addProperty("App::PropertyBool", "StartDepthLock", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "If enabled Start Depth will not be automatically updated when geometry changes")) + obj.StartDepthLock = False + if not hasattr(obj, 'FinalDepthLock'): + obj.addProperty("App::PropertyBool", "FinalDepthLock", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "If enabled Final Depth will not be automatically updated when geometry changes")) + obj.FinalDepthLock = False def __getstate__(self): '''__getstat__(self) ... called when receiver is saved. @@ -198,6 +207,10 @@ class ObjectOp(object): def onChanged(self, obj, prop): '''onChanged(obj, prop) ... base implementation of the FC notification framework. Do not overwrite, overwrite opOnChanged() instead.''' + + if not 'Restore' in obj.State and prop in ['Base','StartDepth', 'StartDepthLock', 'FinalDepth', 'FinalDepthLock']: + self.updateDepths(obj) + self.opOnChanged(obj, prop) def setDefaultValues(self, obj): @@ -214,7 +227,9 @@ class ObjectOp(object): if FeatureDepths & features: obj.StartDepth = 1.0 + obj.StartDepthLock = False obj.FinalDepth = 0.0 + obj.FinalDepthLock = False if FeatureStepDown & features: obj.StepDown = 1.0 @@ -228,6 +243,17 @@ class ObjectOp(object): self.opSetDefaultValues(obj) + def _setBaseAndStock(self, obj): + job = PathUtils.findParentJob(obj) + if not job: + PathLog.error(translate("Path", "No parent job found for operation.")) + return + if not job.Base: + PathLog.error(translate("Path", "Parent job %s doesn't have a base object") % job.Label) + return + self.baseobject = job.Base + self.stock = job.Stock + def updateDepths(self, obj): '''updateDepths(obj) ... base implementation calculating depths depending on base geometry. Can safely be overwritten.''' @@ -246,7 +272,8 @@ class ObjectOp(object): zmin = -sys.maxint zmax = -sys.maxint - if hasattr(obj, 'Base'): + self._setBaseAndStock(obj) + if hasattr(obj, 'Base') and obj.Base: for base, sublist in obj.Base: bb = base.Shape.BoundBox zmax = max(zmax, bb.ZMax) @@ -266,10 +293,19 @@ class ObjectOp(object): else: zmax = zmin + 1 + safeDepths = True if hasattr(obj, 'StartDepth') and not PathGeom.isRoughly(obj.StartDepth.Value, zmax): - obj.StartDepth = zmax + if obj.StartDepthLock: + if obj.StartDepth.Value < zmax: + safeDepths = False + else: + obj.StartDepth = zmax if hasattr(obj, 'FinalDepth') and not PathGeom.isRoughly(obj.FinalDepth.Value, zmin): - obj.FinalDepth = zmin + if obj.FinalDepthLock: + if obj.FinalDepth.Value < zmin: + safeDepths = False + else: + obj.FinalDepth = zmin clearance = obj.StartDepth.Value + 5.0 safe = obj.StartDepth.Value + 3 @@ -278,6 +314,8 @@ class ObjectOp(object): if hasattr(obj, 'SafeHeight') and not PathGeom.isRoughly(safe, obj.SafeHeight.Value): obj.SafeHeight = safe + return safeDepths + @waiting_effects def execute(self, obj): '''execute(obj) ... base implementation - do not overwrite! @@ -308,15 +346,7 @@ class ObjectOp(object): obj.ViewObject.Visibility = False return - job = PathUtils.findParentJob(obj) - if not job: - PathLog.error(translate("Path", "No parent job found for operation.")) - return - if not job.Base: - PathLog.error(translate("Path", "Parent job %s doesn't have a base object") % job.Label) - return - self.baseobject = job.Base - self.stock = job.Stock + self._setBaseAndStock(obj) if FeatureTool & self.opFeatures(obj): tc = obj.ToolController diff --git a/src/Mod/Path/PathScripts/PathOpGui.py b/src/Mod/Path/PathScripts/PathOpGui.py index 5f7559cd3d..9e1c142f6c 100644 --- a/src/Mod/Path/PathScripts/PathOpGui.py +++ b/src/Mod/Path/PathScripts/PathOpGui.py @@ -283,12 +283,16 @@ class TaskPanelPage(object): if obj.ToolController != tc: obj.ToolController = tc - def updateInputField(self, obj, prop, widget): + def updateInputField(self, obj, prop, widget, onBeforeChange = None): '''updateInputField(obj, prop, widget) ... helper function to update obj's property named prop with the value from widget, if it has changed.''' value = FreeCAD.Units.Quantity(widget.text()).Value if getattr(obj, prop) != value: PathLog.debug("updateInputField(%s, %s): %.2f -> %.2f" % (obj.Label, prop, getattr(obj, prop), value)) + if onBeforeChange: + onBeforeChange(obj) setattr(obj, prop, value) + return True + return False class TaskPanelBaseGeometryPage(TaskPanelPage): '''Page controller for the base geometry.''' @@ -543,10 +547,12 @@ class TaskPanelDepthsPage(TaskPanelPage): '''Page controller for depths.''' def getForm(self): return FreeCADGui.PySideUic.loadUi(":/panels/PageDepthsEdit.ui") + def initPage(self, obj): if PathOp.FeatureNoFinalDepth & self.features: self.form.finalDepth.hide() self.form.finalDepthLabel.hide() + self.form.finalDepthLock.hide() self.form.finalDepthSet.hide() if not PathOp.FeatureStepDown & self.features: @@ -556,47 +562,69 @@ class TaskPanelDepthsPage(TaskPanelPage): if not PathOp.FeatureFinishDepth & self.features: self.form.finishDepth.hide() self.form.finishDepthLabel.hide() + def getTitle(self, obj): return translate("PathOp", "Depths") + + def lockStartDepth(self, obj): + if not obj.StartDepthLock: + obj.StartDepthLock = True + def lockFinalDepth(self, obj): + if not obj.FinalDepthLock: + obj.FinalDepthLock = True + def getFields(self, obj): - self.updateInputField(obj, 'StartDepth', self.form.startDepth) + if obj.StartDepthLock != self.form.startDepthLock.isChecked(): + obj.StartDepthLock = self.form.startDepthLock.isChecked() + if obj.FinalDepthLock != self.form.finalDepthLock.isChecked(): + obj.FinalDepthLock = self.form.finalDepthLock.isChecked() + + self.updateInputField(obj, 'StartDepth', self.form.startDepth, self.lockStartDepth) if not PathOp.FeatureNoFinalDepth & self.features: - self.updateInputField(obj, 'FinalDepth', self.form.finalDepth) + self.updateInputField(obj, 'FinalDepth', self.form.finalDepth, self.lockFinalDepth) if PathOp.FeatureStepDown & self.features: self.updateInputField(obj, 'StepDown', self.form.stepDown) if PathOp.FeatureFinishDepth & self.features: self.updateInputField(obj, 'FinishDepth', self.form.finishDepth) + def setFields(self, obj): self.form.startDepth.setText(FreeCAD.Units.Quantity(obj.StartDepth.Value, FreeCAD.Units.Length).UserString) + self.form.startDepthLock.setChecked(obj.StartDepthLock) if not PathOp.FeatureNoFinalDepth & self.features: self.form.finalDepth.setText(FreeCAD.Units.Quantity(obj.FinalDepth.Value, FreeCAD.Units.Length).UserString) + self.form.finalDepthLock.setChecked(obj.FinalDepthLock) if PathOp.FeatureStepDown & self.features: self.form.stepDown.setText(FreeCAD.Units.Quantity(obj.StepDown.Value, FreeCAD.Units.Length).UserString) if PathOp.FeatureFinishDepth & self.features: self.form.finishDepth.setText(FreeCAD.Units.Quantity(obj.FinishDepth.Value, FreeCAD.Units.Length).UserString) self.updateSelection(obj, FreeCADGui.Selection.getSelectionEx()) + def getSignalsForUpdate(self, obj): signals = [] signals.append(self.form.startDepth.editingFinished) + signals.append(self.form.startDepthLock.clicked) if not PathOp.FeatureNoFinalDepth & self.features: signals.append(self.form.finalDepth.editingFinished) + signals.append(self.form.finalDepthLock.clicked) if PathOp.FeatureStepDown & self.features: signals.append(self.form.stepDown.editingFinished) if PathOp.FeatureFinishDepth & self.features: signals.append(self.form.finishDepth.editingFinished) return signals + def registerSignalHandlers(self, obj): self.form.startDepthSet.clicked.connect(lambda: self.depthSet(obj, self.form.startDepth)) if not PathOp.FeatureNoFinalDepth & self.features: self.form.finalDepthSet.clicked.connect(lambda: self.depthSet(obj, self.form.finalDepth)) + def pageUpdateData(self, obj, prop): - if prop in ['StartDepth', 'FinalDepth', 'StepDown', 'FinishDepth']: + if prop in ['StartDepth', 'FinalDepth', 'StepDown', 'FinishDepth', 'FinalDepthLock', 'StartDepthLock']: self.setFields(obj) def depthSet(self, obj, widget): z = self.selectionZLevel(FreeCADGui.Selection.getSelectionEx()) if z is not None: - PathLog.info("depthSet(%.2f)" % z) + PathLog.debug("depthSet(%.2f)" % z) widget.setText(FreeCAD.Units.Quantity(z, FreeCAD.Units.Length).UserString) self.getFields(obj) else: