diff --git a/src/Mod/Path/Gui/DrillingEdit.ui b/src/Mod/Path/Gui/DrillingEdit.ui
new file mode 100644
index 000000000..f9411e387
--- /dev/null
+++ b/src/Mod/Path/Gui/DrillingEdit.ui
@@ -0,0 +1,268 @@
+
+
+ TaskPanel
+
+
+
+ 0
+ 0
+ 322
+ 452
+
+
+
+
+ 0
+ 400
+
+
+
+ Drilling
+
+
+ -
+
+
+ 0
+
+
+
+ true
+
+
+
+ 0
+ 0
+ 304
+ 314
+
+
+
+
+ :/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
+ 116
+ 108
+
+
+
+
+ :/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
+
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Peck Depth
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 150
+ 108
+
+
+
+
+ :/icons/FreeCAD-default/scalable/document-open.svg:/icons/FreeCAD-default/scalable/document-open.svg
+
+
+ Heights
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Safe Height
+
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Clearance Height
+
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Retract Height
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 234
+ 50
+
+
+
+
+ :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg
+
+
+ Operation
+
+
+ -
+
+
-
+
+ OCC Native Outline
+
+
+
+
+ -
+
+
+ Algorithm
+
+
+
+
+
+
+
+
+
+
+
+ Gui::InputField
+ QLineEdit
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Path/Gui/PocketEdit.ui b/src/Mod/Path/Gui/PocketEdit.ui
new file mode 100644
index 000000000..697b3b65b
--- /dev/null
+++ b/src/Mod/Path/Gui/PocketEdit.ui
@@ -0,0 +1,373 @@
+
+
+ TaskPanel
+
+
+
+ 0
+ 0
+ 352
+ 525
+
+
+
+
+ 0
+ 400
+
+
+
+ Pocket
+
+
+ -
+
+
+ 0
+
+
+
+ true
+
+
+
+ 0
+ 0
+ 334
+ 327
+
+
+
+
+ :/icons/FreeCAD-default/scalable/accessories-calculator.svg:/icons/FreeCAD-default/scalable/accessories-calculator.svg
+
+
+ Base Geometry
+
+
+
-
+
+
+ Drag to reorder, then update.
+
+
+ QAbstractItemView::DragDrop
+
+
+ Qt::MoveAction
+
+
+ false
+
+
+
+ -
+
+
+ Add item selected in window.
+
+
+ add
+
+
+
+ -
+
+
+ Remove Item selected in list, then update.
+
+
+ Remove
+
+
+
+ -
+
+
+ Update the path with the removed and reordered items.
+
+
+ Update
+
+
+
+ -
+
+
+ All objects will be profiled using the same depth and speed settings
+
+
+ Qt::AutoText
+
+
+ true
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 334
+ 327
+
+
+
+
+ :/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
+
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Finish Depth
+
+
+
+ -
+
+
+ 3
+
+
+ 0.100000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ Step Down
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 334
+ 327
+
+
+
+
+ :/icons/FreeCAD-default/scalable/document-open.svg:/icons/FreeCAD-default/scalable/document-open.svg
+
+
+ Heights
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Safe Height
+
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Clearance Height
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 334
+ 327
+
+
+
+ Entry
+
+
+
+
+
+ Pattern
+
+
+
+
+
+ 0
+ 0
+ 334
+ 327
+
+
+
+
+ :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg
+
+
+ Operation
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ Algorithm
+
+
+
+ -
+
+
-
+
+ OCC Native
+
+
+ -
+
+ libarea
+
+
+
+
+ -
+
+
+
-
+
+
+ Cut Mode
+
+
+
+ -
+
+
-
+
+ Climb
+
+
+ -
+
+ Conventional
+
+
+
+
+
+
+
+ -
+
+
+
-
+
+
+ Use Start Point
+
+
+
+
+
+
+ -
+
+
+
-
+
+
+ Material Allowance
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gui::InputField
+ QLineEdit
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Path/Gui/ProfileEdit.ui b/src/Mod/Path/Gui/ProfileEdit.ui
new file mode 100644
index 000000000..8a968e68b
--- /dev/null
+++ b/src/Mod/Path/Gui/ProfileEdit.ui
@@ -0,0 +1,450 @@
+
+
+ TaskPanel
+
+
+
+ 0
+ 0
+ 352
+ 525
+
+
+
+
+ 0
+ 400
+
+
+
+ Profile
+
+
+ -
+
+
+ 0
+
+
+
+ true
+
+
+
+ 0
+ 0
+ 334
+ 357
+
+
+
+
+ :/icons/FreeCAD-default/scalable/accessories-calculator.svg:/icons/FreeCAD-default/scalable/accessories-calculator.svg
+
+
+ Base Geometry
+
+
+
-
+
+
+ Drag to reorder, then update.
+
+
+ QAbstractItemView::DragDrop
+
+
+ Qt::MoveAction
+
+
+ false
+
+
+
+ -
+
+
+ Add item selected in window.
+
+
+ add
+
+
+
+ -
+
+
+ Remove Item selected in list, then update.
+
+
+ Remove
+
+
+
+ -
+
+
+ Update the path with the removed and reordered items.
+
+
+ Update
+
+
+
+ -
+
+
+ All objects will be profiled using the same depth and speed settings
+
+
+ Qt::AutoText
+
+
+ true
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 334
+ 357
+
+
+
+
+ :/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
+
+
+
+ -
+
+
+ 3
+
+
+ 0.100000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ Step Down
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 334
+ 357
+
+
+
+
+ :/icons/FreeCAD-default/scalable/document-open.svg:/icons/FreeCAD-default/scalable/document-open.svg
+
+
+ Heights
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Safe Height
+
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+ Clearance Height
+
+
+
+
+
+
+
+ Holding
+
+
+ -
+
+
+
+ Tag
+
+
+
+
+ Location
+
+
+
+
+ Height
+
+
+
+
+ Length
+
+
+
+
+ Angle
+
+
+
+
+ -
+
+
+ Add New
+
+
+
+ -
+
+
+ Delete
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 334
+ 357
+
+
+
+
+ :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg
+
+
+ Operation
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ Algorithm
+
+
+
+ -
+
+
-
+
+ OCC Native
+
+
+ -
+
+ libarea
+
+
+
+
+ -
+
+
+
-
+
+
+ Cut Side
+
+
+
+ -
+
+
-
+
+ Left
+
+
+ -
+
+ Right
+
+
+ -
+
+ On
+
+
+
+
+ -
+
+
+ Direction
+
+
+
+ -
+
+
-
+
+ CW
+
+
+ -
+
+ CCW
+
+
+
+
+
+
+
+ -
+
+
+
-
+
+
+ Use Start Point
+
+
+
+ -
+
+
+ Use Compensation
+
+
+
+ -
+
+
+ Use End Point
+
+
+
+
+
+
+ -
+
+
+
-
+
+
+ Extra Offset
+
+
+
+ -
+
+
+ -
+
+
+ Segment Length
+
+
+
+ -
+
+
+ -
+
+
+ Roll Radius
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gui::InputField
+ QLineEdit
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Path/PathScripts/PathAreaUtils.py b/src/Mod/Path/PathScripts/PathAreaUtils.py
index f88730fa4..c7e9ee7f5 100644
--- a/src/Mod/Path/PathScripts/PathAreaUtils.py
+++ b/src/Mod/Path/PathScripts/PathAreaUtils.py
@@ -378,12 +378,9 @@ def pocket(a,tool_radius, extra_offset, stepover, depthparams, from_center, keep
use_internal_function = (area.holes_linked() == False) # use internal function, if area module is the Clipper library
if use_internal_function:
- print "using internal. PathAreaUtils:382 "
curve_list = a.MakePocketToolpath(tool_radius, extra_offset, stepover, from_center, use_zig_zag, zig_angle)
else:
- print "not using internal. PathAreaUtils:386 "
-
global sin_angle_for_zigs
global cos_angle_for_zigs
global sin_minus_angle_for_zigs
@@ -421,14 +418,12 @@ def pocket(a,tool_radius, extra_offset, stepover, depthparams, from_center, keep
depths = depthparams.get_depths()
current_start_depth = depthparams.start_depth
- print "Startpoint: " + str(start_point)
if start_point==None:
for depth in depths:
cut_curvelist1(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss)
current_start_depth = depth
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
diff --git a/src/Mod/Path/PathScripts/PathCompoundExtended.py b/src/Mod/Path/PathScripts/PathCompoundExtended.py
index 865db491b..6a9349436 100644
--- a/src/Mod/Path/PathScripts/PathCompoundExtended.py
+++ b/src/Mod/Path/PathScripts/PathCompoundExtended.py
@@ -22,7 +22,7 @@
#* *
#***************************************************************************
-import FreeCAD,FreeCADGui,Path,PathGui
+import FreeCAD,FreeCADGui,Path,PathGui, PathUtils
from PySide import QtCore,QtGui
"""Path Compound Extended object and FreeCAD command"""
@@ -54,6 +54,13 @@ class ObjectCompoundExtended:
def __setstate__(self,state):
return None
+ def onChanged(self,obj,prop):
+ if prop == "Group":
+ print 'check order'
+ for child in obj.Group:
+ if child.isDerivedFrom("Path::Feature"):
+ child.touch()
+
def execute(self,obj):
cmds = []
for child in obj.Group:
diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py
index d9a407210..6b5b9fe3a 100644
--- a/src/Mod/Path/PathScripts/PathDrilling.py
+++ b/src/Mod/Path/PathScripts/PathDrilling.py
@@ -49,12 +49,13 @@ class ObjectDrilling:
obj.addProperty("App::PropertyLinkSubList","Base","Path",translate("Parent Object(s)","The base geometry of this toolpath"))
obj.addProperty("App::PropertyVectorList","locations","Path","The drilling locations")
- obj.addProperty("App::PropertyLength", "PeckDepth", "Depth", translate("PeckDepth","Incremental Drill depth before retracting to clear chips"))
- #obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
- obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Clearance Height","The height needed to clear clamps and obstructions"))
- obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Final Depth","Final Depth of Tool- lowest value in Z"))
+ obj.addProperty("App::PropertyLength", "PeckDepth", "Depth", translate("PathProject","Incremental Drill depth before retracting to clear chips"))
+ obj.addProperty("App::PropertyLength", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
+ obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
+ obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
+ obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("PathProject","Height to clear top of materil"))
obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", translate("Retract Height","The height where feed starts and height during retract tool when path is finished"))
- obj.addProperty("App::PropertyLength", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
+ #obj.addProperty("App::PropertyLength", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Active","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use"))
@@ -70,65 +71,75 @@ class ObjectDrilling:
return None
def execute(self,obj):
- locations = []
- for loc in obj.Base:
-
- if "Face" in loc[1] or "Edge" in loc[1]:
- s = getattr(loc[0].Shape,loc[1])
- else:
- s = loc[0].Shape
-
- if s.ShapeType in ['Face', 'Wire', 'Edge' ]:
- X = s.Edges[0].Curve.Center.x
- Y = s.Edges[0].Curve.Center.y
- Z = s.Edges[0].Curve.Center.z
- elif s.ShapeType == 'Vertex':
- X = s.Point.x
- Y = s.Point.y
- Z = s.Point.z
-
- locations.append(FreeCAD.Vector(X,Y,Z))
-
- # tie the toolnumber to the PathLoadTool object ToolNumber
- if len(obj.InList)>0: #check to see if obj is in the Project group yet
- project = obj.InList[0]
- tl = int(PathUtils.changeTool(obj,project))
- obj.ToolNumber= tl
-
- tool = PathUtils.getTool(obj,obj.ToolNumber)
-
- output = "G90 G98\n"
- # rapid to clearance height
- output += "G0 Z" + str(obj.ClearanceHeight.Value)
- # rapid to first hole location, with spindle still retracted:
- p0 = locations[0]
- output += "G0 X"+str(p0.x) + " Y" + str(p0.y)+ "\n"
- # move tool to clearance plane
- output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n"
- if obj.PeckDepth.Value > 0:
- cmd = "G83"
- qword = " Q"+ str(obj.PeckDepth.Value)
+ output = ""
+ toolLoad = PathUtils.getLastToolLoad(obj)
+ if toolLoad == None:
+ self.vertFeed = 100
+ self.horizFeed = 100
+ radius = 0.25
+ obj.ToolNumber= 0
else:
- cmd = "G81"
- qword = ""
- for p in locations:
+ self.vertFeed = toolLoad.VertFeed.Value
+ self.horizFeed = toolLoad.HorizFeed.Value
+ tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
+ radius = tool.Diameter/2
+ obj.ToolNumber= toolLoad.ToolNumber
+ if obj.Base:
+ locations = []
+ for loc in obj.Base:
- output += cmd + " X" + str(p.x) + " Y" + str(p.y) + " Z" + str(obj.FinalDepth.Value) + qword + " R" + str(obj.RetractHeight.Value) + " F" + str(obj.VertFeed.Value) + "\n"
+ if "Face" in loc[1] or "Edge" in loc[1]:
+ s = getattr(loc[0].Shape,loc[1])
+ else:
+ s = loc[0].Shape
- output += "G80\n"
+ if s.ShapeType in ['Face', 'Wire', 'Edge' ]:
+ X = s.Edges[0].Curve.Center.x
+ Y = s.Edges[0].Curve.Center.y
+ Z = s.Edges[0].Curve.Center.z
+ elif s.ShapeType == 'Vertex':
+ X = s.Point.x
+ Y = s.Point.y
+ Z = s.Point.z
+
+ locations.append(FreeCAD.Vector(X,Y,Z))
+
+ output = "G90 G98\n"
+ # rapid to clearance height
+ output += "G0 Z" + str(obj.ClearanceHeight.Value)
+ # rapid to first hole location, with spindle still retracted:
+ p0 = locations[0]
+ output += "G0 X"+str(p0.x) + " Y" + str(p0.y)+ "\n"
+ # move tool to clearance plane
+ output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n"
+ if obj.PeckDepth.Value > 0:
+ cmd = "G83"
+ qword = " Q"+ str(obj.PeckDepth.Value)
+ else:
+ cmd = "G81"
+ qword = ""
+ for p in locations:
+
+ output += cmd + " X" + str(p.x) + " Y" + str(p.y) + " Z" + str(obj.FinalDepth.Value) + qword + " R" + str(obj.RetractHeight.Value) + " F" + str(self.vertFeed) + "\n"
+
+ output += "G80\n"
path = Path.Path(output)
obj.Path = path
- # tie the toolnumber to the PathLoadTool object ToolNumber
- if len(obj.InList)>0: #check to see if obj is in the Project group yet
- project = obj.InList[0]
- tl = int(PathUtils.changeTool(obj,project))
- obj.ToolNumber= tl
-class ViewProviderDrill:
+ def addDrillableLocation(self, obj, ss, sub=""):
+ baselist = obj.Base
+ item = (ss, sub)
+ if item in baselist:
+ FreeCAD.Console.PrintWarning("Drillable location already in the list"+ "\n")
+ else:
+ baselist.append (item)
+ obj.Base = baselist
+ self.execute(obj)
+
+class _ViewProviderDrill:
def __init__(self,obj): #mandatory
-# obj.addProperty("App::PropertyFloat","SomePropertyName","PropertyGroup","Description of this property")
obj.Proxy = self
def __getstate__(self): #mandatory
@@ -152,19 +163,21 @@ class ViewProviderDrill:
# this is executed when a property of the APP OBJECT changes
pass
- def setEdit(self,vobj,mode): #optional
- # this is executed when the object is double-clicked in the tree
- pass
+ def setEdit(self,vobj,mode=0):
+ FreeCADGui.Control.closeDialog()
+ taskd = TaskPanel()
+ taskd.obj = vobj.Object
+ FreeCADGui.Control.showDialog(taskd)
+ taskd.setupUi()
+ return True
+
def unsetEdit(self,vobj,mode): #optional
# this is executed when the user cancels or terminates edit mode
pass
-
-
class CommandPathDrilling:
-
def GetResources(self):
return {'Pixmap' : 'Path-Drilling',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Drilling","Drilling"),
@@ -174,96 +187,8 @@ class CommandPathDrilling:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
- def Drillable(self, obj):
- import Part
- drillable = ""
- if obj.ShapeType == 'Vertex':
- drillable = 'Vertex'
- elif obj.ShapeType == 'Edge':
- if isinstance(obj.Curve, Part.Circle):
- drillable = 'Circle'
- elif obj.ShapeType == 'Face':
- if isinstance(obj.Edges[0].Curve, Part.Circle):
- drillable = 'Circle'
- elif obj.ShapeType == 'Wire':
- if isinstance(obj.Edges[0].Curve, Part.Circle):
- drillable = 'Circle'
- else:
- drillable = None
- return drillable
-
def Activated(self):
- import Path
- import Part
-
- from PathScripts import PathUtils,PathDrilling,PathProject
- prjexists = False
-
- selection = FreeCADGui.Selection.getSelectionEx()
- if not selection:
- FreeCAD.Console.PrintError(translate("PathDrilling","Please select points or cirlces for drilling.\n"))
- return
-
- diamcount = 0 #keep track of how many different hole sizes we're asked to deal with
- lastradius = 0.0
- locations = []
- vertexcount = 0 #keep track of how many vertices
-
- for s in selection:
- if s.HasSubObjects:
- for i in s.SubObjects:
- d = self.Drillable (i)
- if d == 'Circle':
- if i.Edges[0].Curve.Radius != lastradius:
- diamcount += 1
- lastradius = i.Edges[0].Curve.Radius
- elif d == 'Vertex':
- vertexcount += 1
- else:
- FreeCAD.Console.PrintError(translate("PathDrilling","No drillable locations were selected.\n"))
- return
-
- #subs = []
- for n in s.SubElementNames:
- # subs.append(n)
- locations.append((s.ObjectName, s.Object, n))
-
- else:
- d = self.Drillable (s.Object.Shape)
- if d == 'Circle':
- if not str(s.Object.Shape.Edges[0].Curve.Radius) == str(lastradius):
- diamcount += 1
- lastradius = s.Object.Shape.Edges[0].Curve.Radius
-
- elif d == 'Vertex':
- vertexcount += 1
- else:
- FreeCAD.Console.PrintError(translate("PathDrilling","No drillable locations were selected.\n"))
- return
-
- locations.append((s.ObjectName, s.Object, []))
-
- if diamcount > 1:
- FreeCAD.Console.PrintError(translate("PathDrilling","Circles of different radii found. Select only one size circle at a time.\n"))
- return
-
- if diamcount >= 1 and vertexcount >= 1:
- FreeCAD.Console.PrintError(translate("PathDrilling","Please select either points or circles but not both.\n"))
- return
-
- # Take a guess at some reasonable values for Finish depth.
- if selection[0].HasSubObjects:
- bb = selection[0].Object.Shape.BoundBox #parent boundbox
- fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
- if fbb.ZMax < bb.ZMax:
- zbottom = fbb.ZMax
- ztop = bb.ZMax + 1
- else:
- zbottom = bb.ZMin
- ztop = 5
- else:
- zbottom = 0
- ztop = 5
+ import Path, Part
# if everything is ok, execute and register the transaction in the undo/redo stack
@@ -272,15 +197,10 @@ class CommandPathDrilling:
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Drilling")')
FreeCADGui.doCommand('PathScripts.PathDrilling.ObjectDrilling(obj)')
FreeCADGui.doCommand('obj.Active = True')
- FreeCADGui.doCommand('PathScripts.PathDrilling.ViewProviderDrill(obj.ViewObject)')
+ FreeCADGui.doCommand('PathScripts.PathDrilling._ViewProviderDrill(obj.ViewObject)')
- baselist = "["
- for loc in locations:
- baselist += "(FreeCAD.ActiveDocument." + str(loc[0]) + ',"' + str(loc[2]) + '"),'
- baselist += "]"
-
- FreeCADGui.doCommand('obj.Base = (' + baselist + ')')
- FreeCADGui.doCommand('from PathScripts import PathUtils')
+ ztop = 10.0
+ zbottom = 0.0
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop))
FreeCADGui.doCommand('obj.RetractHeight= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
@@ -288,6 +208,147 @@ class CommandPathDrilling:
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/DrillingEdit.ui")
+ #self.form = FreeCADGui.PySideUic.loadUi(":/DrillingEdit.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,"PeckDepth"):
+ self.obj.PeckDepth = self.form.peckDepth.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,"RetractHeight"):
+ self.obj.RetractHeight = self.form.retractHeight.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("PathProject","Please select at least one Drillable Location\n"))
+ return
+ for s in selection:
+ if s.HasSubObjects:
+ for i in s.SubElementNames:
+ self.obj.Proxy.addDrillableLocation(self.obj, s.Object, i)
+ else:
+ self.obj.Proxy.addDrillableLocation(self.obj, s.Object)
+
+ self.form.baseList.clear()
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name + "." + i[1])
+
+
+ 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().partition(".")[0]:
+ 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:
+ objstring = i.text().partition(".")
+ obj = FreeCAD.ActiveDocument.getObject(objstring[0])
+ # sub = o.Shape.getElement(objstring[2])
+ 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)
+
+ def setupUi(self):
+ self.form.startDepth.setText(str(self.obj.StartDepth.Value))
+ self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
+ self.form.peckDepth.setText(str(self.obj.PeckDepth.Value))
+ self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
+ self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
+ self.form.retractHeight.setText(str(self.obj.RetractHeight.Value))
+
+
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name + "." + i[1])
+
+ #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.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)
+
+ self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
+
+class SelObserver:
+ def __init__(self):
+ import PathScripts.PathSelection as PST
+ PST.drillselect()
+
+ 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:
diff --git a/src/Mod/Path/PathScripts/PathEngrave.py b/src/Mod/Path/PathScripts/PathEngrave.py
index a82b1ea68..6ef7ddcef 100644
--- a/src/Mod/Path/PathScripts/PathEngrave.py
+++ b/src/Mod/Path/PathScripts/PathEngrave.py
@@ -25,6 +25,7 @@
import FreeCAD,FreeCADGui,Path,PathGui,Draft
from PySide import QtCore,QtGui
+from PathScripts import PathUtils,PathProject
"""Path Engrave object and FreeCAD command"""
@@ -46,6 +47,10 @@ class ObjectPathEngrave:
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("Path", "The library or Algorithm used to generate the path"))
obj.Algorithm = ['OCC Native']
+
+ obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("Path","The tool number in use"))
+ obj.ToolNumber = (0,0,1000,1)
+ obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Path","The height needed to clear clamps and obstructions"))
@@ -54,8 +59,6 @@ class ObjectPathEngrave:
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Path","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyInteger","StartVertex","Path","The vertex index to start the path from")
#Feed Properties
- 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)
@@ -70,6 +73,20 @@ class ObjectPathEngrave:
def execute(self,obj):
output = ""
+
+ toolLoad = PathUtils.getLastToolLoad(obj)
+ if toolLoad == None:
+ self.vertFeed = 100
+ self.horizFeed = 100
+ radius = 0.25
+ obj.ToolNumber= 0
+ else:
+ self.vertFeed = toolLoad.VertFeed.Value
+ self.horizFeed = toolLoad.HorizFeed.Value
+ tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
+ radius = tool.Diameter/2
+ obj.ToolNumber= toolLoad.ToolNumber
+
if obj.Base:
for o in obj.Base:
output += "G0 " + str(obj.ClearanceHeight.Value)+"\n"
@@ -81,7 +98,6 @@ class ObjectPathEngrave:
#print output
if output == "":
- #output += "G0 Z" + str(obj.ClearanceHeight.Value)
output +="G0"
path = Path.Path(output)
obj.Path = path
@@ -106,7 +122,7 @@ class ObjectPathEngrave:
# we set the first move to our first point
last = edge.Vertexes[0].Point
output += "G0" + " X" + str("%f" % last.x) + " Y" + str("%f" % last.y) #Rapid sto starting position
- output += "G1" + " Z" + str("%f" % last.z) +"F " + str(obj.VertFeed.Value)+ "\n" #Vertical feed to depth
+ output += "G1" + " Z" + str("%f" % last.z) +"F " + str(self.vertFeed)+ "\n" #Vertical feed to depth
if isinstance(edge.Curve,Part.Circle):
point = edge.Vertexes[-1].Point
if point == last: # edges can come flipped
@@ -121,7 +137,7 @@ class ObjectPathEngrave:
output += "G3"
output += " X" + str("%f" % point.x) + " Y" + str("%f" % point.y) + " Z" + str("%f" % point.z)
output += " I" + str("%f" % relcenter.x) + " J" + str("%f" % relcenter.y) + " K" + str("%f" % relcenter.z)
- output += " F " + str(obj.HorizFeed.Value)
+ output += " F " + str(self.horizFeed)
output += "\n"
last = point
else:
@@ -129,7 +145,7 @@ class ObjectPathEngrave:
if point == last: # edges can come flipped
point = edge.Vertexes[0].Point
output += "G1 X" + str("%f" % point.x) + " Y" + str("%f" % point.y) + " Z" + str("%f" % point.z)
- output += " F " + str(obj.HorizFeed.Value)
+ output += " F " + str(self.horizFeed)
output += "\n"
last = point
output += "G0 Z " + str(obj.SafeHeight.Value)
@@ -232,10 +248,7 @@ class TaskPanel:
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)
@@ -299,8 +312,7 @@ class TaskPanel:
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)
@@ -309,8 +321,6 @@ class TaskPanel:
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)
diff --git a/src/Mod/Path/PathScripts/PathKurveUtils.py b/src/Mod/Path/PathScripts/PathKurveUtils.py
index 7520366ff..1a24d140d 100644
--- a/src/Mod/Path/PathScripts/PathKurveUtils.py
+++ b/src/Mod/Path/PathScripts/PathKurveUtils.py
@@ -57,8 +57,8 @@ def makeAreaCurve(edges,direction,startpt=None,endpt=None):
cleanededges = Part.__sortEdges__(PathUtils.cleanedges(edges, 0.01))
- for e in cleanededges:
- print str(e.valueAt(e.FirstParameter)) + "," + str(e.valueAt(e.LastParameter))
+ #for e in cleanededges:
+ #print str(e.valueAt(e.FirstParameter)) + "," + str(e.valueAt(e.LastParameter))
edgelist=[]
if len(cleanededges) == 1: #user selected a single edge.
@@ -270,31 +270,12 @@ def make_smaller( curve, start = None, finish = None, end_beyond = 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)
-# path = profile(curve,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC)
-# del curve
-# return path
-
-# def edgedumper (mylist):
-# import Part, PathUtils
-# print "The amazing edgedumper"
-# print "mylist: " + str(mylist)
-# edgs = PathUtils.cleanedges(mylist, 0.01)
-# edgs = Part.Wire(edgs)
-# for i in edgs.Edges:
-# mystring = str(i)
-# for v in i.Vertexes:
-# mystring = mystring + " : " + str(v.Point)
-# print mystring
'''The following procedures are copied almost directly from heekscnc kurve_funcs.py. They depend on nc directory existing below PathScripts and have not been
throughly optimized, understood, or tested for FreeCAD.'''
def profile2(curve, direction = "on", radius = 1.0, vertfeed=0.0,horizfeed=0.0, offset_extra = 0.0, roll_radius = 2.0, roll_on = None, roll_off = None, depthparams = None, extend_at_start = 0.0, extend_at_end = 0.0, lead_in_line_len=0.0,lead_out_line_len= 0.0):
- print "we're in"
from PathScripts.nc.nc import *
global tags
direction = direction.lower()
diff --git a/src/Mod/Path/PathScripts/PathLoadTool.py b/src/Mod/Path/PathScripts/PathLoadTool.py
index 2d1a0668a..a622a5bd7 100644
--- a/src/Mod/Path/PathScripts/PathLoadTool.py
+++ b/src/Mod/Path/PathScripts/PathLoadTool.py
@@ -70,11 +70,11 @@ class LoadTool:
def onChanged(self,obj,prop):
mode = 2
obj.setEditorMode('Placement',mode)
- if prop == "ToolNumber":
- proj = PathUtils.findProj()
- for g in proj.Group:
- if not(isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool)):
- g.touch()
+ #if prop == "ToolNumber":
+ proj = PathUtils.findProj()
+ for g in proj.Group:
+ if not(isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool)):
+ g.touch()
class _ViewProviderLoadTool:
@@ -110,9 +110,9 @@ class _ViewProviderLoadTool:
vobj.setEditorMode('DisplayMode',mode)
vobj.setEditorMode('BoundingBox',mode)
vobj.setEditorMode('Selectable',mode)
- vobj.setEditorMode('ShapeColor',mode)
- vobj.setEditorMode('Transparency',mode)
- vobj.setEditorMode('Visibility',mode)
+ #vobj.setEditorMode('ShapeColor',mode)
+ #vobj.setEditorMode('Transparency',mode)
+ #vobj.setEditorMode('Visibility',mode)
def updateData(self,vobj,prop): #optional
# this is executed when a property of the APP OBJECT changes
@@ -137,15 +137,12 @@ class CommandPathLoadTool:
return not FreeCAD.ActiveDocument is None
def Activated(self):
FreeCAD.ActiveDocument.openTransaction(translate("Current Tool","Tool Number to Load"))
- FreeCADGui.addModule("PathScripts.PathLoadTool")
snippet = '''
-import Path
-import PathScripts
-from PathScripts import PathProject, PathUtils
-prjexists = False
+import Path, PathScripts
+from PathScripts import PathUtils, PathLoadTool
+
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Tool")
PathScripts.PathLoadTool.LoadTool(obj)
-
PathScripts.PathLoadTool._ViewProviderLoadTool(obj.ViewObject)
PathUtils.addToProject(obj)
@@ -154,6 +151,18 @@ PathUtils.addToProject(obj)
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
+ @staticmethod
+ def Create():
+ #FreeCADGui.addModule("PathScripts.PathLoadTool")
+ import Path, PathScripts, PathUtils
+
+ obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Tool")
+ PathScripts.PathLoadTool.LoadTool(obj)
+ PathScripts.PathLoadTool._ViewProviderLoadTool(obj.ViewObject)
+
+ PathUtils.addToProject(obj)
+
+
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_LoadTool', CommandPathLoadTool())
diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py
index 14af80096..4ee8c193a 100644
--- a/src/Mod/Path/PathScripts/PathPocket.py
+++ b/src/Mod/Path/PathScripts/PathPocket.py
@@ -47,7 +47,7 @@ class ObjectPocket:
def __init__(self,obj):
- obj.addProperty("App::PropertyLinkSub","Base","Path",translate("PathProject","The base geometry of this object"))
+ obj.addProperty("App::PropertyLinkSubList","Base","Path",translate("PathProject","The base geometry of this object"))
obj.addProperty("App::PropertyBool","Active","Path",translate("PathProject","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile"))
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("PathProject", "The library to use to generate the path"))
@@ -59,29 +59,18 @@ class ObjectPocket:
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
- obj.addProperty("App::PropertyFloat", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
- obj.addProperty("App::PropertyFloat", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
+ obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
+ obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("PathProject","Incremental Step Down of Tool"))
obj.StepDown = (0.0, 0.01, 100.0, 0.5)
- obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
- obj.addProperty("App::PropertyFloat", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
- obj.addProperty("App::PropertyFloat", "FinishDepth", "Depth", translate("PathProject","Maximum material removed on final pass."))
- #obj.addProperty("App::PropertyFloat", "RetractHeight", "Depth", translate("PathProject","The height desired to retract tool when path is finished"))
-
- # #Feed Properties
- # obj.addProperty("App::PropertyFloatConstraint", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
- # obj.VertFeed = (0.0, 0.0, 100000.0, 1.0)
- # obj.addProperty("App::PropertyFloatConstraint", "HorizFeed", "Feed",translate("Horiz Feed","Feed rate for horizontal moves"))
- # obj.HorizFeed = (0.0, 0.0, 100000.0, 1.0)
-
- #Feed Properties
- 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"))
+ obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
+ obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
+ obj.addProperty("App::PropertyDistance", "FinishDepth", "Depth", translate("PathProject","Maximum material removed on final pass."))
#Pocket Properties
obj.addProperty("App::PropertyEnumeration", "CutMode", "Pocket",translate("PathProject", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
obj.CutMode = ['Climb','Conventional']
- obj.addProperty("App::PropertyFloat", "MaterialAllowance", "Pocket", translate("PathProject","Amount of material to leave"))
+ obj.addProperty("App::PropertyDistance", "MaterialAllowance", "Pocket", translate("PathProject","Amount of material to leave"))
obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket",translate("PathProject", "Start pocketing at center or boundary"))
obj.StartAt = ['Center', 'Edge']
obj.addProperty("App::PropertyFloatConstraint","StepOver","Pocket",translate("PathProject","Amount to step over on each pass"))
@@ -122,7 +111,21 @@ class ObjectPocket:
def __setstate__(self,state):
return None
-
+
+ def addpocketbase(self, obj, ss, sub=""):
+ #sublist = []
+ #sublist.append(sub)
+ baselist = obj.Base
+ if baselist == None:
+ baselist = []
+ item = (ss, sub)
+ if item in baselist:
+ FreeCAD.Console.PrintWarning("this object already in the list"+ "\n")
+ else:
+ baselist.append (item)
+ obj.Base = baselist
+ print "this base is: " + str(baselist)
+ self.execute(obj)
def getStock(self,obj):
"retrieves a stock object from hosting project if any"
@@ -144,10 +147,10 @@ class ObjectPocket:
FreeCAD.Console.PrintMessage(translate("PathPocket","Generating toolpath with libarea offsets.\n"))
- depthparams = depth_params (obj.ClearanceHeight, obj.SafeHeight, obj.StartDepth, obj.StepDown, obj.FinishDepth, obj.FinalDepth)
+ depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value)
- horizfeed = obj.HorizFeed.Value
- extraoffset = obj.MaterialAllowance
+ horizfeed = self.horizFeed
+ extraoffset = obj.MaterialAllowance.Value
stepover = obj.StepOver
use_zig_zag = obj.UseZigZag
zig_angle = obj.ZigZagAngle
@@ -159,15 +162,26 @@ class ObjectPocket:
PathAreaUtils.flush_nc()
PathAreaUtils.output('mem')
- PathAreaUtils.feedrate_hv(obj.HorizFeed.Value, obj.VertFeed.Value)
+ PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
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)
+ #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)
- PathAreaUtils.pocket(a,self.radius,extraoffset, stepover,depthparams,from_center,keep_tool_down,use_zig_zag,zig_angle,zig_unidirectional,start_point,cut_mode)
+ PathAreaUtils.pocket(a,\
+ self.radius,\
+ extraoffset, \
+ stepover,\
+ depthparams,\
+ from_center,\
+ keep_tool_down,\
+ use_zig_zag,\
+ zig_angle,\
+ zig_unidirectional,\
+ start_point,\
+ cut_mode)
return PathAreaUtils.retrieve_gcode()
@@ -197,9 +211,9 @@ class ObjectPocket:
global feedxy
retstr = "G01 F"
if(x == None) and (y == None):
- retstr += str("%.4f" % obj.HorizFeed.Value)
+ retstr += str("%.4f" % self.horizFeed)
else:
- retstr += str("%.4f" % obj.VertFeed.Value)
+ retstr += str("%.4f" % self.vertFeed)
if (x != None) or (y != None) or (z != None):
if (x != None):
@@ -228,7 +242,7 @@ class ObjectPocket:
retstr += "G03 F"
else:
retstr += "G02 F"
- retstr += str(obj.HorizFeed.Value)
+ retstr += str(self.horizFeed)
#End location
retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey)
@@ -350,16 +364,16 @@ class ObjectPocket:
# first move will be rapid, subsequent will be at feed rate
first = True
startPoint = None
- fastZPos = max(obj.StartDepth + 2, obj.ClearanceHeight)
+ fastZPos = max(obj.StartDepth.Value + 2, obj.ClearanceHeight.Value)
# revert the list so we start with the outer wires
if obj.StartAt != 'Edge':
offsets.reverse()
-# print "startDepth: " + str(obj.StartDepth)
-# print "finalDepth: " + str(obj.FinalDepth)
+# print "startDepth: " + str(obj.StartDepth.Value)
+# print "finalDepth: " + str(obj.FinalDepth.Value)
# print "stepDown: " + str(obj.StepDown)
-# print "finishDepth" + str(obj.FinishDepth)
+# print "finishDepth" + str(obj.FinishDepth.Value)
# print "offsets:", len(offsets)
#Fraction of tool radius our plunge helix is to be
@@ -421,7 +435,7 @@ class ObjectPocket:
#FIXME: Can probably get this from the "machine"?
lastZ = fastZPos
- for vpos in PathUtils.frange(obj.StartDepth, obj.FinalDepth, obj.StepDown, obj.FinishDepth):
+ for vpos in PathUtils.frange(obj.StartDepth.Value, obj.FinalDepth.Value, obj.StepDown, obj.FinishDepth.Value):
#Every for every depth we should helix down
first = True
# loop over successive wires
@@ -483,71 +497,77 @@ class ObjectPocket:
#To reload this from FreeCAD, use: import PathScripts.PathPocket; reload(PathScripts.PathPocket)
def execute(self,obj):
+ output = ""
+ toolLoad = PathUtils.getLastToolLoad(obj)
+ if toolLoad == None:
+ self.vertFeed = 100
+ self.horizFeed = 100
+ self.radius = 0.25
+ obj.ToolNumber = 0
+ else:
+ self.vertFeed = toolLoad.VertFeed.Value
+ self.horizFeed = toolLoad.HorizFeed.Value
+ tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
+ self.radius = tool.Diameter/2
+ obj.ToolNumber= toolLoad.ToolNumber
+
+
if obj.Base:
-
- import Part, PathScripts.PathKurveUtils, DraftGeomUtils
- if "Face" in obj.Base[1][0]:
- shape = getattr(obj.Base[0].Shape,obj.Base[1][0])
- wire = shape.OuterWire
- edges = wire.Edges
- else:
- edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
- print "myedges: " + str(edges)
- wire = Part.Wire(edges)
- shape = None
-
- # tie the toolnumber to the PathLoadTool object ToolNumber
- if len(obj.InList)>0: #check to see if obj is in the Project group yet
- project = obj.InList[0]
- tl = int(PathUtils.changeTool(obj,project))
- obj.ToolNumber= tl
-
- tool = PathUtils.getTool(obj,obj.ToolNumber)
- if tool:
- self.radius = tool.Diameter/2
- else:
- # temporary value,in case we don't have any tools defined already
- self.radius = 0.25
-
- output = ""
- if obj.Algorithm == "OCC Native":
- if shape == None:
- shape = wire
- output += self.buildpathocc(obj, shape)
- else:
- try:
- import area
- except:
- FreeCAD.Console.PrintError(translate("PathKurve","libarea needs to be installed for this command to work.\n"))
- return
-
- a = area.Area()
- if shape == None:
- c = PathScripts.PathKurveUtils.makeAreaCurve(wire.Edges, 'CW')
- a.append(c)
+ for b in obj.Base:
+ print "object base: " + str(b)
+ import Part, PathScripts.PathKurveUtils, DraftGeomUtils
+ if "Face" in b[1]:
+ print "inside"
+ shape = getattr(b[0].Shape,b[1])
+ wire = shape.OuterWire
+ edges = wire.Edges
else:
- for w in shape.Wires:
- c = PathScripts.PathKurveUtils.makeAreaCurve(w.Edges, 'CW')
- # if w.isSame(shape.OuterWire):
- # print "outerwire"
- # if c.IsClockwise():
- # c.Reverse()
- # print "reverse outterwire"
- # else:
- # print "inner wire"
- # if not c.IsClockwise():
- # c.Reverse()
- # print "reverse inner"
- a.append(c)
+ print "in else"
+ edges = [getattr(b[0].Shape,sub) for sub in b[1]]
+ print "myedges: " + str(edges)
+ wire = Part.Wire(edges)
+ shape = None
- ########
- ##This puts out some interesting information from libarea
- print a.text()
- ########
-
-
- a.Reorder()
- output += self.buildpathlibarea(obj, a)
+
+ # output = ""
+ if obj.Algorithm == "OCC Native":
+ if shape == None:
+ shape = wire
+ output += self.buildpathocc(obj, shape)
+ else:
+ try:
+ import area
+ except:
+ FreeCAD.Console.PrintError(translate("PathKurve","libarea needs to be installed for this command to work.\n"))
+ return
+
+ a = area.Area()
+ if shape == None:
+ c = PathScripts.PathKurveUtils.makeAreaCurve(wire.Edges, 'CW')
+ a.append(c)
+ else:
+ for w in shape.Wires:
+ c = PathScripts.PathKurveUtils.makeAreaCurve(w.Edges, 'CW')
+ # if w.isSame(shape.OuterWire):
+ # print "outerwire"
+ # if c.IsClockwise():
+ # c.Reverse()
+ # print "reverse outterwire"
+ # else:
+ # print "inner wire"
+ # if not c.IsClockwise():
+ # c.Reverse()
+ # print "reverse inner"
+ a.append(c)
+
+ ########
+ ##This puts out some interesting information from libarea
+ print a.text()
+ ########
+
+
+ a.Reorder()
+ output += self.buildpathlibarea(obj, a)
if obj.Active:
@@ -586,14 +606,11 @@ class ViewProviderPocket:
return
def setEdit(self,vobj,mode=0):
- import PocketEdit
FreeCADGui.Control.closeDialog()
- taskd = QtGui.QWidget()
- taskd = PocketEdit.Ui_Dialog()
+ taskd = TaskPanel()
taskd.obj = vobj.Object
- #taskd.update()
FreeCADGui.Control.showDialog(taskd)
-
+ taskd.setupUi()
return True
def getIcon(self):
@@ -621,37 +638,40 @@ class CommandPathPocket:
def Activated(self):
# check that the selection contains exactly what we want
- selection = FreeCADGui.Selection.getSelectionEx()
- if len(selection) != 1:
- FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
- return
- if len(selection[0].SubObjects) == 0:
- FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
- return
- for s in selection[0].SubObjects:
- if s.ShapeType != "Edge":
- if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
- FreeCAD.Console.PrintError(translate("PathPocket","Please select only edges or a single face\n"))
- return
- if selection[0].SubObjects[0].ShapeType == "Edge":
- try:
- import Part
- w = Part.Wire(selection[0].SubObjects)
- if w.isClosed() == False:
- FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
- return
+ # selection = FreeCADGui.Selection.getSelectionEx()
+ # if len(selection) != 1:
+ # FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
+ # return
+ # if len(selection[0].SubObjects) == 0:
+ # FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
+ # return
+ # for s in selection[0].SubObjects:
+ # if s.ShapeType != "Edge":
+ # if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
+ # FreeCAD.Console.PrintError(translate("PathPocket","Please select only edges or a single face\n"))
+ # return
+ # if selection[0].SubObjects[0].ShapeType == "Edge":
+ # try:
+ # import Part
+ # w = Part.Wire(selection[0].SubObjects)
+ # if w.isClosed() == False:
+ # FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
+ # return
- except:
- FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
- return
+ # except:
+ # FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
+ # return
# Take a guess at some reasonable values for Finish depth.
- bb = selection[0].Object.Shape.BoundBox #parent boundbox
- fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
- if fbb.ZMax < bb.ZMax:
- zbottom = fbb.ZMax
- else:
- zbottom = bb.ZMin
+ # bb = selection[0].Object.Shape.BoundBox #parent boundbox
+ # fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
+ # if fbb.ZMax < bb.ZMax:
+ # zbottom = fbb.ZMax
+ # else:
+ # zbottom = bb.ZMin
+
+ zbottom = 0.0
+ ztop = 10.0
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction(translate("PathPocket","Create Pocket"))
@@ -663,19 +683,13 @@ class CommandPathPocket:
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('PathScripts.PathPocket.ViewProviderPocket(obj.ViewObject)')
- subs = "["
- for s in selection[0].SubElementNames:
- subs += '"' + s + '",'
- subs += "]"
- FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
-
FreeCADGui.doCommand('from PathScripts import PathUtils')
FreeCADGui.doCommand('obj.StepOver = 1.0')
- FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 2.0))
+ FreeCADGui.doCommand('obj.ClearanceHeight = 10')# + str(bb.ZMax + 2.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
- FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
+ FreeCADGui.doCommand('obj.StartDepth= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('obj.ZigZagAngle=45')
FreeCADGui.doCommand('obj.UseEntry=True')
@@ -687,7 +701,172 @@ class CommandPathPocket:
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/PocketEdit.ui")
+ #self.form = FreeCADGui.PySideUic.loadUi(":/PocketEdit.ui")
+ self.updating = False
+
+
+ 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,"StepDown"):
+ self.obj.StepDown = self.form.stepDown.value()
+ if hasattr(self.obj,"MaterialAllowance"):
+ self.obj.MaterialAllowance = self.form.extraOffset.value()
+ if hasattr(self.obj,"UseStartPoint"):
+ self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
+ if hasattr(self.obj,"Algorithm"):
+ self.obj.Algorithm = str(self.form.algorithmSelect.currentText())
+ if hasattr(self.obj,"CutMode"):
+ self.obj.CutMode = str(self.form.cutMode.currentText())
+ 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("PathProject","Please select at least one profileable object\n"))
+ return
+ for s in selection:
+ if s.HasSubObjects:
+ for i in s.SubElementNames:
+ self.obj.Proxy.addpocketbase(self.obj, s.Object, i)
+ else:
+ self.obj.Proxy.addpocketbase(self.obj, s.Object)
+
+ self.form.baseList.clear()
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name + "." + i[1])
+
+ 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])
+ # sub = o.Shape.getElement(objstring[2])
+ 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)
+
+
+ def edit(self,item,column):
+ if not self.updating:
+ self.resetObject()
+
+ 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.stepDown.setValue(self.obj.StepDown)
+ self.form.extraOffset.setValue(self.obj.MaterialAllowance.Value)
+ self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
+
+ index = self.form.algorithmSelect.findText(self.obj.Algorithm, QtCore.Qt.MatchFixedString)
+ if index >= 0:
+ self.form.algorithmSelect.setCurrentIndex(index)
+
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name + "." + i[1])
+
+ #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)
+
+ #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.algorithmSelect.currentIndexChanged.connect(self.getFields)
+ self.form.cutMode.currentIndexChanged.connect(self.getFields)
+ self.form.useStartPoint.clicked.connect(self.getFields)
+ self.form.extraOffset.editingFinished.connect(self.getFields)
+
+
+class SelObserver:
+ def __init__(self):
+ import PathScripts.PathSelection as PST
+ PST.pocketselect()
+
+ 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/PathProfile.py b/src/Mod/Path/PathScripts/PathProfile.py
index 863a0ffbf..aeea2a426 100644
--- a/src/Mod/Path/PathScripts/PathProfile.py
+++ b/src/Mod/Path/PathScripts/PathProfile.py
@@ -24,13 +24,14 @@
import FreeCAD,Path
from FreeCAD import Vector
-from PathScripts import PathUtils,PathSelection,PathProject
+from PathScripts import PathUtils #,PathSelection,PathProject
+from PathScripts.PathUtils import depth_params
if FreeCAD.GuiUp:
- import FreeCADGui, PathGui
+ import FreeCADGui
from PySide import QtCore, QtGui
from DraftTools import translate
- from pivy import coin
+ #from pivy import coin
else:
def translate(ctxt,txt):
return txt
@@ -50,38 +51,15 @@ except AttributeError:
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig)
-def makeProfile(self, name="Profile"):
- '''creates a Profile operation'''
-
- #obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",name)
- #obj.Label = translate("Path",name)
- obj=self
- ObjectProfile(obj)
- if FreeCAD.GuiUp:
- _ViewProviderProfile(obj.ViewObject)
-
- locations = []
- angles = []
- lengths = []
- heights = []
-
- obj.locs = locations
- obj.angles = angles
- obj.lengths = lengths
- obj.heights = heights
- FreeCAD.ActiveDocument.recompute()
- return obj
-
-
class ObjectProfile:
def __init__(self,obj):
- obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
+ obj.addProperty("App::PropertyLinkSubList","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Path","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString","Comment","Path",translate("Path","An optional comment for this profile"))
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("Path", "The library or algorithm used to generate the path"))
- obj.Algorithm = ['OCC Native','libarea']
+ obj.Algorithm = ['OCC Native','libareal']
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("Path","The tool number in use"))
obj.ToolNumber = (0,0,1000,1)
@@ -94,12 +72,7 @@ class ObjectProfile:
obj.StepDown = (1,0.01,1000,0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("Path","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Path","Final Depth of Tool- lowest value in Z"))
- #obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", translate("Retract Height","The height desired to retract tool when path is finished"))
-
- #Feed Properties
- 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"))
-
+
#Start Point Properties
obj.addProperty("App::PropertyVector","StartPoint","Start Point",translate("Path_Profile","The start point of this path"))
obj.addProperty("App::PropertyBool","UseStartPoint","Start Point",translate("Path_Profile","make True, if specifying a Start Point"))
@@ -128,6 +101,15 @@ class ObjectProfile:
obj.addProperty("App::PropertyFloatList","angles","Tags", translate("Path_Profile", "List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList","heights","Tags", translate("Path_Profile", "List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList","lengths","Tags", translate("Path_Profile", "List of angles for the holding tags"))
+ locations = []
+ angles = []
+ lengths = []
+ heights = []
+
+ obj.locs = locations
+ obj.angles = angles
+ obj.lengths = lengths
+ obj.heights = heights
obj.Proxy = self
@@ -137,142 +119,176 @@ class ObjectProfile:
def __setstate__(self,state):
return None
- def execute(self,obj):
- import Part, DraftGeomUtils, math
+ def addprofilebase(self, obj, ss, sub=""):
+ baselist = obj.Base
+ item = (ss, sub)
+ if item in baselist:
+ FreeCAD.Console.PrintWarning("this object already in the list"+ "\n")
+ else:
+ baselist.append (item)
+ obj.Base = baselist
+ self.execute(obj)
+
+ def _buildPathOCC(self,obj,wire):
+ import DraftGeomUtils
+ output = ""
+ output += '('+ str(obj.Comment)+')\n'
+
+ if obj.Direction == 'CCW':
+ clockwise=False
+ else:
+ clockwise=True
+
+ FirstEdge= None
+ PathClosed = DraftGeomUtils.isReallyClosed(wire)
+
+ output += PathUtils.MakePath(wire, \
+ obj.Side, \
+ self.radius, \
+ clockwise, \
+ obj.ClearanceHeight.Value, \
+ obj.StepDown, \
+ obj.StartDepth.Value, \
+ obj.FinalDepth.Value, \
+ FirstEdge, \
+ PathClosed, \
+ obj.SegLen.Value, \
+ self.vertFeed, \
+ self.horizFeed)
+
+ return output
+
+ def _buildPathLibarea(self,obj, edgelist):
import PathScripts.PathKurveUtils as PathKurveUtils
- from PathScripts.PathUtils import depth_params
+ import math, area
+ output = ""
+
+ if obj.StartPoint and obj.UseStartPoint:
+ startpoint = obj.StartPoint
+ else:
+ startpoint = None
+
+ if obj.EndPoint and obj.UseEndPoint:
+ endpoint = obj.EndPoint
+ else:
+ endpoint = None
+
+
+ PathKurveUtils.output('mem')
+ PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed)
+
+ output = ""
+ output += "G0 Z" + str(obj.ClearanceHeight.Value)
+ curve = PathKurveUtils.makeAreaCurve(edgelist,obj.Direction,startpoint, endpoint)
+
+ '''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
+print "x = " + str(point.x)
+print "y - " + str(point.y)
+ holding tags
+ start location
+ CRC
+ or probably other features in heekscnc'''
+ #output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
+
+ '''The following calls the original procedure from heekscnc profile function. This, in turn, calls many other procedures to modify the profile.
+ This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be
+ thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
+ roll_radius = 2.0
+ extend_at_start = 0.0
+ extend_at_end = 0.0
+ lead_in_line_len=0.0
+ lead_out_line_len= 0.0
+
+ '''
+
+ Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils.
+ I need to access the location vector, length, angle in radians and height.
+
+ '''
+ PathKurveUtils.clear_tags()
+ for i in range(len(obj.locs)):
+ tag = obj.locs[i]
+ h = obj.heights[i]
+ l = obj.lengths[i]
+ a = math.radians(obj.angles[i])
+ PathKurveUtils.add_tag(area.Point(tag.x,tag.y), l, a, h)
+
+ depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
+
+ PathKurveUtils.profile2(curve, \
+ obj.Side, \
+ self.radius, \
+ self.vertFeed, \
+ self.horizFeed, \
+ obj.OffsetExtra.Value,\
+ roll_radius, \
+ None,\
+ None, \
+ depthparams, \
+ extend_at_start, \
+ extend_at_end, \
+ lead_in_line_len,\
+ lead_out_line_len)
+
+ output += PathKurveUtils.retrieve_gcode()
+ return output
+
+ def execute(self,obj):
+ import Part #math #DraftGeomUtils
+ output = ""
+ toolLoad = PathUtils.getLastToolLoad(obj)
+ if toolLoad == None:
+ self.vertFeed = 100
+ self.horizFeed = 100
+ self.radius = 0.25
+ obj.ToolNumber= 0
+ else:
+ self.vertFeed = toolLoad.VertFeed.Value
+ self.horizFeed = toolLoad.HorizFeed.Value
+ tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
+ self.radius = tool.Diameter/2
+ obj.ToolNumber= toolLoad.ToolNumber
if obj.Base:
- # tie the toolnumber to the PathLoadTool object ToolNumber
- if len(obj.InList)>0: #check to see if obj is in the Project group yet
- project = obj.InList[0]
- tl = int(PathUtils.changeTool(obj,project))
- obj.ToolNumber= tl
-
- tool = PathUtils.getTool(obj,obj.ToolNumber)
- if tool:
- radius = tool.Diameter/2
- else:
- # temporary value,in case we don't have any tools defined already
- radius = 0.25
-
- depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
-
- clearance = obj.ClearanceHeight.Value
- step_down=obj.StepDown
- start_depth=obj.StartDepth.Value
- final_depth=obj.FinalDepth.Value
- rapid_safety_space=obj.SafeHeight.Value
-
- side=obj.Side
- offset_extra=obj.OffsetExtra.Value
- use_CRC=obj.UseComp
- vf=obj.VertFeed.Value
- hf=obj.HorizFeed.Value
- seglen=obj.SegLen.Value
- direction = obj.Direction
-
-
+ for b in obj.Base:
+
# we only consider the outer wire if this is a Face
- shape = getattr(obj.Base[0].Shape,obj.Base[1][0])
- if shape.ShapeType in ["Edge"]:
- edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
- wire = Part.Wire(edges)
-
- if not wire.Edges[0].isSame(shape):
- wire.Edges.reverse()
+ #shape = getattr(obj.Base[0][0].Shape,obj.Base[0][1])
+ shape = getattr(b[0].Shape,b[1])
- else:
- wire = shape.OuterWire
-
- edgelist = wire.Edges
- #edgelist = Part.__sortEdges__(wire.Edges)
-
- if obj.StartPoint and obj.UseStartPoint:
- startpoint = obj.StartPoint
- else:
- startpoint = None
-
- if obj.EndPoint and obj.UseEndPoint:
- endpoint = obj.EndPoint
- else:
- endpoint = None
+ if shape.ShapeType in ["Edge"]:
+ edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
+ wire = Part.Wire(edges)
- edgelist = Part.__sortEdges__(edgelist)
-
- if obj.Algorithm == "OCC Native":
- output = ""
- output += '('+ str(obj.Comment)+')\n'
+ if not wire.Edges[0].isSame(shape):
+ wire.Edges.reverse()
- if obj.Direction == 'CCW':
- clockwise=False
else:
- clockwise=True
+ wire = shape.OuterWire
- FirstEdge= None
- PathClosed = DraftGeomUtils.isReallyClosed(wire)
+ edgelist = wire.Edges
+ edgelist = Part.__sortEdges__(edgelist)
+
+ if obj.Algorithm == "OCC Native":
+ output += self._buildPathOCC(obj, wire)
+
+ else:
+ try:
+ import area
+ except:
+ FreeCAD.Console.PrintError(translate("Path","libarea needs to be installed for this command to work.\n"))
+ return
+ output += self._buildPathLibarea(obj,edgelist)
- output += PathUtils.MakePath(wire, side, radius, clockwise, clearance, step_down, start_depth, final_depth, FirstEdge, PathClosed, seglen, vf, hf)
-
- else:
- try:
- import area
- except:
- FreeCAD.Console.PrintError(translate("Path","libarea needs to be installed for this command to work.\n"))
- return
-
- PathKurveUtils.output('mem')
- PathKurveUtils.feedrate_hv(obj.HorizFeed.Value, obj.VertFeed.Value)
-
- output = ""
- output += "G0 Z" + str(clearance)
- curve = PathKurveUtils.makeAreaCurve(edgelist,direction,startpoint, endpoint)
-
- '''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
- print "x = " + str(point.x)
- print "y - " + str(point.y)
- holding tags
- start location
- CRC
- or probably other features in heekscnc'''
- #output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
-
- '''The following calls the original procedure from heekscnc profile function. This, in turn, calls many other procedures to modify the profile.
- This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be
- thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
- roll_radius = 2.0
- extend_at_start = 0.0
- extend_at_end = 0.0
- lead_in_line_len=0.0
- lead_out_line_len= 0.0
-
- '''
-
- Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils.
- I need to access the location vector, length, angle in radians and height.
-
- '''
- PathKurveUtils.clear_tags()
- for i in range(len(obj.locs)):
- tag = obj.locs[i]
- h = obj.heights[i]
- l = obj.lengths[i]
- a = math.radians(obj.angles[i])
- PathKurveUtils.add_tag(area.Point(tag.x,tag.y), l, a, h)
-
- PathKurveUtils.profile2(curve, side, radius, vf, hf, offset_extra, roll_radius, None,None, depthparams, extend_at_start, extend_at_end, lead_in_line_len,lead_out_line_len)
- output += PathKurveUtils.retrieve_gcode()
-
- if obj.Active:
- path = Path.Path(output)
- obj.Path = path
- obj.ViewObject.Visibility = True
-
- else:
- path = Path.Path("(inactive operation)")
- obj.Path = path
- obj.ViewObject.Visibility = False
+ if obj.Active:
+ path = Path.Path(output)
+ obj.Path = path
+ obj.ViewObject.Visibility = True
+ else:
+ path = Path.Path("(inactive operation)")
+ obj.Path = path
+ obj.ViewObject.Visibility = False
class _ViewProviderProfile:
@@ -285,10 +301,10 @@ class _ViewProviderProfile:
def setEdit(self,vobj,mode=0):
FreeCADGui.Control.closeDialog()
- taskd = _EditPanel()
+ taskd = TaskPanel()
taskd.obj = vobj.Object
- taskd.update()
FreeCADGui.Control.showDialog(taskd)
+ taskd.setupUi()
return True
def getIcon(self):
@@ -332,8 +348,6 @@ class _CommandAddTag:
obj.lengths = l
obj.angles = a
-
-
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
@@ -384,60 +398,26 @@ class CommandPathProfile:
return not FreeCAD.ActiveDocument is None
def Activated(self):
- import Path
- from PathScripts import PathProject, PathUtils, PathKurveUtils
+ #import Path
+ #from PathScripts import PathProject, PathUtils, PathKurveUtils
- # check that the selection contains exactly what we want
- selection = FreeCADGui.Selection.getSelectionEx()
- if len(selection) != 1:
- FreeCAD.Console.PrintError(translate("Path","Select one or more edges or a face from one Document object.\n"))
- return
- if len(selection[0].SubObjects) == 0:
- FreeCAD.Console.PrintError(translate("Path","Select one or more edges or a face from one Document object.\n"))
- return
- for s in selection[0].SubObjects:
- if s.ShapeType != "Edge":
- if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
- FreeCAD.Console.PrintError(translate("Path","Please select only edges or a single face\n"))
- return
- if selection[0].SubObjects[0].ShapeType == "Edge":
- try:
- import Part
- w = Part.Wire(selection[0].SubObjects)
- except:
- FreeCAD.Console.PrintError(translate("Path","The selected edges don't form a loop\n"))
- return
+ ztop = 10.0
+ zbottom = 0.0
- # if everything is ok, execute and register the transaction in the undo/redo stack
-
- # Take a guess at some reasonable values for Finish depth.
- bb = selection[0].Object.Shape.BoundBox #parent boundbox
- fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
- if fbb.ZMax < bb.ZMax:
- zbottom = fbb.ZMax
- else:
- zbottom = bb.ZMin
-
- FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Profile operation using libarea"))
+ FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Profile"))
FreeCADGui.addModule("PathScripts.PathProfile")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Profile")')
- FreeCADGui.doCommand('PathScripts.PathProfile.makeProfile(obj)')
- #FreeCADGui.doCommand('PathScripts.PathProfile.ObjectProfile(obj)')
+ FreeCADGui.doCommand('PathScripts.PathProfile.ObjectProfile(obj)')
+ FreeCADGui.doCommand('PathScripts.PathProfile._ViewProviderProfile(obj.ViewObject)')
FreeCADGui.doCommand('obj.Active = True')
- subs ="["
- for s in selection[0].SubElementNames:
- subs += '"' + s + '",'
- subs += "]"
- FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
- #FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
- FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 10.0))
+ FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 10.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
- FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
+ FreeCADGui.doCommand('obj.StartDepth= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
- FreeCADGui.doCommand('obj.SafeHeight = '+ str(bb.ZMax + 2.0))
+ FreeCADGui.doCommand('obj.SafeHeight = '+ str(ztop + 2.0))
FreeCADGui.doCommand('obj.Side = "Left"')
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
FreeCADGui.doCommand('obj.Direction = "CW"')
@@ -446,100 +426,126 @@ class CommandPathProfile:
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.doCommand('obj.ViewObject.startEditing()')
-class _EditPanel:
- '''The editmode TaskPanel for profile tags'''
+class TaskPanel:
def __init__(self):
- # the panel has a tree widget that contains categories
- # for the subcomponents, such as additions, subtractions.
- # the categories are shown only if they are not empty.
-
+ self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/ProfileEdit.ui")
+ #self.form = FreeCADGui.PySideUic.loadUi(":/ProfileEdit.ui")
self.updating = False
- self.obj = None
- self.form = QtGui.QWidget()
- self.form.setObjectName("TaskPanel")
- self.grid = QtGui.QGridLayout(self.form)
- self.grid.setObjectName("grid")
- self.title = QtGui.QLabel(self.form)
- self.grid.addWidget(self.title, 0, 0, 1, 2)
- # tree
- self.tree = QtGui.QTreeWidget(self.form)
- self.grid.addWidget(self.tree, 1, 0, 1, 2)
- self.tree.setColumnCount(4)
- self.tree.header().resizeSection(0,50)
- self.tree.header().resizeSection(1,80)
- self.tree.header().resizeSection(2,60)
- self.tree.header().resizeSection(3,60)
+ def accept(self):
+ self.getFields()
- # buttons
- self.addButton = QtGui.QPushButton(self.form)
- self.addButton.setObjectName("addButton")
- self.addButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
- self.grid.addWidget(self.addButton, 3, 0, 1, 1)
- self.addButton.setEnabled(True)
+ FreeCADGui.ActiveDocument.resetEdit()
+ FreeCADGui.Control.closeDialog()
+ FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.Selection.removeObserver(self.s)
- self.delButton = QtGui.QPushButton(self.form)
- self.delButton.setObjectName("delButton")
- self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
- self.grid.addWidget(self.delButton, 3, 1, 1, 1)
- self.delButton.setEnabled(True)
+ def reject(self):
+ FreeCADGui.Control.closeDialog()
+ FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.Selection.removeObserver(self.s)
- QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement)
- QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement)
- QtCore.QObject.connect(self.tree, QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"), self.edit)
- self.update()
- self.retranslateUi(self.form)
+ 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,"StepDown"):
+ self.obj.StepDown = self.form.stepDown.value()
+ if hasattr(self.obj,"OffsetExtra"):
+ self.obj.OffsetExtra = self.form.extraOffset.value()
+ if hasattr(self.obj,"SegLen"):
+ self.obj.SegLen = self.form.segLen.value()
+ if hasattr(self.obj,"RollRadius"):
+ self.obj.RollRadius = self.form.rollRadius.value()
+ if hasattr(self.obj,"UseComp"):
+ self.obj.UseComp = self.form.useCompensation.isChecked()
+ if hasattr(self.obj,"UseStartPoint"):
+ self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
+ if hasattr(self.obj,"UseEndPoint"):
+ self.obj.UseEndPoint = self.form.useEndPoint.isChecked()
+ if hasattr(self.obj,"Algorithm"):
+ self.obj.Algorithm = str(self.form.algorithmSelect.currentText())
+ 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())
+ self.obj.Proxy.execute(self.obj)
- def isAllowedAlterSelection(self):
- return False
+ def open(self):
+ self.s =SelObserver()
+ # install the function mode resident
+ FreeCADGui.Selection.addObserver(self.s)
- def isAllowedAlterView(self):
- return True
+ 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("PathProject","Please select at least one profileable object\n"))
+ return
+ for s in selection:
+ if s.HasSubObjects:
+ for i in s.SubElementNames:
+ self.obj.Proxy.addprofilebase(self.obj, s.Object, i)
+ else:
+ self.obj.Proxy.addprofilebase(self.obj, s.Object)
+
+ self.form.baseList.clear()
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name + "." + i[1])
+
+ 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])
+ # sub = o.Shape.getElement(objstring[2])
+ 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.Close)
+ return int(QtGui.QDialogButtonBox.Ok)
- def update(self):
- 'fills the treewidget'
- self.updating = True
- self.tree.clear()
- if self.obj:
- for i in range(len(self.obj.locs)):
- item = QtGui.QTreeWidgetItem(self.tree)
- item.setText(0,str(i+1))
- l = self.obj.locs[i]
- item.setText(1,str(l.x)+", " + str(l.y) +", " + str(l.z))
- item.setText(2,str(self.obj.heights[i]))
- item.setText(3,str(self.obj.lengths[i]))
- item.setText(4,str(self.obj.angles[i]))
- item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
- item.setTextAlignment(0,QtCore.Qt.AlignLeft)
- self.retranslateUi(self.form)
- self.updating = False
- return
-
- def addElement(self):
- self.updating = True
-
- item = QtGui.QTreeWidgetItem(self.tree)
- item.setText(0,str(self.tree.topLevelItemCount()))
- item.setText(1,"0.0, 0.0, 0.0")
- item.setText(2, str(float(4.0)))
- item.setText(3, str(float(10.0)))
- item.setText(4, str(float(45.0)))
- item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
- self.updating = False
-
- self.resetObject()
-
- def removeElement(self):
- it = self.tree.currentItem()
- if it:
- nr = int(it.text(0))-1
- self.resetObject(remove=nr)
- self.update()
def edit(self,item,column):
if not self.updating:
@@ -552,8 +558,8 @@ class _EditPanel:
l = []
a = []
- for i in range(self.tree.topLevelItemCount()):
- it = self.tree.findItems(str(i+1),QtCore.Qt.MatchExactly,0)[0]
+ for i in range(self.form.tagTree.topLevelItemCount()):
+ it = self.form.tagTree.findItems(str(i+1),QtCore.Qt.MatchExactly,0)[0]
if (remove == None) or (remove != i):
if it.text(1):
x = float(it.text(1).split()[0].rstrip(","))
@@ -584,21 +590,130 @@ class _EditPanel:
self.obj.touch()
FreeCAD.ActiveDocument.recompute()
- def reject(self):
- FreeCAD.ActiveDocument.recompute()
- FreeCADGui.ActiveDocument.resetEdit()
- return True
+ def addElement(self):
+ self.updating = True
- def retranslateUi(self, TaskPanel=None):
- TaskPanel.setWindowTitle(QtGui.QApplication.translate("Path", "Holding Tags", None, QtGui.QApplication.UnicodeUTF8))
- self.delButton.setText(QtGui.QApplication.translate("Path", "Remove", None, QtGui.QApplication.UnicodeUTF8))
- self.addButton.setText(QtGui.QApplication.translate("Path", "Add", None, QtGui.QApplication.UnicodeUTF8))
- self.title.setText(QtGui.QApplication.translate("Path", "Tag Locations and Properties", None, QtGui.QApplication.UnicodeUTF8))
- self.tree.setHeaderLabels([QtGui.QApplication.translate("Path", "", None, QtGui.QApplication.UnicodeUTF8),
- QtGui.QApplication.translate("Path", "Location", None, QtGui.QApplication.UnicodeUTF8),
- QtGui.QApplication.translate("Path", "Height", None, QtGui.QApplication.UnicodeUTF8),
- QtGui.QApplication.translate("Path", "Length", None, QtGui.QApplication.UnicodeUTF8),
- QtGui.QApplication.translate("Path", "Angle", None, QtGui.QApplication.UnicodeUTF8)])
+ item = QtGui.QTreeWidgetItem(self.form.tagTree)
+ item.setText(0,str(self.form.tagTree.topLevelItemCount()))
+ item.setText(1,"0.0, 0.0, 0.0")
+ item.setText(2, str(float(4.0)))
+ item.setText(3, str(float(10.0)))
+ item.setText(4, str(float(45.0)))
+ item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
+ self.updating = False
+
+ self.resetObject()
+
+ def removeElement(self):
+ it = self.form.tagTree.currentItem()
+ if it:
+ nr = int(it.text(0))-1
+ self.resetObject(remove=nr)
+ self.update()
+
+ def update(self):
+ 'fills the treewidget'
+ self.updating = True
+ self.form.tagTree.clear()
+ if self.obj:
+ for i in range(len(self.obj.locs)):
+ item = QtGui.QTreeWidgetItem(self.form.tagTree)
+ item.setText(0,str(i+1))
+ l = self.obj.locs[i]
+ item.setText(1,str(l.x)+", " + str(l.y) +", " + str(l.z))
+ item.setText(2,str(self.obj.heights[i]))
+ item.setText(3,str(self.obj.lengths[i]))
+ item.setText(4,str(self.obj.angles[i]))
+ item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
+ item.setTextAlignment(0,QtCore.Qt.AlignLeft)
+ self.updating = False
+ return
+
+ 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.stepDown.setValue(self.obj.StepDown)
+ self.form.extraOffset.setValue(self.obj.OffsetExtra.Value)
+ self.form.segLen.setValue(self.obj.SegLen.Value)
+ self.form.rollRadius.setValue(self.obj.RollRadius.Value)
+ self.form.useCompensation.setChecked(self.obj.UseComp)
+ self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
+ self.form.useEndPoint.setChecked(self.obj.UseEndPoint)
+
+ index = self.form.algorithmSelect.findText(self.obj.Algorithm, QtCore.Qt.MatchFixedString)
+ if index >= 0:
+ self.form.algorithmSelect.setCurrentIndex(index)
+
+ index = self.form.cutSide.findText(self.obj.Side, QtCore.Qt.MatchFixedString)
+ if index >= 0:
+ self.form.cutSide.setCurrentIndex(index)
+
+ index = self.form.direction.findText(self.obj.Direction, QtCore.Qt.MatchFixedString)
+ if index >= 0:
+ self.form.direction.setCurrentIndex(index)
+
+
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name + "." + i[1])
+
+ for i in range(len(self.obj.locs)):
+ item = QtGui.QTreeWidgetItem(self.form.tagTree)
+ item.setText(0,str(i+1))
+ l = self.obj.locs[i]
+ item.setText(1,str(l.x)+", " + str(l.y) +", " + str(l.z))
+ item.setText(2,str(self.obj.heights[i]))
+ item.setText(3,str(self.obj.lengths[i]))
+ item.setText(4,str(self.obj.angles[i]))
+ item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
+ item.setTextAlignment(0,QtCore.Qt.AlignLeft)
+
+ #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)
+
+ #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.algorithmSelect.currentIndexChanged.connect(self.getFields)
+ self.form.cutSide.currentIndexChanged.connect(self.getFields)
+ self.form.direction.currentIndexChanged.connect(self.getFields)
+ self.form.useCompensation.clicked.connect(self.getFields)
+ self.form.useStartPoint.clicked.connect(self.getFields)
+ self.form.useEndPoint.clicked.connect(self.getFields)
+ self.form.extraOffset.editingFinished.connect(self.getFields)
+ self.form.segLen.editingFinished.connect(self.getFields)
+ self.form.rollRadius.editingFinished.connect(self.getFields)
+
+ #Tag Form
+ QtCore.QObject.connect(self.form.tagTree, QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"), self.edit)
+ self.form.addTag.clicked.connect(self.addElement)
+ self.form.deleteTag.clicked.connect(self.removeElement)
+
+
+class SelObserver:
+ def __init__(self):
+ import PathScripts.PathSelection as PST
+ PST.profileselect()
+
+ 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:
diff --git a/src/Mod/Path/PathScripts/PathProject.py b/src/Mod/Path/PathScripts/PathProject.py
index 0e3a043b9..743a66a21 100644
--- a/src/Mod/Path/PathScripts/PathProject.py
+++ b/src/Mod/Path/PathScripts/PathProject.py
@@ -141,6 +141,11 @@ class CommandProject:
def Create(pathChildren = []):
"""Code to create a project"""
#FreeCADGui.addModule("PathScripts.PathProject")
+ import PathScripts.PathUtils as PU
+ if not PU.findProj() == None:
+ FreeCAD.Console.PrintError("A Path project already exists in this document\n")
+ return
+
obj = FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython","Project")
ObjectPathProject(obj)
if pathChildren:
@@ -152,8 +157,7 @@ class CommandProject:
#create a machine obj
import PathScripts
PathScripts.PathMachine.CommandPathMachine.Create()
- PLT = PathScripts.PathLoadTool.CommandPathLoadTool()
- PLT.Activated()
+ PathScripts.PathLoadTool.CommandPathLoadTool.Create()
return obj
diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py
index c1bbbc827..f15740644 100644
--- a/src/Mod/Path/PathScripts/PathSelection.py
+++ b/src/Mod/Path/PathScripts/PathSelection.py
@@ -71,6 +71,99 @@ class ENGRAVEGate:
def allow(self,doc,obj,sub):
return (obj.Name[0:11] == 'ShapeString')
+class DRILLGate:
+ def allow(self,doc,obj,sub):
+ import Part
+ drillable = False
+ try:
+ obj = obj.Shape
+ except:
+ return False
+ if obj.ShapeType == 'Vertex':
+ drillable = True
+ elif obj.ShapeType == 'Edge':
+ if isinstance(obj.Curve, Part.Circle):
+ drillable = True
+ elif obj.ShapeType == 'Face':
+ if isinstance(obj.Edges[0].Curve, Part.Circle):
+ drillable = True
+ elif obj.ShapeType == 'Wire':
+ if isinstance(obj.Edges[0].Curve, Part.Circle):
+ drillable = True
+ elif obj.ShapeType == 'Solid':
+ if sub[0:4] == 'Face':
+ o = obj.getElement(sub)
+ drillable = isinstance(o.Edges[0].Curve, Part.Circle)
+ if sub[0:4] == 'Edge':
+ o = obj.getElement(sub)
+ drillable = isinstance(o.Curve, Part.Circle)
+
+ return drillable
+
+class PROFILEGate:
+ def allow(self,doc,obj,sub):
+ import Part
+
+ profileable = False
+ try:
+ obj = obj.Shape
+ except:
+ return False
+
+
+ if obj.ShapeType == 'Edge':
+ profileable = True
+
+ elif obj.ShapeType == 'Face':
+ profileable = True
+
+ elif obj.ShapeType == 'Solid':
+ if sub[0:4] == 'Face':
+ profileable = True
+
+ if sub[0:4] == 'Edge':
+ profileable = True
+
+ elif obj.ShapeType == 'Wire':
+ profileable = True
+
+ if sub[0:6] == 'Vertex':
+ print "might be fun to try to derive the loop by hovering near a vertex"
+
+ return profileable
+
+class POCKETGate:
+ def allow(self,doc,obj,sub):
+ import Part
+
+ pocketable = False
+ try:
+ obj = obj.Shape
+ except:
+ return False
+
+
+ if obj.ShapeType == 'Edge':
+ pocketable = False
+
+ elif obj.ShapeType == 'Face':
+ pocketable = True
+
+ elif obj.ShapeType == 'Solid':
+ if sub[0:4] == 'Face':
+ pocketable = True
+
+ # if sub[0:4] == 'Edge':
+ # pocketable = True
+
+ # elif obj.ShapeType == 'Wire':
+ # pocketable = True
+
+ # if sub[0:6] == 'Vertex':
+ # print "might be fun to try to derive the loop by hovering near a vertex"
+
+ return pocketable
+
def fselect():
FreeCADGui.Selection.addSelectionGate(FGate())
@@ -84,10 +177,22 @@ def eselect():
FreeCADGui.Selection.addSelectionGate(EGate())
FreeCAD.Console.PrintWarning("Edge Select Mode\n")
+def drillselect():
+ FreeCADGui.Selection.addSelectionGate(DRILLGate())
+ FreeCAD.Console.PrintWarning("Drilling Select Mode\n")
def engraveselect():
FreeCADGui.Selection.addSelectionGate(ENGRAVEGate())
- FreeCAD.Console.PrintWarning("ShapeString Select Mode\n")
+ FreeCAD.Console.PrintWarning("Engrave Select Mode\n")
+
+def profileselect():
+ FreeCADGui.Selection.addSelectionGate(PROFILEGate())
+ FreeCAD.Console.PrintWarning("Profile Select Mode\n")
+
+def pocketselect():
+ FreeCADGui.Selection.addSelectionGate(POCKETGate())
+ FreeCAD.Console.PrintWarning("Pocket Select Mode\n")
+
def clear():
FreeCADGui.Selection.removeSelectionGate()
diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py
index ac85ee72a..708bf3bbe 100644
--- a/src/Mod/Path/PathScripts/PathSurface.py
+++ b/src/Mod/Path/PathScripts/PathSurface.py
@@ -2,7 +2,7 @@
#***************************************************************************
#* *
-#* Copyright (c) 2016 sliptonic *
+#* Copyright (c) 2016 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) *
@@ -22,15 +22,24 @@
#* *
#***************************************************************************
-import FreeCAD,FreeCADGui,Path,PathGui
+import FreeCAD,Path
from FreeCAD import Vector
-from PySide import QtCore,QtGui
from PathScripts import PathUtils,PathSelection,PathProject
-"""Path Surface object and FreeCAD command"""
-'''Surface operation is used for 3D sculpting, roughing, and finishing
-Possible algorithms include waterline, zigzag, and adaptive roughing.
-Libraries to consider: opencamlib and libactp'''
+if FreeCAD.GuiUp:
+ import FreeCADGui, PathGui
+ from PySide import QtCore, QtGui
+ from DraftTools import translate
+ from pivy import coin
+else:
+ def translate(ctxt,txt):
+ return txt
+
+__title__="Path Surface Operation"
+__author__ = "sliptonic (Brad Collette)"
+__url__ = "http://www.freecadweb.org"
+
+"""Path surface object and FreeCAD command"""
# Qt tanslation handling
try:
@@ -42,46 +51,38 @@ except AttributeError:
return QtGui.QApplication.translate(context, text, disambig)
-class ObjectProfile:
+class ObjectSurface:
+
def __init__(self,obj):
- obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
+ obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object(s)","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Active","Make False, to prevent operation from generating code"))
- obj.addProperty("App::PropertyString","Comment","Path",translate("Comment","An optional comment for this profile"))
-
+ obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile"))
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("PathProject", "The library to use to generate the path"))
- obj.Algorithm = ['OCL Waterline']
+ obj.Algorithm = ['OCL Dropcutter', 'OCL Waterline']
+ #Tool Properties
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use"))
- obj.ToolNumber = (0,0,1000,1)
+ obj.ToolNumber = (0, 0, 1000, 0)
obj.setEditorMode('ToolNumber',1) #make this read only
+ #Surface Properties
+ obj.addProperty("App::PropertyFloatConstraint", "SampleInterval", "Surface", translate("PathSurface","The Sample Interval. Small values cause long wait"))
+ obj.SampleInterval = (0,0,1,0)
#Depth Properties
- obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Clearance Height","The height needed to clear clamps and obstructions"))
- obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
- obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("StepDown","Incremental Step Down of Tool"))
- obj.StepDown = (1,0.01,1000,0.5)
- obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("Start Depth","Starting Depth of Tool- first cut depth in Z"))
- obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Final Depth","Final Depth of Tool- lowest value in Z"))
+ obj.addProperty("App::PropertyFloat", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
+ obj.addProperty("App::PropertyFloat", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
+ obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("PathProject","Incremental Step Down of Tool"))
+ obj.StepDown = (0.0, 0.01, 100.0, 0.5)
+ obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
+ obj.addProperty("App::PropertyFloat", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
+ obj.addProperty("App::PropertyFloat", "FinishDepth", "Depth", translate("PathProject","Maximum material removed on final pass."))
#Feed Properties
- obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
- obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Horiz Feed","Feed rate for horizontal moves"))
-
- #Start Point Properties
- obj.addProperty("App::PropertyVector","StartPoint","Start Point",translate("Start Point","The start point of this path"))
- obj.addProperty("App::PropertyBool","UseStartPoint","Start Point",translate("Use Start Point","make True, if specifying a Start Point"))
- obj.addProperty("App::PropertyLength", "ExtendAtStart", "Start Point", translate("extend at start", "extra length of tool path before start of part edge"))
- obj.addProperty("App::PropertyLength", "LeadInLineLen", "Start Point", translate("lead in length","length of straight segment of toolpath that comes in at angle to first part edge"))
-
- #End Point Properties
- obj.addProperty("App::PropertyBool","UseEndPoint","End Point",translate("Use End Point","make True, if specifying an End Point"))
- obj.addProperty("App::PropertyLength", "ExtendAtEnd", "End Point", translate("extend at end","extra length of tool path after end of part edge"))
- obj.addProperty("App::PropertyLength", "LeadOutLineLen", "End Point", translate("lead_out_line_len","length of straight segment of toolpath that comes in at angle to last part edge"))
- obj.addProperty("App::PropertyVector","EndPoint","End Point",translate("End Point","The end point of this path"))
-
- #Surface Properties
+ 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"))
+
obj.Proxy = self
def __getstate__(self):
@@ -90,140 +91,316 @@ class ObjectProfile:
def __setstate__(self,state):
return None
- def execute(self,obj):
- import Part, DraftGeomUtils
- from PathScripts.PathUtils import depth_params
+ def _waterline(self,obj, s, bb):
+ import ocl
+# from PathScripts.PathUtils import fmt
+ from PathScripts.PathUtils import depth_params, fmt
+ import time
- if obj.Base:
- # tie the toolnumber to the PathLoadTool object ToolNumber
- if len(obj.InList)>0: #check to see if obj is in the Project group yet
- project = obj.InList[0]
- tl = int(PathUtils.changeTool(obj,project))
- obj.ToolNumber= tl
-
- tool = PathUtils.getTool(obj,obj.ToolNumber)
- if tool:
- radius = tool.Diameter/2
- else:
- # temporary value,in case we don't have any tools defined already
- radius = 0.25
-
- depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
-
- clearance = obj.ClearanceHeight.Value
- step_down=obj.StepDown
- start_depth=obj.StartDepth.Value
- final_depth=obj.FinalDepth.Value
- rapid_safety_space=obj.SafeHeight.Value
+ def drawLoops(loops):
+ nloop = 0
+ waterlinestring = ""
+ waterlinestring += "(waterline begin)"
+ for loop in loops:
+ p = loop[0]
+ loopstring = "(loop begin)" +"\n"
+ loopstring += "G0 Z" + str(obj.SafeHeight) +"\n"
+ loopstring += "G0 X" + str(fmt(p.x)) + " Y" + str(fmt(p.y)) +"\n"
+ loopstring += "G1 Z" + str(fmt(p.z)) +"\n"
+ for p in loop[1:]:
+ loopstring += "G1 X" + str(fmt(p.x)) + " Y" + str(fmt(p.y)) + " Z" + str(fmt(p.z)) +"\n"
+ zheight = p.z
+ p = loop[0]
+ loopstring += "G1 X" + str(fmt(p.x)) + " Y" + str(fmt(p.y)) + " Z" + str(fmt(zheight)) +"\n"
+ loopstring += "(loop end)" +"\n"
+ print " loop ",nloop, " with ", len(loop), " points"
+ nloop = nloop+1
+ waterlinestring += loopstring
+ waterlinestring += "(waterline end)" +"\n"
+
+ return waterlinestring
- vf=obj.VertFeed.Value
- hf=obj.HorizFeed.Value
- '''Parse the base and get the necessary geometry here'''
+ # nloop = 0
+ # for lop in loops:
+ # n = 0
+ # N = len(lop)
+ # first_point=ocl.Point(-1,-1,5)
+ # previous=ocl.Point(-1,-1,5)
+ # for p in lop:
+ # if n==0: # don't draw anything on the first iteration
+ # previous=p
+ # first_point = p
+ # elif n== (N-1): # the last point
+ # # and a line from p to the first point
+ # p1=(p.x,p.y,p.z)
+ # p2=(first_point.x,first_point.y,first_point.z)
+ # output += "G1 X" + str(p2[0]) + " Y" + str (p2[1]) + " Z" +str(p2[2]) +"\n"
+ # else:
+ # p1=(previous.x,previous.y,previous.z)
+ # p2=(p.x,p.y,p.z)
+ # output += "G1 X" + str(p2[0]) + " Y" + str (p2[1]) + " Z" +str(p2[2]) +"\n"
+ # #print "line from: " + str (p1) + "To: " + str (p2)
+
+ # #print "line X: " + str (p1.x) +" Y: " + str(p1.y) + "Z: " + str(p1.z) + " To X: " + str (p2.x) +" Y: " + str(p2.y) + "Z: " + str(p2.z)
+ # previous=p
+ # n=n+1
+ # print " loop ",nloop, " with ", len(lop), " points"
+ # nloop = nloop+1
+ # return output
+ depthparams = depth_params (obj.ClearanceHeight, obj.SafeHeight, obj.StartDepth, obj.StepDown, obj.FinishDepth, obj.FinalDepth)
- if obj.Algorithm == "OCL Waterline":
- try:
- import ocl
- except:
- FreeCAD.Console.PrintError(translate("Path","OpenCAMLib needs to be installed for this command to work.\n"))
- return
+ # stlfile = "../../stl/gnu_tux_mod.stl"
+ # surface = STLSurfaceSource(stlfile)
+
+ surface = s
- output = ""
- output += '('+ str(obj.Comment)+')\n'
-
- output += self.buildoclwaterline()
-
- else:
- return
-
-
-
- if obj.Active:
- path = Path.Path(output)
- obj.Path = path
- obj.ViewObject.Visibility = True
-
- else:
- path = Path.Path("(inactive operation)")
- obj.Path = path
- obj.ViewObject.Visibility = False
-
- def buildoclwaterline(self):
- output = "Some text"
+ t_before = time.time()
+
+ zheights= depthparams.get_depths()
+
+ wl = ocl.Waterline()
+ #wl = ocl.AdaptiveWaterline() # this is slower, ca 60 seconds on i7 CPU
+ wl.setSTL(surface)
+ diam = 0.5
+ length= 10
+ cutter = ocl.BallCutter( diam , length ) # any ocl MillingCutter class should work here
+ wl.setCutter(cutter)
+ wl.setSampling(obj.SampleInterval) # this should be smaller than the smallest details in the STL file
+ # AdaptiveWaterline() also has settings for minimum sampling interval (see c++ code)
+ all_loops=[]
+ for zh in zheights:
+ print "calculating Waterline at z= ", zh
+ wl.reset()
+ wl.setZ(zh) # height for this waterline
+ wl.run()
+ all_loops.append( wl.getLoops() )
+ t_after = time.time()
+ calctime = t_after-t_before
+ n=0
+ output = ""
+ for loops in all_loops: # at each z-height, we may get many loops
+ print " %d/%d:" % (n,len(all_loops))
+ output += drawLoops(loops)
+ n=n+1
+ print "(" + str(calctime) + ")"
return output
-class ViewProviderProfile:
+ def _dropcutter(self,obj, s, bb):
+ import ocl
+ import time
- def __init__(self,vobj):
- vobj.Proxy = self
+ cutter = ocl.CylCutter(self.radius*2, 5)
+ pdc = ocl.PathDropCutter() # create a pdc
+ pdc.setSTL(s)
+ pdc.setCutter(cutter)
+ pdc.minimumZ = 0.25
+ pdc.setSampling(obj.SampleInterval)
+
+ # some parameters for this "zigzig" pattern
+ xmin=bb.XMin - cutter.getDiameter()
+ xmax=bb.XMax + cutter.getDiameter()
+ ymin=bb.YMin - cutter.getDiameter()
+ ymax=bb.YMax + cutter.getDiameter()
+ zmax=bb.ZMax + cutter.getDiameter()
+
+ Ny=int(bb.YLength/cutter.getDiameter()) # number of lines in the y-direction
+ dy = float(ymax-ymin)/Ny # the y step-over
+
+ path = ocl.Path() # create an empty path object
+
+ # add Line objects to the path in this loop
+ for n in xrange(0,Ny):
+ y = ymin+n*dy
+ p1 = ocl.Point(xmin,y,0) # start-point of line
+ p2 = ocl.Point(xmax,y,0) # end-point of line
+ if (n % 2 == 0): #even
+ l = ocl.Line(p1,p2) # line-object
+ else: #odd
+ l = ocl.Line(p2,p1) # line-object
- def attach(self,vobj):
- self.Object = vobj.Object
- return
+ path.append( l ) # add the line to the path
+
+ pdc.setPath( path )
+
+ # run drop-cutter on the path
+ t_before = time.time()
+ pdc.run()
+ t_after = time.time()
+ print "calculation took ", t_after-t_before," s"
- def getIcon(self):
- return ":/icons/Path-Surface.svg"
+ #retrieve the points
+ clp = pdc.getCLPoints()
+ print "points received: " + str(len(clp))
- def __getstate__(self):
+ #generate the path commands
+ output = ""
+ output += "G0 Z" + str(obj.ClearanceHeight) + "\n"
+ output += "G0 X" + str(clp[0].x) +" Y" + str(clp[0].y) + "\n"
+ output += "G1 Z" + str(clp[0].z) + " F" + str(obj.VertFeed.Value) + "\n"
+
+ for c in clp:
+ output += "G1 X" + str(c.x) +" Y" + str(c.y) +" Z" + str(c.z)+ "\n"
+
+ return output
+
+
+
+ def execute(self,obj):
+ import Part
+ import Mesh
+ import MeshPart
+ FreeCAD.Console.PrintWarning(translate("PathSurface","Hold on. This might take a minute.\n"))
+
+ output = ""
+
+ if obj.Algorithm in ['OCL Dropcutter', 'OCL Waterline']:
+ try:
+ import ocl
+ except:
+ FreeCAD.Console.PrintError(translate("PathSurface","This operation requires OpenCamLib to be installed.\n"))
+ return
+
+ # tie the toolnumber to the PathLoadTool object ToolNumber
+ if len(obj.InList)>0: #check to see if obj is in the Project group yet
+ project = obj.InList[0]
+ tl = int(PathUtils.changeTool(obj,project))
+ obj.ToolNumber= tl
+
+ tool = PathUtils.getTool(obj,obj.ToolNumber)
+ if tool:
+ self.radius = tool.Diameter/2
+ else:
+ # temporary value,in case we don't have any tools defined already
+ self.radius = 0.25
+
+
+ mesh = obj.Base[0]
+ if mesh.TypeId.startswith('Mesh'):
+ mesh = mesh.Mesh
+ bb = mesh.BoundBox
+ else:
+ bb = mesh.Shape.BoundBox
+ mesh = MeshPart.meshFromShape(mesh.Shape,MaxLength=2)
+
+ s= ocl.STLSurf()
+ for f in mesh.Facets:
+ p = f.Points[0];q=f.Points[1];r=f.Points[2]
+ t= ocl.Triangle(ocl.Point(p[0],p[1],p[2]),ocl.Point(q[0],q[1],q[2]),ocl.Point(r[0],r[1],r[2]))
+ s.addTriangle(t)
+
+ if obj.Algorithm == 'OCL Dropcutter':
+ output = self._dropcutter(obj, s, bb)
+ elif obj.Algorithm == 'OCL Waterline':
+ output = self._waterline(obj, s, bb)
+
+
+ path = Path.Path(output)
+ obj.Path = path
+
+
+
+class ViewProviderSurface:
+ def __init__(self,obj): #mandatory
+# obj.addProperty("App::PropertyFloat","SomePropertyName","PropertyGroup","Description of this property")
+ obj.Proxy = self
+
+ def __getstate__(self): #mandatory
return None
- def __setstate__(self,state):
+ def __setstate__(self,state): #mandatory
return None
+ def getIcon(self): #optional
+ return ":/icons/Path-Surfacing.svg"
+
+# def attach(self): #optional
+# # this is executed on object creation and object load from file
+# pass
+
+ def onChanged(self,obj,prop): #optional
+ # this is executed when a property of the VIEW PROVIDER changes
+ pass
+
+ def updateData(self,obj,prop): #optional
+ # this is executed when a property of the APP OBJECT changes
+ pass
+
+ def setEdit(self,vobj,mode): #optional
+ # this is executed when the object is double-clicked in the tree
+ pass
+
+ def unsetEdit(self,vobj,mode): #optional
+ # this is executed when the user cancels or terminates edit mode
+ pass
+
+
+
+class CommandPathSurfacing:
+
-class CommandPathProfile:
def GetResources(self):
- return {'Pixmap' : 'Path-Surface',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathSurface","Surface"),
- 'Accel': "P, P",
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathSurface","Creates a Path Surface object from selected solid")}
+ return {'Pixmap' : 'Path-Surfacing',
+ 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Surface","Surfacing"),
+ 'Accel': "P, D",
+ 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Surface","Creates a Path Surfacing object")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
-
- def Activated(self):
- import Path
- from PathScripts import PathProject, PathUtils
+ def Activated(self):
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
- FreeCAD.Console.PrintError(translate("Path","Select a Solid.\n"))
+ FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
return
- if len(selection[0].SubObjects) == 0:
- FreeCAD.Console.PrintError(translate("Path","Select a Solid.\n"))
+ if not len(selection[0].SubObjects) == 0:
+ FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
return
-
- # if everything is ok, execute and register the transaction in the undo/redo stack
+ for s in selection[0].SubObjects:
+ if s.ShapeType != "Edge":
+ if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
+ FreeCAD.Console.PrintError(translate("PathSurface","Please select only edges or a single face\n"))
+ return
- # Take a guess at some reasonable values for Finish depth.
- bb = selection[0].Object.Shape.BoundBox #parent boundbox
- fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
- if fbb.ZMax < bb.ZMax:
- zbottom = fbb.ZMax
+ sel = selection[0].Object
+ #get type of object
+ if sel.TypeId.startswith('Mesh'):
+ #it is a mesh already
+ print 'was already mesh'
+ ztop = sel.Mesh.BoundBox.ZMax
+ zbottom = sel.Mesh.BoundBox.ZMin
+
+ #mesh = sel
+ elif sel.TypeId.startswith('Part') and \
+ (sel.Shape.BoundBox.XLength > 0) and \
+ (sel.Shape.BoundBox.YLength > 0) and \
+ (sel.Shape.BoundBox.ZLength > 0):
+ ztop = sel.Shape.BoundBox.ZMax
+ zbottom = sel.Shape.BoundBox.ZMin
+ print 'this is a solid Part object'
+
else:
- zbottom = bb.ZMin
+ FreeCAD.Console.PrintError(translate("PathSurface","Cannot work with this object\n"))
+ return
- FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Surfacing Operation"))
+ # if everything is ok, execute and register the transaction in the undo/redo stack
+ FreeCAD.ActiveDocument.openTransaction(translate("Path_Surfacing","Create Surface"))
FreeCADGui.addModule("PathScripts.PathSurface")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Surface")')
- FreeCADGui.doCommand('PathScripts.PathSurface.ObjectProfile(obj)')
-
+ FreeCADGui.doCommand('PathScripts.PathSurface.ObjectSurface(obj)')
FreeCADGui.doCommand('obj.Active = True')
- # subs ="["
- # for s in selection[0].SubElementNames:
- # subs += '"' + s + '",'
- # subs += "]"
- # FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
+ FreeCADGui.doCommand('PathScripts.PathSurface.ViewProviderSurface(obj.ViewObject)')
+ FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.'+selection[0].ObjectName+',[])')
+ FreeCADGui.doCommand('from PathScripts import PathUtils')
+ FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 2))
+ FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop))
+ FreeCADGui.doCommand('obj.SafeHeight = ' + str(ztop + 2))
+ FreeCADGui.doCommand('obj.StepDown = ' + str((ztop-zbottom)/8))
+ FreeCADGui.doCommand('obj.SampleInterval = 0.4')
- FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
- FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 10.0))
- FreeCADGui.doCommand('obj.StepDown = 1.0')
- FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
-
- FreeCADGui.doCommand('obj.SafeHeight = '+ str(bb.ZMax + 2.0))
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
FreeCAD.ActiveDocument.commitTransaction()
@@ -232,6 +409,6 @@ class CommandPathProfile:
if FreeCAD.GuiUp:
# register the FreeCAD command
- FreeCADGui.addCommand('Path_Surface',CommandPathSurface())
+ FreeCADGui.addCommand('Path_Surfacing',CommandPathSurfacing())
-FreeCAD.Console.PrintLog("Loading PathSurface... done\n")
+FreeCAD.Console.PrintLog("Loading PathSurfacing... done\n")
diff --git a/src/Mod/Path/PathScripts/PathUtils.py b/src/Mod/Path/PathScripts/PathUtils.py
index 669cfbe29..7addc8c1d 100644
--- a/src/Mod/Path/PathScripts/PathUtils.py
+++ b/src/Mod/Path/PathScripts/PathUtils.py
@@ -324,7 +324,6 @@ def changeTool(obj,proj):
if g == obj:
return tlnum
-
def getLastTool(obj):
toolNum = obj.ToolNumber
if obj.ToolNumber == 0:
@@ -333,6 +332,44 @@ def getLastTool(obj):
toolNum = changeTool(obj, proj)
return getTool(obj, toolNum)
+def getLastToolLoad(obj):
+ #This walks up the hierarchy and tries to find the closest preceding toolchange.
+
+ import PathScripts
+ tc = None
+ lastfound = None
+
+ try:
+ child = obj
+ parent = obj.InList[0]
+ except:
+ parent = None
+
+ while parent != None:
+
+ sibs = parent.Group
+ for g in sibs:
+ if isinstance(g.Proxy,PathScripts.PathLoadTool.LoadTool):
+ lastfound = g
+ if g == child:
+ tc = lastfound
+
+ if tc == None:
+ try:
+ child = parent
+ parent = parent.InList[0]
+ except:
+ parent = None
+ else:
+ return tc
+
+ if tc == None:
+ for g in FreeCAD.ActiveDocument.Objects: #top level object
+ if isinstance(g.Proxy,PathScripts.PathLoadTool.LoadTool):
+ lastfound = g
+ if g == obj:
+ tc = lastfound
+ return tc
def getTool(obj,number=0):
"retrieves a tool from a hosting object with a tooltable, if any"
@@ -419,7 +456,6 @@ class depth_params:
self.user_depths = user_depths
def get_depths(self):
- print "in function"
depths = []
if self.user_depths != None:
depths = self.user_depths