From f1a4a5bcc439b91db023f8af72e72728d4470255 Mon Sep 17 00:00:00 2001 From: brad Date: Thu, 24 Mar 2016 14:22:53 -0500 Subject: [PATCH] First attempt at a task panel Panel for engraving operation. --- src/Mod/Path/Gui/EngraveEdit.ui | 287 +++++++++++++++++++++ src/Mod/Path/PathScripts/PathAreaUtils.py | 48 ++-- src/Mod/Path/PathScripts/PathEngrave.py | 217 ++++++++++++++-- src/Mod/Path/PathScripts/PathKurveUtils.py | 15 ++ src/Mod/Path/PathScripts/PathPocket.py | 40 ++- src/Mod/Path/PathScripts/PathSelection.py | 37 +++ 6 files changed, 591 insertions(+), 53 deletions(-) create mode 100644 src/Mod/Path/Gui/EngraveEdit.ui diff --git a/src/Mod/Path/Gui/EngraveEdit.ui b/src/Mod/Path/Gui/EngraveEdit.ui new file mode 100644 index 000000000..30cfe0cda --- /dev/null +++ b/src/Mod/Path/Gui/EngraveEdit.ui @@ -0,0 +1,287 @@ + + + TaskPanel + + + + 0 + 0 + 322 + 452 + + + + + 0 + 400 + + + + Engrave + + + + + + 0 + + + + true + + + + 0 + 0 + 304 + 279 + + + + + :/icons/FreeCAD-default/scalable/accessories-calculator.svg:/icons/FreeCAD-default/scalable/accessories-calculator.svg + + + Base Geometry + + + + + + Add item selected in window. + + + add + + + + + + + Drag to reorder, then update. + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + false + + + + + + + Update the path with the removed and reordered items. + + + Update + + + + + + + Remove Item selected in list, then update. + + + Remove + + + + + + + + + 0 + 0 + 304 + 279 + + + + + :/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg:/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg + + + Depths + + + + + + mm + + + + + + + Start Depth + + + + + + + mm + + + + + + + Final Depth + + + + + + + + + 0 + 0 + 304 + 279 + + + + + :/icons/FreeCAD-default/scalable/document-open.svg:/icons/FreeCAD-default/scalable/document-open.svg + + + Heights + + + + + + mm + + + + + + + Safe Height + + + + + + + mm + + + + + + + Clearance Height + + + + + + + + + 0 + 0 + 304 + 279 + + + + + :/icons/FreeCAD-default/scalable/document-save-as.svg:/icons/FreeCAD-default/scalable/document-save-as.svg + + + Speeds + + + + + + mm/(s) + + + + + + + Horiz Feed + + + + + + + mm/(s) + + + + + + + Vert Feed + + + + + + + + + 0 + 0 + 304 + 279 + + + + + :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg + + + Operation + + + + + + + OCC Native Outline + + + + + + + + Algorithm + + + + + + + + + + + + Gui::InputField + QLineEdit +
Gui/InputField.h
+
+
+ + + + +
diff --git a/src/Mod/Path/PathScripts/PathAreaUtils.py b/src/Mod/Path/PathScripts/PathAreaUtils.py index aae5c5a36..f88730fa4 100644 --- a/src/Mod/Path/PathScripts/PathAreaUtils.py +++ b/src/Mod/Path/PathScripts/PathAreaUtils.py @@ -99,29 +99,29 @@ def cut_curvelist1(curve_list, rapid_safety_space, current_start_depth, depth, c rapid(z = clearance_height) -# def cut_curvelist2(curve_list, rapid_safety_space, current_start_depth, depth, clearance_height, keep_tool_down_if_poss,start_point): -# p = area.Point(0, 0) -# start_x,start_y=start_point -# first = True -# for curve in curve_list: -# need_rapid = True -# if first == True: -# direction = "on";radius = 0.0;offset_extra = 0.0; roll_radius = 0.0;roll_on = 0.0; roll_off = 0.0; rapid_safety_space; step_down = math.fabs(depth);extend_at_start = 0.0;extend_at_end = 0.0 -# kurve_funcs.make_smaller( curve, start = area.Point(start_x,start_y)) -# kurve_funcs.profile(curve, direction, radius , offset_extra, roll_radius, roll_on, roll_off, rapid_safety_space , clearance_height, current_start_depth, step_down , depth, extend_at_start, extend_at_end) -# else: -# s = curve.FirstVertex().p -# if keep_tool_down_if_poss == True: +def cut_curvelist2(curve_list, rapid_safety_space, current_start_depth, depth, clearance_height, keep_tool_down_if_poss,start_point): + p = area.Point(0, 0) + start_x,start_y=start_point + first = True + for curve in curve_list: + need_rapid = True + if first == True: + direction = "On";radius = 0.0;offset_extra = 0.0; roll_radius = 0.0;roll_on = 0.0; roll_off = 0.0; rapid_safety_space; step_down = math.fabs(depth);extend_at_start = 0.0;extend_at_end = 0.0 + PathKurveUtils.make_smaller( curve, start = area.Point(start_x,start_y)) + PathKurveUtils.profile(curve, direction, radius , offset_extra, roll_radius, roll_on, roll_off, rapid_safety_space , clearance_height, current_start_depth, step_down , depth, extend_at_start, extend_at_end) + else: + s = curve.FirstVertex().p + if keep_tool_down_if_poss == True: -# # see if we can feed across -# if feed_possible(p, s): -# need_rapid = False -# elif s.x == p.x and s.y == p.y: -# need_rapid = False + # see if we can feed across + if feed_possible(p, s): + need_rapid = False + elif s.x == p.x and s.y == p.y: + need_rapid = False -# cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, depth) -# first = False #change to True if you want to rapid back to start side before zigging again with unidirectional set -# rapid(z = clearance_height) + cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, depth) + first = False #change to True if you want to rapid back to start side before zigging again with unidirectional set + rapid(z = clearance_height) def recur(arealist, a1, stepover, from_center): # this makes arealist by recursively offsetting a1 inwards @@ -429,8 +429,8 @@ def pocket(a,tool_radius, extra_offset, stepover, depthparams, from_center, keep else: print "PathAreaUtils:438 I guess it IS used. Who knew?" - # for depth in depths: - # cut_curvelist2(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss, start_point) - # current_start_depth = depth + for depth in depths: + cut_curvelist2(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss, start_point) + current_start_depth = depth diff --git a/src/Mod/Path/PathScripts/PathEngrave.py b/src/Mod/Path/PathScripts/PathEngrave.py index a39e87e6f..2f1dacf52 100644 --- a/src/Mod/Path/PathScripts/PathEngrave.py +++ b/src/Mod/Path/PathScripts/PathEngrave.py @@ -22,7 +22,8 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Path,PathGui +import FreeCAD,FreeCADGui,Path,PathGui,Draft + from PySide import QtCore,QtGui """Path Engrave object and FreeCAD command""" @@ -41,7 +42,7 @@ class ObjectPathEngrave: def __init__(self,obj): - obj.addProperty("App::PropertyLinkSub","Base","Path","The base geometry of this object") + obj.addProperty("App::PropertyLinkSubList","Base","Path","The base geometry of this object") obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("Path", "The library or Algorithm used to generate the path")) obj.Algorithm = ['OCC Native'] @@ -56,6 +57,8 @@ class ObjectPathEngrave: obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Path","Feed rate for vertical moves in Z")) obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Path","Feed rate for horizontal moves")) + if FreeCAD.GuiUp: + _ViewProviderEngrave(obj.ViewObject) obj.Proxy = self @@ -66,17 +69,22 @@ class ObjectPathEngrave: return None def execute(self,obj): - if obj.Base: - # we only consider the outer wire if this is a Face - wires = obj.Base[0].Shape.Wires + output = "" + if obj.Base: + for o in obj.Base: + output += "G0 " + str(obj.ClearanceHeight.Value)+"\n" + # we only consider the outer wire if this is a Face + wires = o[0].Shape.Wires - output = "" - if obj.Algorithm == "OCC Native": - output += self.buildpathocc(obj, wires) + if obj.Algorithm == "OCC Native": + output += self.buildpathocc(obj, wires) - #print output - path = Path.Path(output) - obj.Path = path + #print output + if output == "": + #output += "G0 Z" + str(obj.ClearanceHeight.Value) + output +="G0" + path = Path.Path(output) + obj.Path = path def buildpathocc(self, obj, wires): import Part,DraftGeomUtils @@ -127,8 +135,45 @@ class ObjectPathEngrave: output += "G0 Z " + str(obj.SafeHeight.Value) return output -class CommandPathEngrave: + def addShapeString(self, obj, ss): + baselist = obj.Base + item = (ss, "") + if item in baselist: + FreeCAD.Console.PrintWarning("ShapeString already in the Engraving list"+ "\n") + else: + baselist.append (item) + obj.Base = baselist + self.execute(obj) + + +class _ViewProviderEngrave: + + def __init__(self,vobj): + vobj.Proxy = self + + def attach(self,vobj): + self.Object = vobj.Object + return + + def setEdit(self,vobj,mode=0): + FreeCADGui.Control.closeDialog() + taskd = TaskPanel() + taskd.obj = vobj.Object + FreeCADGui.Control.showDialog(taskd) + taskd.setupUi() + return True + + def getIcon(self): + return ":/icons/Path-Profile.svg" + + def __getstate__(self): + return None + + def __setstate__(self,state): + return None + +class CommandPathEngrave: def GetResources(self): return {'Pixmap' : 'Path-Engrave', @@ -139,36 +184,156 @@ class CommandPathEngrave: return not FreeCAD.ActiveDocument is None def Activated(self): - import Draft - # check that the selection contains exactly what we want - selection = FreeCADGui.Selection.getSelectionEx() - if len(selection) != 1: - FreeCAD.Console.PrintError(translate("Path_Engrave","Please select one ShapeString\n")) - return - if len(selection[0].SubObjects) != 0: - FreeCAD.Console.PrintError(translate("Path_Engrave","Please select one ShapeString\n")) - return - if not Draft.getType(selection[0].Object) == "ShapeString": - FreeCAD.Console.PrintError(translate("Path_Engrave","Please select one ShapeString\n")) - return # if everything is ok, execute and register the transaction in the undo/redo stack + FreeCAD.ActiveDocument.openTransaction("Create Engrave Path") FreeCADGui.addModule("PathScripts.PathFaceProfile") FreeCADGui.addModule("PathScripts.PathUtils") FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","PathEngrave")') FreeCADGui.doCommand('PathScripts.PathEngrave.ObjectPathEngrave(obj)') - FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.'+selection[0].ObjectName+',[])') + FreeCADGui.doCommand('obj.ClearanceHeight = 10') FreeCADGui.doCommand('obj.StartDepth= 0') FreeCADGui.doCommand('obj.FinalDepth= -0.1' ) FreeCADGui.doCommand('obj.SafeHeight= 5.0' ) - FreeCADGui.doCommand('obj.ViewObject.Proxy = 0') + #FreeCADGui.doCommand('obj.ViewObject.Proxy = 0') FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)') FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() + FreeCADGui.doCommand('obj.ViewObject.startEditing()') +class TaskPanel: + def __init__(self): + self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/EngraveEdit.ui") + #self.form = FreeCADGui.PySideUic.loadUi(":/gui/EngraveEdit.ui") + + def accept(self): + self.getFields() + + FreeCADGui.ActiveDocument.resetEdit() + FreeCADGui.Control.closeDialog() + FreeCAD.ActiveDocument.recompute() + FreeCADGui.Selection.removeObserver(self.s) + + def reject(self): + FreeCADGui.Control.closeDialog() + FreeCAD.ActiveDocument.recompute() + FreeCADGui.Selection.removeObserver(self.s) + + def getFields(self): + if self.obj: + if hasattr(self.obj,"StartDepth"): + self.obj.StartDepth = self.form.startDepth.text() + if hasattr(self.obj,"FinalDepth"): + self.obj.FinalDepth = self.form.finalDepth.text() + if hasattr(self.obj,"SafeHeight"): + self.obj.SafeHeight = self.form.safeHeight.text() + if hasattr(self.obj,"ClearanceHeight"): + self.obj.ClearanceHeight = self.form.clearanceHeight.text() + if hasattr(self.obj,"VertFeed"): + self.obj.VertFeed= self.form.vertFeed.text() + if hasattr(self.obj,"HorizFeed"): + self.obj.HorizFeed = self.form.horizFeed.text() + + self.obj.Proxy.execute(self.obj) + + 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 not len(selection) >= 1: + FreeCAD.Console.PrintError(translate("Path_Engrave","Please select at least one ShapeString\n")) + return + for s in selection: + if not Draft.getType(s.Object) == "ShapeString": + FreeCAD.Console.PrintError(translate("Path_Engrave","Please select at least one ShapeString\n")) + return + self.obj.Proxy.addShapeString(self.obj, s.Object) + + self.form.baseList.clear() + for i in self.obj.Base: + self.form.baseList.addItem(i[0].Name) + + def deleteBase(self): + dlist = self.form.baseList.selectedItems() + for d in dlist: + newlist = [] + for i in self.obj.Base: + if not i[0].Name == d.text(): + newlist.append (i) + self.obj.Base = newlist + self.form.baseList.takeItem(self.form.baseList.row(d)) + # self.obj.Proxy.execute(self.obj) + # FreeCAD.ActiveDocument.recompute() + + def itemActivated(self): + FreeCADGui.Selection.clearSelection() + slist = self.form.baseList.selectedItems() + for i in slist: + o = FreeCAD.ActiveDocument.getObject(i.text()) + FreeCADGui.Selection.addSelection(o) + FreeCADGui.updateGui() + + def reorderBase(self): + newlist = [] + for i in range(self.form.baseList.count()): + s = self.form.baseList.item(i).text() + obj = FreeCAD.ActiveDocument.getObject(s) + newlist.append(obj) + self.obj.Base=newlist + self.obj.Proxy.execute(self.obj) + FreeCAD.ActiveDocument.recompute() + + def getStandardButtons(self): + return int(QtGui.QDialogButtonBox.Ok) + + def setupUi(self): + self.form.startDepth.setText(str(self.obj.StartDepth.Value)) + self.form.finalDepth.setText(str(self.obj.FinalDepth.Value)) + self.form.safeHeight.setText(str(self.obj.SafeHeight.Value)) + self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value)) + self.form.vertFeed.setText(str(self.obj.VertFeed.Value)) + self.form.horizFeed.setText(str(self.obj.HorizFeed.Value)) + + for i in self.obj.Base: + self.form.baseList.addItem(i[0].Name) + + #Connect Signals and Slots + self.form.startDepth.editingFinished.connect(self.getFields) #This is newer syntax + #QtCore.QObject.connect(self.form.startDepth, QtCore.SIGNAL("editingFinished()"), self.getFields) + QtCore.QObject.connect(self.form.finalDepth, QtCore.SIGNAL("editingFinished()"), self.getFields) + QtCore.QObject.connect(self.form.horizFeed, QtCore.SIGNAL("editingFinished()"), self.getFields) + QtCore.QObject.connect(self.form.vertFeed, QtCore.SIGNAL("editingFinished()"), self.getFields) + QtCore.QObject.connect(self.form.safeHeight, QtCore.SIGNAL("editingFinished()"), self.getFields) + QtCore.QObject.connect(self.form.clearanceHeight, QtCore.SIGNAL("editingFinished()"), self.getFields) + + QtCore.QObject.connect(self.form.addBase, QtCore.SIGNAL("clicked()"), self.addBase) + QtCore.QObject.connect(self.form.deleteBase, QtCore.SIGNAL("clicked()"), self.deleteBase) + QtCore.QObject.connect(self.form.reorderBase, QtCore.SIGNAL("clicked()"), self.reorderBase) + + QtCore.QObject.connect(self.form.baseList, QtCore.SIGNAL("itemSelectionChanged()"), self.itemActivated) + + + +class SelObserver: + def __init__(self): + import PathScripts.PathSelection as PST + PST.engraveselect() + + def __del__(self): + import PathScripts.PathSelection as PST + PST.clear() + + def addSelection(self,doc,obj,sub,pnt): # Selection object + FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj +')') + FreeCADGui.updateGui() if FreeCAD.GuiUp: # register the FreeCAD command diff --git a/src/Mod/Path/PathScripts/PathKurveUtils.py b/src/Mod/Path/PathScripts/PathKurveUtils.py index dacf6c120..7520366ff 100644 --- a/src/Mod/Path/PathScripts/PathKurveUtils.py +++ b/src/Mod/Path/PathScripts/PathKurveUtils.py @@ -255,6 +255,21 @@ def profile(curve,side_of_line,radius=1.0,vertfeed=0.0,horizfeed=0.0,offset_extr return output +def make_smaller( curve, start = None, finish = None, end_beyond = False ): + if start != None: + curve.ChangeStart(curve.NearestPoint(start)) + + if finish != None: + if end_beyond: + curve2 = area.Curve(curve) + curve2.ChangeEnd(curve2.NearestPoint(finish)) + first = True + for vertex in curve2.getVertices(): + if first == False: curve.append(vertex) + first = False + else: + curve.ChangeEnd(curve.NearestPoint(finish)) + # def makePath(edges,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC,direction,startpt=None,endpt=None): # curve = makeAreaCurve(edges,direction,startpt, endpt) diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py index a41610ddf..14af80096 100644 --- a/src/Mod/Path/PathScripts/PathPocket.py +++ b/src/Mod/Path/PathScripts/PathPocket.py @@ -99,7 +99,11 @@ class ObjectPocket: obj.HelixSize = (0.0, 0.01, 100.0, 0.5) obj.addProperty("App::PropertyFloatConstraint", "RampAngle", "Entry", translate("PathProject","The Angle of the ramp entry.")) obj.RampAngle = (0.0, 0.01, 100.0, 0.5) - + + #Start Point Properties + obj.addProperty("App::PropertyVector","StartPoint","Start Point",translate("PathProject","The start point of this path")) + obj.addProperty("App::PropertyBool","UseStartPoint","Start Point",translate("PathProject","make True, if specifying a Start Point")) + obj.Proxy = self def onChanged(self,obj,prop): @@ -157,6 +161,9 @@ class ObjectPocket: PathAreaUtils.output('mem') PathAreaUtils.feedrate_hv(obj.HorizFeed.Value, obj.VertFeed.Value) + if obj.UseStartPoint: + start_point = (obj.StartPoint.x,obj.StartPoint.y) + print "a," + str(self.radius) + "," + str(extraoffset) + "," + str(stepover) + ",depthparams, " + str(from_center) + "," + str(keep_tool_down) + "," + str(use_zig_zag) + "," + str(zig_angle) + "," + str(zig_unidirectional) + "," + str(start_point) + "," + str(cut_mode) @@ -165,8 +172,6 @@ class ObjectPocket: return PathAreaUtils.retrieve_gcode() - - def buildpathocc(self, obj, shape): import Part, DraftGeomUtils FreeCAD.Console.PrintMessage(translate("PathPocket","Generating toolpath with OCC native offsets.\n")) @@ -554,6 +559,22 @@ class ObjectPocket: obj.Path = path obj.ViewObject.Visibility = False +class _CommandSetPocketStartPoint: + def GetResources(self): + return {'Pixmap' : 'Path-StartPoint', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathPocket","Pick Start Point"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathPocket","Pick Start Point")} + + def IsActive(self): + return not FreeCAD.ActiveDocument is 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 ViewProviderPocket: @@ -564,6 +585,17 @@ class ViewProviderPocket: self.Object = vobj.Object return + def setEdit(self,vobj,mode=0): + import PocketEdit + FreeCADGui.Control.closeDialog() + taskd = QtGui.QWidget() + taskd = PocketEdit.Ui_Dialog() + taskd.obj = vobj.Object + #taskd.update() + FreeCADGui.Control.showDialog(taskd) + + return True + def getIcon(self): return ":/icons/Path-Pocket.svg" @@ -660,5 +692,7 @@ class CommandPathPocket: if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand('Path_Pocket',CommandPathPocket()) + FreeCADGui.addCommand('Set_PocketStartPoint',_CommandSetPocketStartPoint()) + FreeCAD.Console.PrintLog("Loading PathPocket... done\n") diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py index 3e566f2d2..c1bbbc827 100644 --- a/src/Mod/Path/PathScripts/PathSelection.py +++ b/src/Mod/Path/PathScripts/PathSelection.py @@ -55,5 +55,42 @@ def check_clockwise(poly): return clockwise +class FGate: + def allow(self,doc,obj,sub): + return (sub[0:4] == 'Face') + +class VGate: + def allow(self,doc,obj,sub): + return (sub[0:6] == 'Vertex') + +class EGate: + def allow(self,doc,obj,sub): + return (sub[0:4] == 'Edge') + +class ENGRAVEGate: + def allow(self,doc,obj,sub): + return (obj.Name[0:11] == 'ShapeString') + + +def fselect(): + FreeCADGui.Selection.addSelectionGate(FGate()) + FreeCAD.Console.PrintWarning("Face Select Mode\n") + +def vselect(): + FreeCADGui.Selection.addSelectionGate(VGate()) + FreeCAD.Console.PrintWarning("Vertex Select Mode\n") + +def eselect(): + FreeCADGui.Selection.addSelectionGate(EGate()) + FreeCAD.Console.PrintWarning("Edge Select Mode\n") + + +def engraveselect(): + FreeCADGui.Selection.addSelectionGate(ENGRAVEGate()) + FreeCAD.Console.PrintWarning("ShapeString Select Mode\n") + +def clear(): + FreeCADGui.Selection.removeSelectionGate() + FreeCAD.Console.PrintWarning("Free Select\n")