diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index e3c39dda22..cc7428b255 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -57,6 +57,8 @@ SET(PathScripts_SRCS PathScripts/PathPocketBase.py PathScripts/PathPocketBaseGui.py PathScripts/PathPocketGui.py + PathScripts/PathPocketShape.py + PathScripts/PathPocketShapeGui.py PathScripts/PathPost.py PathScripts/PathPostProcessor.py PathScripts/PathPreferences.py diff --git a/src/Mod/Path/InitGui.py b/src/Mod/Path/InitGui.py index 219fe76f00..0580e979ae 100644 --- a/src/Mod/Path/InitGui.py +++ b/src/Mod/Path/InitGui.py @@ -61,6 +61,7 @@ class PathWorkbench (Workbench): from PathScripts import PathMillFaceGui from PathScripts import PathPlane from PathScripts import PathPocketGui + from PathScripts import PathPocketShapeGui from PathScripts import PathPost from PathScripts import PathProfileContourGui from PathScripts import PathProfileEdgesGui @@ -78,7 +79,7 @@ class PathWorkbench (Workbench): projcmdlist = ["Path_Job", "Path_Post", "Path_Inspect", "Path_Sanity"] toolcmdlist = ["Path_ToolLibraryEdit"] prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment", "Path_Stop", "Path_Custom", "Path_Shape"] - twodopcmdlist = ["Path_Contour", "Path_Profile_Faces", "Path_Profile_Edges", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"] + twodopcmdlist = ["Path_Contour", "Path_Profile_Faces", "Path_Profile_Edges", "Path_Pocket_Shape", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"] threedopcmdlist = ["Path_Pocket", "Path_Surfacing"] modcmdlist = ["Path_OperationCopy", "Path_Array", "Path_SimpleCopy" ] dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_Tag", "PathDressup_RampEntry"] diff --git a/src/Mod/Path/PathScripts/PathPocketShape.py b/src/Mod/Path/PathScripts/PathPocketShape.py new file mode 100644 index 0000000000..f603048c53 --- /dev/null +++ b/src/Mod/Path/PathScripts/PathPocketShape.py @@ -0,0 +1,139 @@ +# -*- 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 Part +import PathScripts.PathLog as PathLog +import PathScripts.PathOp as PathOp +import PathScripts.PathPocketBase as PathPocketBase +import PathScripts.PathUtils as PathUtils +import sys + +from PathScripts.PathGeom import PathGeom +from PySide import QtCore + +__title__ = "Path Pocket Shape Operation" +__author__ = "sliptonic (Brad Collette)" +__url__ = "http://www.freecadweb.org" +__doc__ = "Class and implementation of shape based Pocket operation." + +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + +# Qt tanslation handling +def translate(context, text, disambig=None): + return QtCore.QCoreApplication.translate(context, text, disambig) + + +class ObjectPocket(PathPocketBase.ObjectPocket): + '''Proxy object for Pocket operation.''' + + def initPocketOp(self, obj): + '''initPocketOp(obj) ... setup receiver''' + pass + + def pocketInvertExtraOffset(self): + return False + + def areaOpShapes(self, obj): + '''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' + PathLog.track() + + if obj.Base: + PathLog.debug("base items exist. Processing...") + removalshapes = [] + for b in obj.Base: + PathLog.debug("Base item: {}".format(b)) + for sub in b[1]: + if "Face" in sub: + shape = Part.makeCompound([getattr(b[0].Shape, sub)]) + else: + edges = [getattr(b[0].Shape, sub) for sub in b[1]] + shape = Part.makeFace(edges, 'Part::FaceMakerSimple') + + env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=shape, depthparams=self.depthparams) + obj.removalshape = env.cut(self.baseobject.Shape) + obj.removalshape.tessellate(0.1) + removalshapes.append((obj.removalshape, False)) + else: # process the job base object as a whole + PathLog.debug("processing the whole job base object") + + env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=None, depthparams=self.depthparams) + obj.removalshape = env.cut(self.baseobject.Shape) + obj.removalshape.tessellate(0.1) + removalshapes = [(obj.removalshape, False)] + return removalshapes + + def areaOpSetDefaultValues(self, obj): + '''areaOpSetDefaultValues(obj) ... set default values''' + obj.StepOver = 100 + obj.ZigZagAngle = 45 + + def areaOpOnChanged(self, obj, prop): + if 'Base' == prop and obj.Base and not 'Restore' in obj.State: + PathLog.track(obj.Label, prop) + zmin = -sys.maxint + zmax = zmin + for base, sublist in obj.Base: + bb = base.Shape.BoundBox # parent boundbox + for sub in sublist: + subobj = base.Shape.getElement(sub) + fbb = subobj.BoundBox # feature boundbox + + if fbb.ZMax == fbb.ZMin and fbb.ZMax == bb.ZMax: # top face + finalDepth = bb.ZMin + elif fbb.ZMax > fbb.ZMin and fbb.ZMax == bb.ZMax: # vertical face, full cut + finalDepth = fbb.ZMin + elif fbb.ZMax > fbb.ZMin and fbb.ZMin > bb.ZMin: # internal vertical wall + finalDepth = fbb.ZMin + elif fbb.ZMax == fbb.ZMin and fbb.ZMax > bb.ZMin: # face/shelf + finalDepth = fbb.ZMin + else: # catch all + finalDepth = bb.ZMin + + zmin = max(zmin, finalDepth) + zmax = max(zmax, bb.ZMax) + PathLog.debug("%s: final=%.2f, max=%.2f" % (sub, zmin, zmax)) + + PathLog.debug("zmin=%.2f, zmax=%.2f" % (zmin, zmax)) + if not PathGeom.isRoughly(zmin, obj.FinalDepth.Value): + obj.FinalDepth = zmin + if not PathGeom.isRoughly(zmax, obj.StartDepth.Value): + obj.StartDepth = zmax + clearance = zmax + 5.0 + safe = zmax + 3 + if not PathGeom.isRoughly(clearance, obj.ClearanceHeight.Value): + obj.CearanceHeight = clearance + if not PathGeom.isRoughly(safe, obj.SafeHeight.Value): + obj.SafeHeight = safe + + +def Create(name): + '''Create(name) ... Creates and returns a Pocket operation.''' + obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) + proxy = ObjectPocket(obj) + return obj diff --git a/src/Mod/Path/PathScripts/PathPocketShapeGui.py b/src/Mod/Path/PathScripts/PathPocketShapeGui.py new file mode 100644 index 0000000000..399f105f24 --- /dev/null +++ b/src/Mod/Path/PathScripts/PathPocketShapeGui.py @@ -0,0 +1,51 @@ +# -*- 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 PathScripts.PathOpGui as PathOpGui +import PathScripts.PathPocket as PathPocket +import PathScripts.PathPocketBaseGui as PathPocketBaseGui + +from PySide import QtCore + +__title__ = "Path Pocket Shape Operation UI" +__author__ = "sliptonic (Brad Collette)" +__url__ = "http://www.freecadweb.org" +__doc__ = "Pocket Shape operation page controller and command implementation." + +class TaskPanelOpPage(PathPocketBaseGui.TaskPanelOpPage): + '''Page controller class for Pocket operation''' + + def pocketFeatures(self): + '''pocketFeatures() ... return FeaturePocket (see PathPocketBaseGui)''' + return PathPocketBaseGui.FeaturePocket + +Command = PathOpGui.SetupOperation('Pocket Shape', + PathPocket.Create, + TaskPanelOpPage, + 'Path-Pocket', + QtCore.QT_TRANSLATE_NOOP("PathPocket", "Pocket Shape"), + QtCore.QT_TRANSLATE_NOOP("PathPocket", "Creates a Path Pocket object from a face or faces")) + +FreeCAD.Console.PrintLog("Loading PathPocketShapeGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py index 269900f549..5bb5c89f7e 100644 --- a/src/Mod/Path/PathScripts/PathSelection.py +++ b/src/Mod/Path/PathScripts/PathSelection.py @@ -168,6 +168,7 @@ def select(op): opsel['Helix'] = drillselect opsel['MillFace'] = pocketselect opsel['Pocket'] = pocketselect + opsel['Pocket Shape'] = pocketselect opsel['Profile Edges'] = eselect opsel['Profile Faces'] = profileselect opsel['Surface'] = surfaceselect