diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index 7534672003..01b3605e68 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -57,9 +57,10 @@ SET(PathScripts_SRCS PathScripts/PathPreferencesPathDressup.py PathScripts/PathPreferencesPathJob.py PathScripts/PathProfileBase.py + PathScripts/PathProfileEdges.py + PathScripts/PathProfileEdgesGui.py PathScripts/PathProfileFaces.py PathScripts/PathProfileFacesGui.py - PathScripts/PathProfileEdges.py PathScripts/PathSanity.py PathScripts/PathSelection.py PathScripts/PathSimpleCopy.py diff --git a/src/Mod/Path/Gui/Resources/Path.qrc b/src/Mod/Path/Gui/Resources/Path.qrc index efc9742cfd..ac791c3ce0 100644 --- a/src/Mod/Path/Gui/Resources/Path.qrc +++ b/src/Mod/Path/Gui/Resources/Path.qrc @@ -66,6 +66,7 @@ panels/PageHeightsEdit.ui panels/PageOpContourEdit.ui panels/PageOpPocketEdit.ui + panels/PageOpProfileEdgesEdit.ui panels/PageOpProfileFacesEdit.ui panels/PocketEdit.ui panels/PointEdit.ui diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpContourEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpContourEdit.ui index 18af8df671..c5634c1ce5 100644 --- a/src/Mod/Path/Gui/Resources/panels/PageOpContourEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PageOpContourEdit.ui @@ -7,14 +7,14 @@ 0 0 424 - 428 + 263 Form - - + + QFrame::StyledPanel @@ -36,50 +36,82 @@ - - - - Direction + + + + + + + Direction + + + + + + + + CW + + + + + CCW + + + + + + + + Extra Offset + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Use Start Point + + + + + + + Use Compensation + + + + + + + + + + Qt::Vertical - - - - - - - CW - - - - - CCW - - - - - - - - Use Start Point + + + 20 + 1 + - - - - - - Use Compensation - - - - - - - Extra Offset - - - - - + diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpProfileEdgesEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpProfileEdgesEdit.ui new file mode 100644 index 0000000000..914e41eb09 --- /dev/null +++ b/src/Mod/Path/Gui/Resources/panels/PageOpProfileEdgesEdit.ui @@ -0,0 +1,148 @@ + + + Form + + + + 0 + 0 + 400 + 298 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Tool Controller + + + + + + + + + + + + + + + + Cut Side + + + + + + + + Outside + + + + + Inside + + + + + + + + Direction + + + + + + + + CW + + + + + CCW + + + + + + + + Extra Offset + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Use Compensation + + + + + + + Use Start Point + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Gui::InputField + QLineEdit +
Gui/InputField.h
+
+
+ + +
diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpProfileFacesEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpProfileFacesEdit.ui index 44f8fa3791..3f32a4c7d8 100644 --- a/src/Mod/Path/Gui/Resources/panels/PageOpProfileFacesEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PageOpProfileFacesEdit.ui @@ -7,7 +7,7 @@ 0 0 446 - 419 + 342 diff --git a/src/Mod/Path/InitGui.py b/src/Mod/Path/InitGui.py index ed349176ed..9b32ce62b4 100644 --- a/src/Mod/Path/InitGui.py +++ b/src/Mod/Path/InitGui.py @@ -67,8 +67,8 @@ class PathWorkbench (Workbench): from PathScripts import PathPlane from PathScripts import PathPocketGui from PathScripts import PathPost + from PathScripts import PathProfileEdgesGui from PathScripts import PathProfileFacesGui - from PathScripts import PathProfileEdges from PathScripts import PathSanity from PathScripts import PathSimpleCopy from PathScripts import PathStock @@ -83,7 +83,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_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_Shape"] - twodopcmdlist = ["Path_Contour", "Path_Profile", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"] + twodopcmdlist = ["Path_Contour", "Path_Profile_Faces", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"] threedopcmdlist = ["Path_Surfacing"] modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ] dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_Tag", "PathDressup_RampEntry"] diff --git a/src/Mod/Path/PathScripts/PathAreaOpGui.py b/src/Mod/Path/PathScripts/PathAreaOpGui.py index e48f5b63d0..f14b377d70 100644 --- a/src/Mod/Path/PathScripts/PathAreaOpGui.py +++ b/src/Mod/Path/PathScripts/PathAreaOpGui.py @@ -529,7 +529,7 @@ def SetupOperation(name, toolTip): res = CommandResources(name, objFactory, opPageClass, pixmap, menuText, accelKey, toolTip) - FreeCADGui.addCommand("Path_%s" % name, CommandPathOp(res)) + FreeCADGui.addCommand("Path_%s" % name.replace(' ', '_'), CommandPathOp(res)) FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint()) diff --git a/src/Mod/Path/PathScripts/PathProfileEdges.py b/src/Mod/Path/PathScripts/PathProfileEdges.py index ea1e3f8240..6162090815 100644 --- a/src/Mod/Path/PathScripts/PathProfileEdges.py +++ b/src/Mod/Path/PathScripts/PathProfileEdges.py @@ -23,18 +23,19 @@ # *************************************************************************** import FreeCAD -import Path import Part -from PathScripts import PathUtils -from PathScripts.PathUtils import depth_params -from DraftGeomUtils import findWires -from DraftGeomUtils import isReallyClosed +import Path +import PathScripts.PathAreaOp as PathAreaOp +import PathScripts.PathProfileBase as PathProfileBase +import PathScripts.PathUtils as PathUtils import PathScripts.PathLog as PathLog -from PathScripts.PathUtils import waiting_effects + +from DraftGeomUtils import findWires +from PySide import QtCore """Path Profile from Edges Object and Command""" -if False: +if True: PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) PathLog.trackModule(PathLog.thisModule()) else: @@ -42,7 +43,7 @@ else: if FreeCAD.GuiUp: import FreeCADGui - from PySide import QtCore, QtGui + from PySide import QtGui # Qt tanslation handling @@ -56,213 +57,21 @@ __url__ = "http://www.freecadweb.org" """Path Profile object and FreeCAD command for operating on sets of edges""" -class ObjectProfile: +class ObjectProfile(PathProfileBase.ObjectProfile): - def __init__(self, obj): - obj.addProperty("App::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base geometry of this toolpath")) - 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 profile")) - obj.addProperty("App::PropertyString", "UserLabel", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "User Assigned Label")) + def baseObject(self): + return super(self.__class__, self) - # Tool Properties - obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path")) + def opFeatures(self, obj): + return self.baseObject().opFeatures(obj) | PathAreaOp.FeatureBaseEdges - # Depth Properties - 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::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool")) - - # Heights - obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid Safety Height between locations")) - obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height needed to clear clamps and obstructions")) - - # Start Point Properties - 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")) - - # 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 - obj.addProperty("App::PropertyEnumeration", "Direction", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW")) - obj.Direction = ['CW', 'CCW'] # this is the direction that the profile runs - obj.addProperty("App::PropertyBool", "UseComp", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if using Cutter Radius Compensation")) - - obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final profile- good for roughing toolpath")) - obj.addProperty("App::PropertyEnumeration", "JoinType", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Controls how tool moves around corners. Default=Round")) - obj.JoinType = ['Round', 'Square', 'Miter'] # this is the direction that the Contour runs - obj.addProperty("App::PropertyFloat", "MiterLimit", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum distance before a miter join is truncated")) - - - # Debug Parameters - obj.addProperty("App::PropertyString", "AreaParams", "Path") - obj.setEditorMode('AreaParams', 2) # hide - obj.addProperty("App::PropertyString", "PathParams", "Path") - obj.setEditorMode('PathParams', 2) # hide - obj.addProperty("Part::PropertyPartShape", "removalshape", "Path") - obj.setEditorMode('removalshape', 2) # hide - - if FreeCAD.GuiUp: - _ViewProviderProfile(obj.ViewObject) - - obj.Proxy = self - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None - - def onChanged(self, obj, prop): - if prop == "UseComp": - if not obj.UseComp: - obj.setEditorMode('Side', 2) - else: - obj.setEditorMode('Side', 0) - if prop in ['AreaParams', 'PathParams', 'removalshape']: - obj.setEditorMode(prop, 2) - - obj.setEditorMode('MiterLimit', 2) - if obj.JoinType == 'Miter': - obj.setEditorMode('MiterLimit', 0) - - - def addprofilebase(self, obj, ss, sub=""): - baselist = obj.Base - if len(baselist) == 0: # When adding the first base object, guess at heights - try: - bb = ss.Shape.BoundBox # parent boundbox - subobj = ss.Shape.getElement(sub) - fbb = subobj.BoundBox # feature boundbox - obj.StartDepth = bb.ZMax - obj.ClearanceHeight = bb.ZMax + 5.0 - obj.SafeHeight = bb.ZMax + 3.0 - - 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 - except: - obj.StartDepth = 5.0 - obj.ClearanceHeight = 10.0 - obj.SafeHeight = 8.0 - - item = (ss, sub) - if item in baselist: - FreeCAD.Console.PrintWarning("this object already in the list" + "\n") - else: - baselist.append(item) - obj.Base = baselist - - @waiting_effects - def _buildPathArea(self, obj, baseobject, start=None, getsim=False): + def opShapes(self, obj, commandlist): PathLog.track() - profile = Path.Area() - profile.setPlane(Part.makeCircle(10)) - profile.add(baseobject) - profileparams = {'Fill': 0, - 'Coplanar': 0, - 'Offset': 0.0, - 'SectionCount': -1} - - if obj.UseComp: - if obj.Side == 'Inside': - profileparams['Offset'] = 0 - self.radius+obj.OffsetExtra.Value - else: - profileparams['Offset'] = self.radius+obj.OffsetExtra.Value - - jointype = ['Round', 'Square', 'Miter'] - profileparams['JoinType'] = jointype.index(obj.JoinType) - - if obj.JoinType == 'Miter': - profileparams['MiterLimit'] = obj.MiterLimit - - profile.setParams(**profileparams) - obj.AreaParams = str(profile.getParams()) - - PathLog.debug("About to profile with params: {}".format(profile.getParams())) - - heights = [i for i in self.depthparams] - sections = profile.makeSections(mode=0, project=True, heights=heights) - shapelist = [sec.getShape() for sec in sections] - - params = {'shapes': shapelist, - 'feedrate': self.horizFeed, - 'feedrate_v': self.vertFeed, - 'verbose': False, - 'resume_height': obj.StepDown.Value, - 'retraction': obj.ClearanceHeight.Value} - - if obj.Direction == 'CCW': - params['orientation'] = 0 - else: - params['orientation'] = 1 - - if obj.UseStartPoint is True and obj.StartPoint is not None: - params['start'] = obj.StartPoint - - pp = Path.fromShapes(**params) - PathLog.debug("Generating Path with params: {}".format(params)) - - # store the params for debugging. Don't need the shape. - obj.PathParams = str({key: value for key, value in params.items() if key != 'shapes'}) - - simobj = None - if getsim: - profileparams['Thicken'] = True - profileparams['ToolRadius'] = self.radius - self.radius * .005 - profile.setParams(**profileparams) - sec = profile.makeSections(mode=0, project=False, heights=heights)[-1].getShape() - simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) - - return pp, simobj - - def execute(self, obj, getsim=False): - commandlist = [] - sim = None - - if not obj.Active: - path = Path.Path("(inactive operation)") - obj.Path = path - obj.ViewObject.Visibility = False + job = PathUtils.findParentJob(obj) + if not job or not job.Base: return - - parentJob = PathUtils.findParentJob(obj) - if parentJob is None: - return - baseobject = parentJob.Base - if baseobject is None: - return - - self.depthparams = depth_params( - clearance_height=obj.ClearanceHeight.Value, - safe_height=obj.SafeHeight.Value, - start_depth=obj.StartDepth.Value, - step_down=obj.StepDown.Value, - z_finish_step=0.0, - 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.") - 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 + baseobject = job.Base commandlist.append(Path.Command("(" + obj.Label + ")")) @@ -271,6 +80,7 @@ class ObjectProfile: else: commandlist.append(Path.Command("(Uncompensated Tool Path)")) + shapes = [] if obj.Base: wires = [] @@ -289,373 +99,10 @@ class ObjectProfile: newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), f.Placement.Rotation) f.Placement = newPlace env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) + shapes.append((env, False)) + return shapes - try: - (pp, sim) = self._buildPathArea(obj, baseobject=env, start=obj.StartPoint, getsim=getsim) - commandlist.extend(pp.Commands) - - except Exception as e: - FreeCAD.Console.PrintError(e) - FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") - - # Let's finish by rapid to clearance...just for safety - commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) - - path = Path.Path(commandlist) - obj.Path = path - return sim - - -class _ViewProviderProfile: - - def __init__(self, vobj): - vobj.Proxy = self - - def attach(self, vobj): - self.Object = vobj.Object - return - - def deleteObjectsOnReject(self): - return hasattr(self, 'deleteOnReject') and self.deleteOnReject - - def setEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - taskd = TaskPanel(vobj.Object, self.deleteObjectsOnReject()) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - taskd.setupUi() - self.deleteOnReject = False - return True - - def getIcon(self): - return ":/icons/Path-Profile.svg" - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None - - -class _CommandSetStartPoint: - def GetResources(self): - return {'Pixmap': 'Path-StartPoint', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick Start Point"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick Start Point")} - - def IsActive(self): - return FreeCAD.ActiveDocument is not None - - def setpoint(self, point, o): - obj = FreeCADGui.Selection.getSelection()[0] - obj.StartPoint.x = point.x - obj.StartPoint.y = point.y - - def Activated(self): - - FreeCADGui.Snapper.getPoint(callback=self.setpoint) - - -class _CommandSetEndPoint: - def GetResources(self): - return {'Pixmap': 'Path-EndPoint', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick End Point"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick End Point")} - - def IsActive(self): - return FreeCAD.ActiveDocument is not None - - def setpoint(self, point, o): - obj = FreeCADGui.Selection.getSelection()[0] - obj.EndPoint.x = point.x - obj.EndPoint.y = point.y - - def Activated(self): - - FreeCADGui.Snapper.getPoint(callback=self.setpoint) - - -class CommandPathProfileEdges: - def GetResources(self): - return {'Pixmap': 'Path-Profile-Edges', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathProfile", "Edge Profile"), - 'Accel': "P, F", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathProfile", "Profile based on Edges")} - - def IsActive(self): - if FreeCAD.ActiveDocument is not None: - for o in FreeCAD.ActiveDocument.Objects: - if o.Name[:3] == "Job": - return True - return False - - def Activated(self): - ztop = 10.0 - zbottom = 0.0 - - FreeCAD.ActiveDocument.openTransaction(translate("Path", "Create a Profile based on edge selection")) - FreeCADGui.addModule("PathScripts.PathProfile") - FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Edge Profile")') - FreeCADGui.doCommand('PathScripts.PathProfileEdges.ObjectProfile(obj)') - FreeCADGui.doCommand('obj.ViewObject.Proxy.deleteOnReject = True') - - FreeCADGui.doCommand('obj.Active = True') - - FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 10.0)) - FreeCADGui.doCommand('obj.StepDown = 1.0') - FreeCADGui.doCommand('obj.StartDepth= ' + str(ztop)) - FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom)) - - FreeCADGui.doCommand('obj.SafeHeight = ' + str(ztop + 2.0)) - FreeCADGui.doCommand('obj.Side = "Inside"') - FreeCADGui.doCommand('obj.OffsetExtra = 0.0') - FreeCADGui.doCommand('obj.Direction = "CW"') - FreeCADGui.doCommand('obj.UseComp = True') - - FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)') - FreeCADGui.doCommand('obj.ToolController = PathScripts.PathUtils.findToolController(obj)') - - FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() - FreeCADGui.doCommand('obj.ViewObject.startEditing()') - - -class TaskPanel: - def __init__(self, obj, deleteOnReject): - FreeCAD.ActiveDocument.openTransaction(translate("Path_ProfileEdges", "ProfileEdges Operation")) - self.form = FreeCADGui.PySideUic.loadUi(":/panels/ProfileEdgesEdit.ui") - self.deleteOnReject = deleteOnReject - self.obj = obj - self.isDirty = True - - def accept(self): - FreeCADGui.Control.closeDialog() - FreeCADGui.ActiveDocument.resetEdit() - FreeCAD.ActiveDocument.commitTransaction() - FreeCADGui.Selection.removeObserver(self.s) - if self.isDirty: - FreeCAD.ActiveDocument.recompute() - - def reject(self): - FreeCADGui.Control.closeDialog() - FreeCADGui.ActiveDocument.resetEdit() - FreeCAD.ActiveDocument.abortTransaction() - FreeCADGui.Selection.removeObserver(self.s) - if self.deleteOnReject: - FreeCAD.ActiveDocument.openTransaction(translate("Path_ProfileEdges", "Uncreate ProfileEdges Operation")) - FreeCAD.ActiveDocument.removeObject(self.obj.Name) - FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() - - def clicked(self, button): - if button == QtGui.QDialogButtonBox.Apply: - self.getFields() - self.obj.Proxy.execute(self.obj) - self.isDirty = False - - def getFields(self): - if self.obj: - - if hasattr(self.obj, "StartDepth"): - self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value - if hasattr(self.obj, "FinalDepth"): - self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value - if hasattr(self.obj, "StepDown"): - self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value - if hasattr(self.obj, "SafeHeight"): - self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value - if hasattr(self.obj, "ClearanceHeight"): - self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value - if hasattr(self.obj, "OffsetExtra"): - self.obj.OffsetExtra = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value - if hasattr(self.obj, "UseComp"): - self.obj.UseComp = self.form.useCompensation.isChecked() - if hasattr(self.obj, "Side"): - self.obj.Side = str(self.form.cutSide.currentText()) - if hasattr(self.obj, "Direction"): - self.obj.Direction = str(self.form.direction.currentText()) - if hasattr(self.obj, "UseStartPoint"): - self.obj.UseStartPoint = self.form.useStartPoint.isChecked() - - if hasattr(self.obj, "ToolController"): - PathLog.debug("name: {}".format(self.form.uiToolController.currentText())) - tc = PathUtils.findToolController(self.obj, self.form.uiToolController.currentText()) - self.obj.ToolController = tc - - self.isDirty = True - - def setFields(self): - self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString) - self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString) - self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown.Value, FreeCAD.Units.Length).UserString) - self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString) - self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString) - self.form.extraOffset.setText(FreeCAD.Units.Quantity(self.obj.OffsetExtra.Value, FreeCAD.Units.Length).UserString) - self.form.useCompensation.setChecked(self.obj.UseComp) - self.form.useStartPoint.setChecked(self.obj.UseStartPoint) - - controllers = PathUtils.getToolControllers(self.obj) - labels = [c.Label for c in controllers] - self.form.uiToolController.blockSignals(True) - self.form.uiToolController.addItems(labels) - self.form.uiToolController.blockSignals(False) - if self.obj.ToolController is not None: - index = self.form.uiToolController.findText( - self.obj.ToolController.Label, QtCore.Qt.MatchFixedString) - PathLog.debug("searching for TC label {}. Found Index: {}".format(self.obj.ToolController.Label, index)) - if index >= 0: - self.form.uiToolController.blockSignals(True) - self.form.uiToolController.setCurrentIndex(index) - self.form.uiToolController.blockSignals(False) - else: - self.obj.ToolController = PathUtils.findToolController(self.obj) - - index = self.form.cutSide.findText( - self.obj.Side, QtCore.Qt.MatchFixedString) - if index >= 0: - self.form.cutSide.blockSignals(True) - self.form.cutSide.setCurrentIndex(index) - self.form.cutSide.blockSignals(False) - - index = self.form.direction.findText( - self.obj.Direction, QtCore.Qt.MatchFixedString) - if index >= 0: - self.form.direction.setCurrentIndex(index) - self.form.baseList.blockSignals(True) - for i in self.obj.Base: - for sub in i[1]: - self.form.baseList.addItem(i[0].Name + "." + sub) - self.form.baseList.blockSignals(False) - - def open(self): - self.s = SelObserver() - # install the function mode resident - FreeCADGui.Selection.addObserver(self.s) - - def addBase(self): - # check that the selection contains exactly what we want - selection = FreeCADGui.Selection.getSelectionEx() - - if len(selection) != 1: - FreeCAD.Console.PrintError(translate("PathProject", "Please select only Edges from the Base model\n")) - return - sel = selection[0] - if not sel.HasSubObjects: - FreeCAD.Console.PrintError(translate("PathProject", "Please select one or more edges from the Base model\n")) - return - if not selection[0].SubObjects[0].ShapeType == "Edge": - FreeCAD.Console.PrintError(translate("PathProject", "Please select one or more edges from the Base model\n")) - return - try: - theWire = Part.Wire(sel.SubObjects) - except: - FreeCAD.Console.PrintError(translate("PathProject", "The selected edges don't form a closed loop\n")) - return - if not isReallyClosed(theWire): - FreeCAD.Console.PrintError(translate("PathProject", "The selected edges don't form a closed loop\n")) - return - - for i in sel.SubElementNames: - self.obj.Proxy.addprofilebase(self.obj, sel.Object, i) - - self.setFields() # defaults may have changed. Reload. - self.form.baseList.clear() - - for i in self.obj.Base: - for sub in i[1]: - self.form.baseList.addItem(i[0].Name + "." + sub) - - def deleteBase(self): - dlist = self.form.baseList.selectedItems() - newlist = [] - for d in dlist: - for i in self.obj.Base: - if i[0].Name != d.text().partition(".")[0] or i[1] != d.text().partition(".")[2]: - newlist.append(i) - self.form.baseList.takeItem(self.form.baseList.row(d)) - self.obj.Base = newlist - self.obj.Proxy.execute(self.obj) - FreeCAD.ActiveDocument.recompute() - - def itemActivated(self): - FreeCADGui.Selection.clearSelection() - slist = self.form.baseList.selectedItems() - for i in slist: - objstring = i.text().partition(".") - obj = FreeCAD.ActiveDocument.getObject(objstring[0]) - if objstring[2] != "": - FreeCADGui.Selection.addSelection(obj, objstring[2]) - else: - FreeCADGui.Selection.addSelection(obj) - - FreeCADGui.updateGui() - - def reorderBase(self): - newlist = [] - for i in range(self.form.baseList.count()): - s = self.form.baseList.item(i).text() - objstring = s.partition(".") - - obj = FreeCAD.ActiveDocument.getObject(objstring[0]) - item = (obj, str(objstring[2])) - newlist.append(item) - self.obj.Base = newlist - - self.obj.Proxy.execute(self.obj) - FreeCAD.ActiveDocument.recompute() - - def getStandardButtons(self): - return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel) - - def setupUi(self): - - # Connect Signals and Slots - # Base Controls - self.form.baseList.itemSelectionChanged.connect(self.itemActivated) - self.form.addBase.clicked.connect(self.addBase) - self.form.deleteBase.clicked.connect(self.deleteBase) - self.form.reorderBase.clicked.connect(self.reorderBase) - self.form.uiToolController.currentIndexChanged.connect(self.getFields) - - # Depths - self.form.startDepth.editingFinished.connect(self.getFields) - self.form.finalDepth.editingFinished.connect(self.getFields) - self.form.stepDown.editingFinished.connect(self.getFields) - - # Heights - self.form.safeHeight.editingFinished.connect(self.getFields) - self.form.clearanceHeight.editingFinished.connect(self.getFields) - - # operation - self.form.cutSide.currentIndexChanged.connect(self.getFields) - self.form.direction.currentIndexChanged.connect(self.getFields) - self.form.useCompensation.clicked.connect(self.getFields) - self.form.extraOffset.editingFinished.connect(self.getFields) - self.form.useStartPoint.clicked.connect(self.getFields) - - self.setFields() - - sel = FreeCADGui.Selection.getSelectionEx() - if len(sel) != 0 and sel[0].HasSubObjects: - self.addBase() - - -class SelObserver: - def __init__(self): - import PathScripts.PathSelection as PST - PST.eselect() - - def __del__(self): - import PathScripts.PathSelection as PST - PST.clear() - - def addSelection(self, doc, obj, sub, pnt): - FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')') - FreeCADGui.updateGui() - - -if FreeCAD.GuiUp: - # register the FreeCAD command - FreeCADGui.addCommand('Path_Profile_Edges', CommandPathProfileEdges()) - -FreeCAD.Console.PrintLog("Loading PathProfileEdges... done\n") +def Create(name): + obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) + proxy = ObjectProfile(obj) + return obj diff --git a/src/Mod/Path/PathScripts/PathProfileEdgesGui.py b/src/Mod/Path/PathScripts/PathProfileEdgesGui.py new file mode 100644 index 0000000000..c4be5ff2f5 --- /dev/null +++ b/src/Mod/Path/PathScripts/PathProfileEdgesGui.py @@ -0,0 +1,82 @@ +# -*- 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 FreeCADGui +import Path +import PathScripts.PathAreaOpGui as PathAreaOpGui +import PathScripts.PathLog as PathLog +import PathScripts.PathProfileEdges as PathProfileEdges +import PathScripts.PathSelection as PathSelection + +from PathScripts import PathUtils +from PySide import QtCore, QtGui + +def translate(context, text, disambig=None): + return QtCore.QCoreApplication.translate(context, text, disambig) + +class TaskPanelOpPage(PathAreaOpGui.TaskPanelPage): + + def getForm(self): + return FreeCADGui.PySideUic.loadUi(":/panels/PageOpProfileEdgesEdit.ui") + + def getFields(self, obj): + self.obj.OffsetExtra = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value + self.obj.UseComp = self.form.useCompensation.isChecked() + self.obj.UseStartPoint = self.form.useStartPoint.isChecked() + self.obj.Side = str(self.form.cutSide.currentText()) + self.obj.Direction = str(self.form.direction.currentText()) + + tc = PathUtils.findToolController(self.obj, self.form.toolController.currentText()) + self.obj.ToolController = tc + + def setFields(self, obj): + self.form.extraOffset.setText(FreeCAD.Units.Quantity(self.obj.OffsetExtra.Value, FreeCAD.Units.Length).UserString) + self.form.useCompensation.setChecked(self.obj.UseComp) + self.form.useStartPoint.setChecked(self.obj.UseStartPoint) + + self.selectInComboBox(self.obj.Side, self.form.cutSide) + self.selectInComboBox(self.obj.Direction, self.form.direction) + self.setupToolController(self.obj, self.form.toolController) + + def getSignalsForUpdate(self, obj): + signals = [] + signals.append(self.form.cutSide.currentIndexChanged) + signals.append(self.form.direction.currentIndexChanged) + signals.append(self.form.useCompensation.clicked) + signals.append(self.form.useStartPoint.clicked) + signals.append(self.form.extraOffset.editingFinished) + return signals + + + +PathAreaOpGui.SetupOperation('Profile Edges', + PathProfileEdges.Create, + TaskPanelOpPage, + 'Path-Profile', + QtCore.QT_TRANSLATE_NOOP("PathProfile", "Edge Profile"), + "P, F", + QtCore.QT_TRANSLATE_NOOP("PathProfile", "Profile based on face or faces")) + +FreeCAD.Console.PrintLog("Loading PathProfileEdgesGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathProfileFacesGui.py b/src/Mod/Path/PathScripts/PathProfileFacesGui.py index 7665f2c60c..c1b8aaa285 100644 --- a/src/Mod/Path/PathScripts/PathProfileFacesGui.py +++ b/src/Mod/Path/PathScripts/PathProfileFacesGui.py @@ -78,7 +78,7 @@ class TaskPanelOpPage(PathAreaOpGui.TaskPanelPage): signals.append(self.form.processCircles.clicked) return signals -PathAreaOpGui.SetupOperation('Profile', +PathAreaOpGui.SetupOperation('Profile Faces', PathProfileFaces.Create, TaskPanelOpPage, 'Path-Profile', @@ -86,4 +86,4 @@ PathAreaOpGui.SetupOperation('Profile', "P, F", QtCore.QT_TRANSLATE_NOOP("PathProfile", "Profile based on face or faces")) -FreeCAD.Console.PrintLog("Loading PathProfileGui... done\n") +FreeCAD.Console.PrintLog("Loading PathProfileFacesGui... done\n") diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py index d1611ac37c..b42b8f01b9 100644 --- a/src/Mod/Path/PathScripts/PathSelection.py +++ b/src/Mod/Path/PathScripts/PathSelection.py @@ -162,9 +162,10 @@ def surfaceselect(): def select(op): opsel = {} - opsel['Profile'] = profileselect - opsel['Pocket'] = pocketselect opsel['Contour'] = contourselect + opsel['Pocket'] = pocketselect + opsel['Profile Edges'] = eselect + opsel['Profile Faces'] = profileselect opsel['Surface'] = surfaceselect return opsel[op]