From 0d4bc71a6591b2fa9e3f6ff3c209c53088774e37 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Mon, 7 Aug 2017 13:22:32 -0700 Subject: [PATCH] Moved base functionality into PathOp and renamed AreaOp interface to areaOp... --- src/Mod/Path/CMakeLists.txt | 1 + src/Mod/Path/PathScripts/PathAreaOp.py | 154 +++------------ src/Mod/Path/PathScripts/PathAreaOpGui.py | 22 +-- src/Mod/Path/PathScripts/PathMillFace.py | 22 +-- src/Mod/Path/PathScripts/PathMillFaceGui.py | 1 - src/Mod/Path/PathScripts/PathOp.py | 185 ++++++++++++++++++ src/Mod/Path/PathScripts/PathPocket.py | 18 +- src/Mod/Path/PathScripts/PathPocketBaseGui.py | 1 - src/Mod/Path/PathScripts/PathPocketGui.py | 2 - src/Mod/Path/PathScripts/PathProfileBase.py | 34 ++-- .../Path/PathScripts/PathProfileBaseGui.py | 5 +- .../Path/PathScripts/PathProfileContour.py | 21 +- src/Mod/Path/PathScripts/PathProfileEdges.py | 15 +- src/Mod/Path/PathScripts/PathProfileFaces.py | 25 ++- src/Mod/Path/PathScripts/PathSelection.py | 2 +- 15 files changed, 289 insertions(+), 219 deletions(-) create mode 100644 src/Mod/Path/PathScripts/PathOp.py diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index e17286f475..38bfac0e23 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -47,6 +47,7 @@ SET(PathScripts_SRCS PathScripts/PathLog.py PathScripts/PathMillFace.py PathScripts/PathMillFaceGui.py + PathScripts/PathOp.py PathScripts/PathPlane.py PathScripts/PathPocket.py PathScripts/PathPocketBaseGui.py diff --git a/src/Mod/Path/PathScripts/PathAreaOp.py b/src/Mod/Path/PathScripts/PathAreaOp.py index 8f33ce7734..42a2dff5cb 100644 --- a/src/Mod/Path/PathScripts/PathAreaOp.py +++ b/src/Mod/Path/PathScripts/PathAreaOp.py @@ -25,6 +25,7 @@ import FreeCAD import Path import PathScripts.PathLog as PathLog +import PathScripts.PathOp as PathOp import PathScripts.PathUtils as PathUtils from PathScripts.PathUtils import depth_params @@ -43,48 +44,14 @@ PathLog.trackModule() def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) -FeatureTool = 0x0001 -FeatureDepths = 0x0002 -FeatureHeights = 0x0004 -FeatureStartPoint = 0x0008 -FeatureFinishDepth = 0x0010 -FeatureBaseFaces = 0x1001 -FeatureBaseEdges = 0x1002 -FeatureBasePanels = 0x1002 +class ObjectOp(PathOp.ObjectOp): -FeatureBaseGeometry = FeatureBaseFaces | FeatureBaseEdges | FeatureBasePanels + def opFeatures(self, obj): + return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureHeights | PathOp.FeatureStartPoint | self.areaOpFeatures(obj) -class ObjectOp(object): - - def __init__(self, obj): + def initOperation(self, obj): PathLog.track() - obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Make False, to prevent operation from generating code")) - obj.addProperty("App::PropertyString", "Comment", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "An optional comment for this Operation")) - obj.addProperty("App::PropertyString", "UserLabel", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "User Assigned Label")) - - if FeatureBaseGeometry & self.opFeatures(obj): - obj.addProperty("App::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base geometry for this operation")) - - if FeatureTool & self.opFeatures(obj): - obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path")) - - if FeatureDepths & self.opFeatures(obj): - obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool")) - 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")) - - if FeatureFinishDepth & self.opFeatures(obj): - obj.addProperty("App::PropertyDistance", "FinishDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum material removed on final pass.")) - - if FeatureHeights & self.opFeatures(obj): - obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height needed to clear clamps and obstructions")) - obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid Safety Height between locations.")) - - if FeatureStartPoint & self.opFeatures(obj): - obj.addProperty("App::PropertyVector", "StartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The start point of this path")) - obj.addProperty("App::PropertyBool", "UseStartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if specifying a Start Point")) - # Debugging obj.addProperty("App::PropertyString", "AreaParams", "Path") obj.setEditorMode('AreaParams', 2) # hide @@ -93,23 +60,9 @@ class ObjectOp(object): obj.addProperty("Part::PropertyPartShape", "removalshape", "Path") obj.setEditorMode('removalshape', 2) # hide - self.initOperation(obj) - obj.Proxy = self - self.setDefaultValues(obj) + self.initAreaOp(obj) - def __getstate__(self): - return None - - def __setstate__(self, state): - return None - - def opFeatures(self, obj): - return FeatureTool | FeatureDepths | FeatureHeights | FeatureStartPoint | FeatureBaseGeometry | FeatureFinishDepth - def opOnChanged(self, obj, prop): - pass - def opSetDefaultValues(self, obj): - pass - def opShapeForDepths(self, obj): + def areaOpShapeForDepths(self, obj): job = PathUtils.findParentJob(obj) if job and job.Base: PathLog.debug("job=%s base=%s shape=%s" % (job, job.Base, job.Base.Shape)) @@ -120,13 +73,15 @@ class ObjectOp(object): PathLog.warning(translate("PathAreaOp", "no job for op %s found.") % obj.Label) return None - - def onChanged(self, obj, prop): + def areaOpOnChanged(self, obj, prop): + pass + + def opOnChanged(self, obj, prop): #PathLog.track(obj.Label, prop) if prop in ['AreaParams', 'PathParams', 'removalshape']: obj.setEditorMode(prop, 2) - if FeatureBaseGeometry & self.opFeatures(obj): + if PathOp.FeatureBaseGeometry & self.opFeatures(obj): if prop == 'Base' and len(obj.Base) == 1: try: (base, sub) = obj.Base[0] @@ -162,19 +117,12 @@ class ObjectOp(object): if hasattr(obj, 'Side'): obj.Side = "Outside" - self.opOnChanged(obj, prop) + self.areaOpOnChanged(obj, prop) - def setDefaultValues(self, obj): - PathUtils.addToJob(obj) - - obj.Active = True - - if FeatureTool & self.opFeatures(obj): - obj.ToolController = PathUtils.findToolController(obj) - - if FeatureDepths & self.opFeatures(obj): + def opSetDefaultValues(self, obj): + if PathOp.FeatureDepths & self.opFeatures(obj): try: - shape = self.opShapeForDepths(obj) + shape = self.areaOpShapeForDepths(obj) except: shape = None @@ -188,9 +136,9 @@ class ObjectOp(object): obj.FinalDepth = 0.0 obj.StepDown = 1.0 - if FeatureHeights & self.opFeatures(obj): + if PathOp.FeatureHeights & self.opFeatures(obj): try: - shape = self.opShapeForDepths(obj) + shape = self.areaOpShapeForDepths(obj) except: shape = None @@ -202,19 +150,15 @@ class ObjectOp(object): obj.ClearanceHeight = 10.0 obj.SafeHeight = 8.0 - if FeatureStartPoint & self.opFeatures(obj): - obj.UseStartPoint = False + self.areaOpSetDefaultValues(obj) - self.opSetDefaultValues(obj) - - @waiting_effects def _buildPathArea(self, obj, baseobject, isHole, start, getsim): PathLog.track() area = Path.Area() area.setPlane(makeWorkplane(baseobject)) area.add(baseobject) - areaParams = self.opAreaParams(obj, isHole) + areaParams = self.areaOpAreaParams(obj, isHole) heights = [i for i in self.depthparams] PathLog.debug('depths: {}'.format(heights)) @@ -223,12 +167,12 @@ class ObjectOp(object): PathLog.debug("Area with params: {}".format(area.getParams())) - sections = area.makeSections(mode=0, project=self.opUseProjection(obj), heights=heights) + sections = area.makeSections(mode=0, project=self.areaOpUseProjection(obj), heights=heights) PathLog.debug("sections = %s" % sections) shapelist = [sec.getShape() for sec in sections] PathLog.debug("shapelist = %s" % shapelist) - pathParams = self.opPathParams(obj, isHole) + pathParams = self.areaOpPathParams(obj, isHole) pathParams['shapes'] = shapelist pathParams['feedrate'] = self.horizFeed pathParams['feedrate_v'] = self.vertFeed @@ -259,17 +203,10 @@ class ObjectOp(object): return pp, simobj - def execute(self, obj, getsim=False): + def opExecute(self, obj, getsim=False): PathLog.track() self.endVector = None - if not obj.Active: - path = Path.Path("(inactive operation)") - obj.Path = path - if obj.ViewObject: - obj.ViewObject.Visibility = False - return - self.depthparams = depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, @@ -279,60 +216,21 @@ class ObjectOp(object): final_depth=obj.FinalDepth.Value, user_depths=None) - toolLoad = obj.ToolController - if toolLoad is None or toolLoad.ToolNumber == 0: - - FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") - return - else: - self.vertFeed = toolLoad.VertFeed.Value - self.horizFeed = toolLoad.HorizFeed.Value - self.vertRapid = toolLoad.VertRapid.Value - self.horizRapid = toolLoad.HorizRapid.Value - tool = toolLoad.Proxy.getTool(toolLoad) - if not tool or tool.Diameter == 0: - FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") - return - else: - self.radius = tool.Diameter/2 - - if FeatureStartPoint and obj.UseStartPoint: + if PathOp.FeatureStartPoint and obj.UseStartPoint: start = obj.StartPoint else: start = FreeCAD.Vector() - commandlist = [] - commandlist.append(Path.Command("(" + obj.Label + ")")) - - shapes = self.opShapes(obj, commandlist) + shapes = self.areaOpShapes(obj) sims = [] for (shape, isHole) in shapes: try: (pp, sim) = self._buildPathArea(obj, shape, isHole, start, getsim) - commandlist.extend(pp.Commands) + self.commandlist.extend(pp.Commands) sims.append(sim) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Check project and tool config.") - - # Let's finish by rapid to clearance...just for safety - commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) - - PathLog.track() - path = Path.Path(commandlist) - obj.Path = path return sims - - def addBase(self, obj, base, sub=""): - PathLog.track() - baselist = obj.Base - if baselist is None: - baselist = [] - item = (base, sub) - if item in baselist: - PathLog.warning(translate("Path", "this object already in the list" + "\n")) - else: - baselist.append(item) - obj.Base = baselist diff --git a/src/Mod/Path/PathScripts/PathAreaOpGui.py b/src/Mod/Path/PathScripts/PathAreaOpGui.py index 0c6948a393..a9a07f9a1e 100644 --- a/src/Mod/Path/PathScripts/PathAreaOpGui.py +++ b/src/Mod/Path/PathScripts/PathAreaOpGui.py @@ -24,10 +24,10 @@ import FreeCAD import FreeCADGui -import Path import PathScripts.PathAreaOp as PathAreaOp import PathScripts.PathLog as PathLog import PathScripts.PathSelection as PathSelection +import PathScripts.PathOp as PathOp import importlib from PathScripts import PathUtils @@ -176,7 +176,7 @@ class TaskPanelBaseGeometryPage(TaskPanelPage): DataObjectSub = QtCore.Qt.ItemDataRole.UserRole + 1 def initPage(self, obj): - self.supports = PathAreaOp.FeatureBaseGeometry + self.supports = PathOp.FeatureBaseGeometry def getForm(self): return FreeCADGui.PySideUic.loadUi(":/panels/PageBaseGeometryEdit.ui") @@ -205,11 +205,11 @@ class TaskPanelBaseGeometryPage(TaskPanelPage): #FreeCADGui.updateGui() def supportsEdges(self): - return self.supports & PathAreaOp.FeatureBaseEdges + return self.supports & PathOp.FeatureBaseEdges def supportsFaces(self): - return self.supports & PathAreaOp.FeatureBaseFaces + return self.supports & PathOp.FeatureBaseFaces def supportsPanels(self): - return self.supports & PathAreaOp.FeatureBasePanels + return self.supports & PathOp.FeatureBasePanels def featureName(self): if self.supportsEdges() and self.supportsFaces(): @@ -341,19 +341,19 @@ class TaskPanel(object): self.deleteOnReject = deleteOnReject self.featurePages = [] - if PathAreaOp.FeatureBaseGeometry & obj.Proxy.opFeatures(obj): + if PathOp.FeatureBaseGeometry & obj.Proxy.opFeatures(obj): basePage = TaskPanelBaseGeometryPage(obj) - basePage.supports = obj.Proxy.opFeatures(obj) & PathAreaOp.FeatureBaseGeometry + basePage.supports = obj.Proxy.opFeatures(obj) & PathOp.FeatureBaseGeometry self.featurePages.append(basePage) - if PathAreaOp.FeatureDepths & obj.Proxy.opFeatures(obj): - if PathAreaOp.FeatureFinishDepth & obj.Proxy.opFeatures(obj): + if PathOp.FeatureDepths & obj.Proxy.opFeatures(obj): + if PathOp.FeatureFinishDepth & obj.Proxy.opFeatures(obj): depthPage = TaskPanelDepthsPage(obj) else: depthPage = TaskPanelDepthsWoFinishPage(obj) self.featurePages.append(depthPage) - if PathAreaOp.FeatureHeights & obj.Proxy.opFeatures(obj): + if PathOp.FeatureHeights & obj.Proxy.opFeatures(obj): self.featurePages.append(TaskPanelHeightsPage(obj)) opPage.setTitle(translate('PathAreaOp', 'Operation')) @@ -441,7 +441,7 @@ class TaskPanel(object): def setupUi(self): PathLog.track(self.deleteOnReject) - if self.deleteOnReject and PathAreaOp.FeatureBaseGeometry & self.obj.Proxy.opFeatures(self.obj): + if self.deleteOnReject and PathOp.FeatureBaseGeometry & self.obj.Proxy.opFeatures(self.obj): sel = FreeCADGui.Selection.getSelectionEx() if len(sel) == 1 and sel[0].Object != self.obj: for page in self.featurePages: diff --git a/src/Mod/Path/PathScripts/PathMillFace.py b/src/Mod/Path/PathScripts/PathMillFace.py index 03d97730fa..f3c2985a63 100644 --- a/src/Mod/Path/PathScripts/PathMillFace.py +++ b/src/Mod/Path/PathScripts/PathMillFace.py @@ -26,9 +26,9 @@ from __future__ import print_function import FreeCAD import Part -import Path import PathScripts.PathAreaOp as PathAreaOp import PathScripts.PathLog as PathLog +import PathScripts.PathOp as PathOp import PathScripts.PathUtils as PathUtils from PySide import QtCore, QtGui @@ -56,10 +56,10 @@ __url__ = "http://www.freecadweb.org" class ObjectFace(PathAreaOp.ObjectOp): - def opFeatures(self, obj): - return PathAreaOp.FeatureTool | PathAreaOp.FeatureDepths | PathAreaOp.FeatureHeights | PathAreaOp.FeatureStartPoint | PathAreaOp.FeatureBaseFaces | PathAreaOp.FeatureFinishDepth + def areaOpFeatures(self, obj): + return PathOp.FeatureBaseFaces | PathOp.FeatureFinishDepth - def initOperation(self, obj): + def initAreaOp(self, obj): # Face Properties obj.addProperty("App::PropertyEnumeration", "CutMode", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW")) @@ -78,7 +78,7 @@ class ObjectFace(PathAreaOp.ObjectOp): obj.OffsetPattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle'] - def opOnChanged(self, obj, prop): + def areaOpOnChanged(self, obj, prop): PathLog.track(prop) if prop == "StepOver" and obj.StepOver == 0: obj.StepOver = 1 @@ -93,10 +93,10 @@ class ObjectFace(PathAreaOp.ObjectOp): obj.StartDepth = d.safe_height obj.FinalDepth = d.start_depth - def opUseProjection(self, obj): + def areaOpUseProjection(self, obj): return False - def opAreaParams(self, obj, isHole): + def areaOpAreaParams(self, obj, isHole): params = {} params['Fill'] = 0 params['Coplanar'] = 0 @@ -114,7 +114,7 @@ class ObjectFace(PathAreaOp.ObjectOp): return params - def opPathParams(self, obj, isHole): + def areaOpPathParams(self, obj, isHole): params = {} params['feedrate'] = self.horizFeed params['feedrate_v'] = self.vertFeed @@ -127,9 +127,7 @@ class ObjectFace(PathAreaOp.ObjectOp): return params - def opShapes(self, obj, commandlist): - commandlist.append(Path.Command("(" + obj.Label + ")")) - + def areaOpShapes(self, obj): # Facing is done either against base objects if obj.Base: PathLog.debug("obj.Base: {}".format(obj.Base)) @@ -165,7 +163,7 @@ class ObjectFace(PathAreaOp.ObjectOp): return [(env, False)] - def opSetDefaultValues(self, obj): + def areaOpSetDefaultValues(self, obj): obj.StepOver = 50 obj.ZigZagAngle = 45.0 diff --git a/src/Mod/Path/PathScripts/PathMillFaceGui.py b/src/Mod/Path/PathScripts/PathMillFaceGui.py index 21fa10d157..81968baa2d 100644 --- a/src/Mod/Path/PathScripts/PathMillFaceGui.py +++ b/src/Mod/Path/PathScripts/PathMillFaceGui.py @@ -24,7 +24,6 @@ import FreeCAD import FreeCADGui -import Path import PathScripts.PathAreaOpGui as PathAreaOpGui import PathScripts.PathMillFace as PathMillFace import PathScripts.PathPocketBaseGui as PathPocketBaseGui diff --git a/src/Mod/Path/PathScripts/PathOp.py b/src/Mod/Path/PathScripts/PathOp.py new file mode 100644 index 0000000000..129c9b53bb --- /dev/null +++ b/src/Mod/Path/PathScripts/PathOp.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- + +# *************************************************************************** +# * * +# * Copyright (c) 2017 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD +import Path +import PathScripts.PathLog as PathLog +import PathScripts.PathUtils as PathUtils + +from PathScripts.PathUtils import waiting_effects +from PySide import QtCore + +__title__ = "Base class for all operations." +__author__ = "sliptonic (Brad Collette)" +__url__ = "http://www.freecadweb.org" + +PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) +PathLog.trackModule() + +# Qt tanslation handling +def translate(context, text, disambig=None): + return QtCore.QCoreApplication.translate(context, text, disambig) + +FeatureTool = 0x0001 +FeatureDepths = 0x0002 +FeatureHeights = 0x0004 +FeatureStartPoint = 0x0008 +FeatureFinishDepth = 0x0010 +FeatureBaseFeatures = 0x1000 +FeatureBaseFaces = 0x2000 +FeatureBaseEdges = 0x4000 +FeatureBasePanels = 0x8000 + +FeatureBaseGeometry = FeatureBaseFeatures | FeatureBaseFaces | FeatureBaseEdges | FeatureBasePanels + +class ObjectOp(object): + + def __init__(self, obj): + PathLog.track() + + obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Make False, to prevent operation from generating code")) + obj.addProperty("App::PropertyString", "Comment", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "An optional comment for this Operation")) + obj.addProperty("App::PropertyString", "UserLabel", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "User Assigned Label")) + + if FeatureBaseGeometry & self.opFeatures(obj): + obj.addProperty("App::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base geometry for this operation")) + + if FeatureTool & self.opFeatures(obj): + obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path")) + + if FeatureDepths & self.opFeatures(obj): + obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool")) + 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")) + + if FeatureFinishDepth & self.opFeatures(obj): + obj.addProperty("App::PropertyDistance", "FinishDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum material removed on final pass.")) + + if FeatureHeights & self.opFeatures(obj): + obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height needed to clear clamps and obstructions")) + obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid Safety Height between locations.")) + + if FeatureStartPoint & self.opFeatures(obj): + obj.addProperty("App::PropertyVector", "StartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The start point of this path")) + obj.addProperty("App::PropertyBool", "UseStartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if specifying a Start Point")) + + self.initOperation(obj) + + obj.Proxy = self + self.setDefaultValues(obj) + + def __getstate__(self): + return None + + def __setstate__(self, state): + return None + + def opFeatures(self, obj): + return FeatureTool | FeatureDepths | FeatureHeights | FeatureStartPoint | FeatureBaseGeometry | FeatureFinishDepth + def opOnChanged(self, obj, prop): + pass + def opSetDefaultValues(self, obj): + pass + + def onChanged(self, obj, prop): + self.opOnChanged(obj, prop) + + def setDefaultValues(self, obj, callOp = True): + PathUtils.addToJob(obj) + + obj.Active = True + + if FeatureTool & self.opFeatures(obj): + obj.ToolController = PathUtils.findToolController(obj) + + if FeatureDepths & self.opFeatures(obj): + obj.StartDepth = 1.0 + obj.FinalDepth = 0.0 + obj.StepDown = 1.0 + + if FeatureHeights & self.opFeatures(obj): + obj.ClearanceHeight = 10.0 + obj.SafeHeight = 8.0 + + if FeatureStartPoint & self.opFeatures(obj): + obj.UseStartPoint = False + + self.opSetDefaultValues(obj) + + @waiting_effects + def execute(self, obj): + PathLog.track() + + if not obj.Active: + path = Path.Path("(inactive operation)") + obj.Path = path + if obj.ViewObject: + obj.ViewObject.Visibility = False + return + + tc = obj.ToolController + if tc is None or tc.ToolNumber == 0: + FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") + return + else: + self.vertFeed = tc.VertFeed.Value + self.horizFeed = tc.HorizFeed.Value + self.vertRapid = tc.VertRapid.Value + self.horizRapid = tc.HorizRapid.Value + tool = tc.Proxy.getTool(tc) + if not tool or tool.Diameter == 0: + FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") + return + else: + self.radius = tool.Diameter/2 + + if FeatureStartPoint and obj.UseStartPoint: + start = obj.StartPoint + else: + start = FreeCAD.Vector() + + self.commandlist = [] + self.commandlist.append(Path.Command("(" + obj.Label + ")")) + + result = self.opExecute(obj) + + # Let's finish by rapid to clearance...just for safety + self.commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) + + path = Path.Path(self.commandlist) + obj.Path = path + return result + + def addBase(self, obj, base, sub): + PathLog.track() + baselist = obj.Base + if baselist is None: + baselist = [] + item = (base, sub) + if item in baselist: + PathLog.notice(translate("Path", "this object already in the list" + "\n")) + else: + baselist.append(item) + obj.Base = baselist + diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py index 8813c92cd1..240305f8ba 100644 --- a/src/Mod/Path/PathScripts/PathPocket.py +++ b/src/Mod/Path/PathScripts/PathPocket.py @@ -24,9 +24,9 @@ import FreeCAD import Part -import Path import PathScripts.PathAreaOp as PathAreaOp import PathScripts.PathLog as PathLog +import PathScripts.PathOp as PathOp from PathScripts import PathUtils from PySide import QtCore @@ -46,10 +46,10 @@ def translate(context, text, disambig=None): class ObjectPocket(PathAreaOp.ObjectOp): - def opFeatures(self, obj): - return PathAreaOp.FeatureTool | PathAreaOp.FeatureDepths | PathAreaOp.FeatureHeights | PathAreaOp.FeatureStartPoint | PathAreaOp.FeatureBaseFaces | PathAreaOp.FeatureFinishDepth + def areaOpFeatures(self, obj): + return PathOp.FeatureBaseFaces | PathOp.FeatureFinishDepth - def initOperation(self, obj): + def initAreaOp(self, obj): PathLog.track() # Pocket Properties @@ -64,10 +64,10 @@ class ObjectPocket(PathAreaOp.ObjectOp): obj.OffsetPattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle'] obj.addProperty("App::PropertyBool", "MinTravel", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Use 3D Sorting of Path")) - def opUseProjection(self, obj): + def areaOpUseProjection(self, obj): return False - def opAreaParams(self, obj, isHole): + def areaOpAreaParams(self, obj, isHole): params = {} params['Fill'] = 0 params['Coplanar'] = 0 @@ -83,7 +83,7 @@ class ObjectPocket(PathAreaOp.ObjectOp): params['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1 return params - def opPathParams(self, obj, isHole): + def areaOpPathParams(self, obj, isHole): params = {} # if MinTravel is turned on, set path sorting to 3DSort @@ -93,7 +93,7 @@ class ObjectPocket(PathAreaOp.ObjectOp): params['sort_mode'] = 2 return params - def opShapes(self, obj, commandlist): + def areaOpShapes(self, obj): PathLog.track() job = PathUtils.findParentJob(obj) @@ -124,7 +124,7 @@ class ObjectPocket(PathAreaOp.ObjectOp): removalshapes = [(obj.removalshape, False)] return removalshapes - def opSetDefaultValues(self, obj): + def areaOpSetDefaultValues(self, obj): obj.StepOver = 100 obj.ZigZagAngle = 45 diff --git a/src/Mod/Path/PathScripts/PathPocketBaseGui.py b/src/Mod/Path/PathScripts/PathPocketBaseGui.py index da1c009488..a71e35df5e 100644 --- a/src/Mod/Path/PathScripts/PathPocketBaseGui.py +++ b/src/Mod/Path/PathScripts/PathPocketBaseGui.py @@ -24,7 +24,6 @@ import FreeCAD import FreeCADGui -import Path import PathScripts.PathAreaOpGui as PathAreaOpGui import PathScripts.PathLog as PathLog import PathScripts.PathPocket as PathPocket diff --git a/src/Mod/Path/PathScripts/PathPocketGui.py b/src/Mod/Path/PathScripts/PathPocketGui.py index 4e46d9875b..6067e33693 100644 --- a/src/Mod/Path/PathScripts/PathPocketGui.py +++ b/src/Mod/Path/PathScripts/PathPocketGui.py @@ -23,8 +23,6 @@ # *************************************************************************** import FreeCAD -import FreeCADGui -import Path import PathScripts.PathAreaOpGui as PathAreaOpGui import PathScripts.PathPocket as PathPocket import PathScripts.PathPocketBaseGui as PathPocketBaseGui diff --git a/src/Mod/Path/PathScripts/PathProfileBase.py b/src/Mod/Path/PathScripts/PathProfileBase.py index e7c84ff14a..70de5030ee 100644 --- a/src/Mod/Path/PathScripts/PathProfileBase.py +++ b/src/Mod/Path/PathScripts/PathProfileBase.py @@ -23,11 +23,9 @@ # *************************************************************************** import FreeCAD -import Part -import Path import PathScripts.PathAreaOp as PathAreaOp -import PathScripts.PathUtils as PathUtils import PathScripts.PathLog as PathLog +import PathScripts.PathOp as PathOp from PySide import QtCore @@ -57,10 +55,7 @@ __url__ = "http://www.freecadweb.org" class ObjectProfile(PathAreaOp.ObjectOp): - def opFeatures(self, obj): - return PathAreaOp.FeatureTool | PathAreaOp.FeatureDepths | PathAreaOp.FeatureHeights | PathAreaOp.FeatureStartPoint - - def initOperation(self, obj): + def initAreaOp(self, obj): # Profile Properties obj.addProperty("App::PropertyEnumeration", "Side", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Side of edge that tool should cut")) obj.Side = ['Outside', 'Inside'] # side of profile that cutter is on in relation to direction of profile @@ -74,9 +69,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): obj.addProperty("App::PropertyFloat", "MiterLimit", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum distance before a miter join is truncated")) obj.setEditorMode('MiterLimit', 2) - obj.Proxy = self - - def onOpChanged(self, obj, prop): + def areaOpOnChanged(self, obj, prop): if prop == "UseComp": if not obj.UseComp: obj.setEditorMode('Side', 2) @@ -89,19 +82,20 @@ class ObjectProfile(PathAreaOp.ObjectOp): else: obj.setEditorMode('MiterLimit', 2) - def opAreaParams(self, obj, isHole): + def areaOpAreaParams(self, obj, isHole): params = {} params['Fill'] = 0 params['Coplanar'] = 0 params['SectionCount'] = -1 + offset = 0.0 if obj.UseComp: - if obj.Side == 'Inside': - params['Offset'] = 0 - self.radius+obj.OffsetExtra.Value - else: - params['Offset'] = self.radius+obj.OffsetExtra.Value - else: - params['Offset'] = 0.0 + offset = self.radius + obj.OffsetExtra.Value + if obj.Side == 'Inside': + offset = 0 - offset + if isHole: + offset = 0 - offset + params['Offset'] = offset jointype = ['Round', 'Square', 'Miter'] params['JoinType'] = jointype.index(obj.JoinType) @@ -111,7 +105,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): return params - def opPathParams(self, obj, isHole): + def areaOpPathParams(self, obj, isHole): params = {} # Reverse the direction for holes @@ -127,10 +121,10 @@ class ObjectProfile(PathAreaOp.ObjectOp): return params - def opUseProjection(self, obj): + def areaOpUseProjection(self, obj): return True - def opSetDefaultValues(self, obj): + def areaOpSetDefaultValues(self, obj): obj.Side = "Outside" obj.OffsetExtra = 0.0 obj.Direction = "CW" diff --git a/src/Mod/Path/PathScripts/PathProfileBaseGui.py b/src/Mod/Path/PathScripts/PathProfileBaseGui.py index 9dd6d05cd5..127bb5b411 100644 --- a/src/Mod/Path/PathScripts/PathProfileBaseGui.py +++ b/src/Mod/Path/PathScripts/PathProfileBaseGui.py @@ -24,14 +24,13 @@ import FreeCAD import FreeCADGui -import Path import PathScripts.PathAreaOpGui as PathAreaOpGui import PathScripts.PathLog as PathLog import PathScripts.PathProfileFaces as PathProfileFaces import PathScripts.PathSelection as PathSelection +import PathScripts.PathUtils as PathUtils -from PathScripts import PathUtils -from PySide import QtCore, QtGui +from PySide import QtCore def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) diff --git a/src/Mod/Path/PathScripts/PathProfileContour.py b/src/Mod/Path/PathScripts/PathProfileContour.py index 98600acce3..a4bbb3b49b 100644 --- a/src/Mod/Path/PathScripts/PathProfileContour.py +++ b/src/Mod/Path/PathScripts/PathProfileContour.py @@ -59,19 +59,22 @@ class ObjectContour(PathProfileBase.ObjectProfile): def baseObject(self): return super(self.__class__, self) - def initOperation(self, obj): - self.baseObject().initOperation(obj) + def areaOpFeatures(self, obj): + return 0 + + def initAreaOp(self, obj): + self.baseObject().initAreaOp(obj) obj.setEditorMode('Side', 2) # it's always outside - def opSetDefaultValues(self, obj): - self.baseObject().opSetDefaultValues(obj) + def areaOpSetDefaultValues(self, obj): + self.baseObject().areaOpSetDefaultValues(obj) obj.Side = 'Outside' - def opShapes(self, obj, commandlist): + def areaOpShapes(self, obj): if obj.UseComp: - commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) + self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: - commandlist.append(Path.Command("(Uncompensated Tool Path)")) + self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) job = PathUtils.findParentJob(obj) @@ -95,8 +98,8 @@ class ObjectContour(PathProfileBase.ObjectProfile): if hasattr(baseobject, "Shape") and not isPanel: return [(PathUtils.getEnvelope(partshape=baseobject.Shape, subshape=None, depthparams=self.depthparams), False)] - def opAreaParams(self, obj, isHole): - params = self.baseObject().opAreaParams(obj, isHole) + def areaOpAreaParams(self, obj, isHole): + params = self.baseObject().areaOpAreaParams(obj, isHole) params['Coplanar'] = 2 return params diff --git a/src/Mod/Path/PathScripts/PathProfileEdges.py b/src/Mod/Path/PathScripts/PathProfileEdges.py index 6162090815..025f7ac6b0 100644 --- a/src/Mod/Path/PathScripts/PathProfileEdges.py +++ b/src/Mod/Path/PathScripts/PathProfileEdges.py @@ -26,9 +26,10 @@ import FreeCAD import Part import Path import PathScripts.PathAreaOp as PathAreaOp +import PathScripts.PathLog as PathLog +import PathScripts.PathOp as PathOp import PathScripts.PathProfileBase as PathProfileBase import PathScripts.PathUtils as PathUtils -import PathScripts.PathLog as PathLog from DraftGeomUtils import findWires from PySide import QtCore @@ -62,10 +63,10 @@ class ObjectProfile(PathProfileBase.ObjectProfile): def baseObject(self): return super(self.__class__, self) - def opFeatures(self, obj): - return self.baseObject().opFeatures(obj) | PathAreaOp.FeatureBaseEdges + def areaOpFeatures(self, obj): + return PathOp.FeatureBaseEdges - def opShapes(self, obj, commandlist): + def areaOpShapes(self, obj): PathLog.track() job = PathUtils.findParentJob(obj) @@ -73,12 +74,10 @@ class ObjectProfile(PathProfileBase.ObjectProfile): return baseobject = job.Base - commandlist.append(Path.Command("(" + obj.Label + ")")) - if obj.UseComp: - commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) + self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: - commandlist.append(Path.Command("(Uncompensated Tool Path)")) + self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] if obj.Base: diff --git a/src/Mod/Path/PathScripts/PathProfileFaces.py b/src/Mod/Path/PathScripts/PathProfileFaces.py index e34666ede9..7ec188f32c 100644 --- a/src/Mod/Path/PathScripts/PathProfileFaces.py +++ b/src/Mod/Path/PathScripts/PathProfileFaces.py @@ -27,8 +27,9 @@ import FreeCAD import Part import Path import PathScripts.PathAreaOp as PathAreaOp -import PathScripts.PathProfileBase as PathProfileBase import PathScripts.PathLog as PathLog +import PathScripts.PathOp as PathOp +import PathScripts.PathProfileBase as PathProfileBase import PathScripts.PathUtils as PathUtils import numpy @@ -54,33 +55,29 @@ class ObjectProfile(PathProfileBase.ObjectProfile): def baseObject(self): return super(self.__class__, self) - def initOperation(self, obj): - self.baseObject().initOperation(obj) - + def initAreaOp(self, obj): # Face specific Properties obj.addProperty("App::PropertyBool", "processHoles", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile holes as well as the outline")) obj.addProperty("App::PropertyBool", "processPerimeter", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile the outline")) obj.addProperty("App::PropertyBool", "processCircles", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile round holes")) - obj.Proxy = self + self.baseObject().initAreaOp(obj) - def opSetDefaultValues(self, obj): - self.baseObject().opSetDefaultValues(obj) + def areaOpSetDefaultValues(self, obj): + self.baseObject().areaOpSetDefaultValues(obj) obj.processHoles = False obj.processCircles = False obj.processPerimeter = True - def opFeatures(self, obj): - return self.baseObject().opFeatures(obj) | PathAreaOp.FeatureBaseFaces - - def opShapes(self, obj, commandlist): - commandlist.append(Path.Command("(" + obj.Label + ")")) + def areaOpFeatures(self, obj): + return PathOp.FeatureBaseFaces + def areaOpShapes(self, obj): if obj.UseComp: - commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) + self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: - commandlist.append(Path.Command("(Uncompensated Tool Path)")) + self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) job = PathUtils.findParentJob(obj) if not job or not job.Base: diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py index 753102d735..f0e89dd352 100644 --- a/src/Mod/Path/PathScripts/PathSelection.py +++ b/src/Mod/Path/PathScripts/PathSelection.py @@ -25,8 +25,8 @@ import FreeCAD import FreeCADGui -import PathScripts.PathUtils as PathUtils import PathScripts.PathLog as PathLog +import PathScripts.PathUtils as PathUtils LOG_MODULE = 'PathSelection' PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)