diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt
index a2fbad13a..848159391 100644
--- a/src/Mod/Path/CMakeLists.txt
+++ b/src/Mod/Path/CMakeLists.txt
@@ -57,6 +57,8 @@ SET(PathScripts_SRCS
PathScripts/PathInspect.py
PathScripts/PathSimpleCopy.py
PathScripts/PathEngrave.py
+ PathScripts/PathSurface.py
+
)
SET(PathScripts_NC_SRCS
diff --git a/src/Mod/Path/Gui/CMakeLists.txt b/src/Mod/Path/Gui/CMakeLists.txt
index 43df8f04c..6a39864e1 100644
--- a/src/Mod/Path/Gui/CMakeLists.txt
+++ b/src/Mod/Path/Gui/CMakeLists.txt
@@ -88,7 +88,7 @@ add_library(PathGui SHARED ${PathGui_SRCS})
target_link_libraries(PathGui ${PathGui_LIBS})
-fc_target_copy_resource(PathGui
+fc_target_copy_resource(PathGui
${CMAKE_SOURCE_DIR}/src/Mod/Path
${CMAKE_BINARY_DIR}/Mod/Path
InitGui.py)
diff --git a/src/Mod/Path/Gui/DrillingEdit.ui b/src/Mod/Path/Gui/DrillingEdit.ui
index f9411e387..21d5c0d2a 100644
--- a/src/Mod/Path/Gui/DrillingEdit.ui
+++ b/src/Mod/Path/Gui/DrillingEdit.ui
@@ -98,8 +98,8 @@
0
0
- 116
- 108
+ 304
+ 314
@@ -159,8 +159,8 @@
0
0
- 150
- 108
+ 304
+ 314
@@ -220,13 +220,13 @@
0
0
- 234
- 50
+ 304
+ 314
-
- :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg
+
+ :/icons/Path-Hamburger.svg:/icons/Path-Hamburger.svg
Operation
@@ -263,6 +263,7 @@
+
diff --git a/src/Mod/Path/Gui/EngraveEdit.ui b/src/Mod/Path/Gui/EngraveEdit.ui
index 7e18f163d..635566c58 100644
--- a/src/Mod/Path/Gui/EngraveEdit.ui
+++ b/src/Mod/Path/Gui/EngraveEdit.ui
@@ -34,7 +34,7 @@
0
0
304
- 314
+ 284
@@ -99,7 +99,7 @@
0
0
304
- 314
+ 284
@@ -146,7 +146,7 @@
0
0
304
- 314
+ 284
@@ -187,18 +187,65 @@
+
+
+
+ 0
+ 0
+ 304
+ 284
+
+
+
+
+ :/icons/FreeCAD-default/scalable/document-save-as.svg:/icons/FreeCAD-default/scalable/document-save-as.svg
+
+
+ Speeds
+
+
+ -
+
+
+ mm/(s)
+
+
+
+ -
+
+
+ Horiz Feed
+
+
+
+ -
+
+
+ mm/(s)
+
+
+
+ -
+
+
+ Vert Feed
+
+
+
+
+
0
0
304
- 314
+ 284
-
- :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg
+
+ :/icons/Path-Hamburger.svg:/icons/Path-Hamburger.svg
Operation
@@ -235,6 +282,7 @@
+
diff --git a/src/Mod/Path/Gui/PocketEdit.ui b/src/Mod/Path/Gui/PocketEdit.ui
index 697b3b65b..35e634a3b 100644
--- a/src/Mod/Path/Gui/PocketEdit.ui
+++ b/src/Mod/Path/Gui/PocketEdit.ui
@@ -252,6 +252,14 @@
+
+
+ 0
+ 0
+ 334
+ 327
+
+
Pattern
@@ -266,8 +274,8 @@
-
- :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg
+
+ :/icons/Path-Hamburger.svg:/icons/Path-Hamburger.svg
Operation
@@ -368,6 +376,7 @@
+
diff --git a/src/Mod/Path/Gui/ProfileEdit.ui b/src/Mod/Path/Gui/ProfileEdit.ui
index 8a968e68b..ab0b740ac 100644
--- a/src/Mod/Path/Gui/ProfileEdit.ui
+++ b/src/Mod/Path/Gui/ProfileEdit.ui
@@ -224,6 +224,14 @@
+
+
+ 0
+ 0
+ 334
+ 357
+
+
Holding
@@ -283,8 +291,8 @@
-
- :/icons/FreeCAD-default/scalable/user.svg:/icons/FreeCAD-default/scalable/user.svg
+
+ :/icons/Path-Hamburger.svg:/icons/Path-Hamburger.svg
Operation
@@ -445,6 +453,7 @@
+
diff --git a/src/Mod/Path/Gui/Resources/Path.qrc b/src/Mod/Path/Gui/Resources/Path.qrc
index 442006295..9da94a228 100644
--- a/src/Mod/Path/Gui/Resources/Path.qrc
+++ b/src/Mod/Path/Gui/Resources/Path.qrc
@@ -31,6 +31,8 @@
icons/Path-ToolChange.svg
icons/Path-SimpleCopy.svg
icons/Path-Engrave.svg
+ icons/Path-Surfacing.svg
+ icons/Path-Hamburger.svg
translations/Path_de.qm
translations/Path_af.qm
translations/Path_zh-CN.qm
diff --git a/src/Mod/Path/Gui/Resources/icons/Path-Surfacing.svg b/src/Mod/Path/Gui/Resources/icons/Path-Surfacing.svg
new file mode 100644
index 000000000..295f78626
--- /dev/null
+++ b/src/Mod/Path/Gui/Resources/icons/Path-Surfacing.svg
@@ -0,0 +1,644 @@
+
+
+
+
diff --git a/src/Mod/Path/Gui/SurfaceEdit.ui b/src/Mod/Path/Gui/SurfaceEdit.ui
new file mode 100644
index 000000000..bbdaf94ed
--- /dev/null
+++ b/src/Mod/Path/Gui/SurfaceEdit.ui
@@ -0,0 +1,299 @@
+
+
+ TaskPanel
+
+
+
+ 0
+ 0
+ 352
+ 525
+
+
+
+
+ 0
+ 400
+
+
+
+ Surface
+
+
+ -
+
+
+ 0
+
+
+
+ true
+
+
+
+ 0
+ 0
+ 334
+ 387
+
+
+
+
+ :/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
+ 387
+
+
+
+
+ :/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
+ 387
+
+
+
+
+ :/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
+ 387
+
+
+
+
+ :/icons/Path-Hamburger.svg:/icons/Path-Hamburger.svg
+
+
+ Operation
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ Algorithm
+
+
+
+ -
+
+
-
+
+ OCL Dropcutter
+
+
+ -
+
+ OCL Waterline
+
+
+
+
+
+
+
+
+
+
+
+
+ Gui::InputField
+ QLineEdit
+
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py
index 6b5b9fe3a..a9fc7edcc 100644
--- a/src/Mod/Path/PathScripts/PathDrilling.py
+++ b/src/Mod/Path/PathScripts/PathDrilling.py
@@ -24,7 +24,7 @@
import FreeCAD,Path
from PySide import QtCore,QtGui
-from PathScripts import PathUtils,PathSelection,PathProject
+from PathScripts import PathUtils
FreeCADGui = None
if FreeCAD.GuiUp:
@@ -43,25 +43,25 @@ except AttributeError:
class ObjectDrilling:
-
+
def __init__(self,obj):
- 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::PropertyLinkSubList","Base","Path",translate("PathProject","The base geometry of this toolpath"))
+ 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::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::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::PropertyDistance", "RetractHeight", "Depth", translate("PathProject","The height where feed starts and height during retract tool when path is finished"))
+
+ #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,1)
obj.setEditorMode('ToolNumber',1) #make this read only
-
+
obj.Proxy = self
def __getstate__(self):
@@ -69,26 +69,24 @@ class ObjectDrilling:
def __setstate__(self,state):
return None
-
+
def execute(self,obj):
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad == None:
self.vertFeed = 100
self.horizFeed = 100
- radius = 0.25
- obj.ToolNumber= 0
+ 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
+ obj.ToolNumber= toolLoad.ToolNumber
if obj.Base:
locations = []
for loc in obj.Base:
- if "Face" in loc[1] or "Edge" in loc[1]:
+ if "Face" in loc[1] or "Edge" in loc[1]:
s = getattr(loc[0].Shape,loc[1])
else:
s = loc[0].Shape
@@ -131,6 +129,26 @@ class ObjectDrilling:
def addDrillableLocation(self, obj, ss, sub=""):
baselist = obj.Base
item = (ss, sub)
+ if len(baselist) == 0: #When adding the first base object, guess at heights
+ try:
+ bb = ss.Shape.BoundBox #parent boundbox
+ subobj = ss.Shape.getElement(sub)
+ fbb = subobj.BoundBox #feature boundbox
+ obj.StartDepth = bb.ZMax
+ obj.ClearanceHeight = bb.ZMax + 5.0
+ obj.SafeHeight = bb.ZMax + 3.0
+ obj.RetractHeight = bb.ZMax + 1.0
+
+ if fbb.ZMax < bb.ZMax:
+ obj.FinalDepth = fbb.ZMax
+ else:
+ obj.FinalDepth = bb.ZMin
+ except:
+ obj.StartDepth = 5.0
+ obj.ClearanceHeight = 10.0
+ obj.SafeHeight = 8.0
+ obj.RetractHeight = 6.0
+
if item in baselist:
FreeCAD.Console.PrintWarning("Drillable location already in the list"+ "\n")
else:
@@ -151,10 +169,6 @@ class _ViewProviderDrill:
def getIcon(self): #optional
return ":/icons/Path-Drilling.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
@@ -188,8 +202,6 @@ class CommandPathDrilling:
return not FreeCAD.ActiveDocument is None
def Activated(self):
- import Path, Part
-
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction(translate("Path_Drilling","Create Drilling"))
@@ -221,14 +233,14 @@ class TaskPanel:
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
- def getFields(self):
+ def getFields(self):
if self.obj:
if hasattr(self.obj,"StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
@@ -248,7 +260,7 @@ class TaskPanel:
def open(self):
self.s =SelObserver()
# install the function mode resident
- FreeCADGui.Selection.addObserver(self.s)
+ FreeCADGui.Selection.addObserver(self.s)
def addBase(self):
# check that the selection contains exactly what we want
@@ -261,14 +273,15 @@ class TaskPanel:
if s.HasSubObjects:
for i in s.SubElementNames:
self.obj.Proxy.addDrillableLocation(self.obj, s.Object, i)
- else:
+ else:
self.obj.Proxy.addDrillableLocation(self.obj, s.Object)
+ self.setupUi() #defaults may have changed. Reload.
self.form.baseList.clear()
- for i in self.obj.Base:
+ 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:
@@ -288,7 +301,7 @@ class TaskPanel:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# sub = o.Shape.getElement(objstring[2])
- if objstring[2] != "":
+ if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj,objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
@@ -321,29 +334,28 @@ class TaskPanel:
self.form.retractHeight.setText(str(self.obj.RetractHeight.Value))
- for i in self.obj.Base:
+ 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)
+ self.form.finalDepth.editingFinished.connect(self.getFields)
+ self.form.safeHeight.editingFinished.connect(self.getFields)
+ self.form.clearanceHeight.editingFinished.connect(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.addBase.clicked.connect(self.addBase)
+ self.form.deleteBase.clicked.connect(self.deleteBase)
+ self.form.reorderBase.clicked.connect(self.reorderBase)
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
class SelObserver:
def __init__(self):
- import PathScripts.PathSelection as PST
+ import PathScripts.PathSelection as PST
PST.drillselect()
def __del__(self):
- import PathScripts.PathSelection as PST
+ import PathScripts.PathSelection as PST
PST.clear()
def addSelection(self,doc,obj,sub,pnt): # Selection object
@@ -351,7 +363,7 @@ class SelObserver:
FreeCADGui.updateGui()
-if FreeCAD.GuiUp:
+if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Drilling',CommandPathDrilling())
diff --git a/src/Mod/Path/PathScripts/PathEngrave.py b/src/Mod/Path/PathScripts/PathEngrave.py
index 6ef7ddcef..b74ec914f 100644
--- a/src/Mod/Path/PathScripts/PathEngrave.py
+++ b/src/Mod/Path/PathScripts/PathEngrave.py
@@ -22,10 +22,10 @@
#* *
#***************************************************************************
-import FreeCAD,FreeCADGui,Path,PathGui,Draft
+import FreeCAD,FreeCADGui,Path,Draft
from PySide import QtCore,QtGui
-from PathScripts import PathUtils,PathProject
+from PathScripts import PathUtils
"""Path Engrave object and FreeCAD command"""
@@ -40,16 +40,19 @@ except AttributeError:
class ObjectPathEngrave:
-
+
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSubList","Base","Path","The base geometry of this object")
+ 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']
-
+
+ #Tool Properties
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("Path","The tool number in use"))
- obj.ToolNumber = (0,0,1000,1)
+ obj.ToolNumber = (0,0,1000,1)
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
@@ -58,7 +61,6 @@ class ObjectPathEngrave:
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::PropertyInteger","StartVertex","Path","The vertex index to start the path from")
- #Feed Properties
if FreeCAD.GuiUp:
_ViewProviderEngrave(obj.ViewObject)
@@ -70,22 +72,22 @@ class ObjectPathEngrave:
def __setstate__(self,state):
return None
-
+
def execute(self,obj):
output = ""
-
+
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad == None:
self.vertFeed = 100
self.horizFeed = 100
- radius = 0.25
- obj.ToolNumber= 0
+ self.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
+ self.radius = tool.Diameter/2
+ obj.ToolNumber= toolLoad.ToolNumber
if obj.Base:
for o in obj.Base:
@@ -111,10 +113,10 @@ class ObjectPathEngrave:
for wire in wires:
offset = wire
-
+
# reorder the wire
offset = DraftGeomUtils.rebaseWire(offset,obj.StartVertex)
-
+
# we create the path from the offset shape
last = None
for edge in offset.Edges:
@@ -153,6 +155,24 @@ class ObjectPathEngrave:
def addShapeString(self, obj, ss):
baselist = obj.Base
+ if len(baselist) == 0: #When adding the first base object, guess at heights
+ try:
+ bb = ss.Shape.BoundBox #parent boundbox
+ subobj = ss.Shape.getElement(sub)
+ fbb = subobj.BoundBox #feature boundbox
+ obj.StartDepth = bb.ZMax
+ obj.ClearanceHeight = bb.ZMax + 5.0
+ obj.SafeHeight = bb.ZMax + 3.0
+
+ if fbb.ZMax < bb.ZMax:
+ obj.FinalDepth = fbb.ZMax
+ else:
+ obj.FinalDepth = bb.ZMin
+ except:
+ obj.StartDepth = 5.0
+ obj.ClearanceHeight = 10.0
+ obj.SafeHeight = 8.0
+
item = (ss, "")
if item in baselist:
FreeCAD.Console.PrintWarning("ShapeString already in the Engraving list"+ "\n")
@@ -198,9 +218,9 @@ class CommandPathEngrave:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
-
+
def Activated(self):
-
+
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction("Create Engrave Path")
@@ -231,14 +251,14 @@ class TaskPanel:
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
- def getFields(self):
+ def getFields(self):
if self.obj:
if hasattr(self.obj,"StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
@@ -255,7 +275,7 @@ class TaskPanel:
def open(self):
self.s =SelObserver()
# install the function mode resident
- FreeCADGui.Selection.addObserver(self.s)
+ FreeCADGui.Selection.addObserver(self.s)
def addBase(self):
# check that the selection contains exactly what we want
@@ -271,7 +291,7 @@ class TaskPanel:
self.obj.Proxy.addShapeString(self.obj, s.Object)
self.form.baseList.clear()
- for i in self.obj.Base:
+ for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name)
def deleteBase(self):
@@ -313,38 +333,35 @@ class TaskPanel:
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
-
- for i in self.obj.Base:
+ for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name)
#Connect Signals and Slots
- self.form.startDepth.editingFinished.connect(self.getFields) #This is newer syntax
- #QtCore.QObject.connect(self.form.startDepth, QtCore.SIGNAL("editingFinished()"), self.getFields)
- QtCore.QObject.connect(self.form.finalDepth, QtCore.SIGNAL("editingFinished()"), self.getFields)
- QtCore.QObject.connect(self.form.safeHeight, QtCore.SIGNAL("editingFinished()"), self.getFields)
- QtCore.QObject.connect(self.form.clearanceHeight, QtCore.SIGNAL("editingFinished()"), self.getFields)
+ self.form.startDepth.editingFinished.connect(self.getFields)
+ self.form.finalDepth.editingFinished.connect(self.getFields)
+ self.form.safeHeight.editingFinished.connect(self.getFields)
+ self.form.clearanceHeight.editingFinished.connect(self.getFields)
- QtCore.QObject.connect(self.form.addBase, QtCore.SIGNAL("clicked()"), self.addBase)
- QtCore.QObject.connect(self.form.deleteBase, QtCore.SIGNAL("clicked()"), self.deleteBase)
- QtCore.QObject.connect(self.form.reorderBase, QtCore.SIGNAL("clicked()"), self.reorderBase)
-
- QtCore.QObject.connect(self.form.baseList, QtCore.SIGNAL("itemSelectionChanged()"), self.itemActivated)
+ self.form.addBase.clicked.connect(self.addBase)
+ self.form.deleteBase.clicked.connect(self.deleteBase)
+ self.form.reorderBase.clicked.connect(self.reorderBase)
+ self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
class SelObserver:
def __init__(self):
- import PathScripts.PathSelection as PST
+ import PathScripts.PathSelection as PST
PST.engraveselect()
def __del__(self):
- import PathScripts.PathSelection as PST
+ 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:
+if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Engrave',CommandPathEngrave())
diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py
index 4ee8c193a..0096be32d 100644
--- a/src/Mod/Path/PathScripts/PathPocket.py
+++ b/src/Mod/Path/PathScripts/PathPocket.py
@@ -44,12 +44,12 @@ except AttributeError:
class ObjectPocket:
-
def __init__(self,obj):
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"))
obj.Algorithm = ['OCC Native','libarea']
@@ -113,19 +113,35 @@ class ObjectPocket:
return None
def addpocketbase(self, obj, ss, sub=""):
- #sublist = []
- #sublist.append(sub)
baselist = obj.Base
if baselist == None:
baselist = []
+ if len(baselist) == 0: #When adding the first base object, guess at heights
+ try:
+ bb = ss.Shape.BoundBox #parent boundbox
+ subobj = ss.Shape.getElement(sub)
+ fbb = subobj.BoundBox #feature boundbox
+ obj.StartDepth = bb.ZMax
+ obj.ClearanceHeight = bb.ZMax + 5.0
+ obj.SafeHeight = bb.ZMax + 3.0
+
+ if fbb.ZMax < bb.ZMax:
+ obj.FinalDepth = fbb.ZMax
+ else:
+ obj.FinalDepth = bb.ZMin
+ except:
+ obj.StartDepth = 5.0
+ obj.ClearanceHeight = 10.0
+ obj.SafeHeight = 8.0
+
item = (ss, sub)
if item in baselist:
FreeCAD.Console.PrintWarning("this object already in the list"+ "\n")
else:
baselist.append (item)
obj.Base = baselist
- print "this base is: " + str(baselist)
- self.execute(obj)
+ print "this base is: " + str(baselist)
+ self.execute(obj)
def getStock(self,obj):
"retrieves a stock object from hosting project if any"
@@ -140,16 +156,14 @@ class ObjectPocket:
return None
def buildpathlibarea(self, obj, a):
- import PathScripts.PathUtils as PathUtils
import PathScripts.PathAreaUtils as PathAreaUtils
from PathScripts.PathUtils import depth_params
import area
-
+
FreeCAD.Console.PrintMessage(translate("PathPocket","Generating toolpath with libarea offsets.\n"))
-
+
depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value)
-
- horizfeed = self.horizFeed
+
extraoffset = obj.MaterialAllowance.Value
stepover = obj.StepOver
use_zig_zag = obj.UseZigZag
@@ -159,7 +173,7 @@ class ObjectPocket:
zig_unidirectional = obj.ZigUnidirectional
start_point = None
cut_mode = obj.CutMode
-
+
PathAreaUtils.flush_nc()
PathAreaUtils.output('mem')
PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
@@ -214,7 +228,7 @@ class ObjectPocket:
retstr += str("%.4f" % self.horizFeed)
else:
retstr += str("%.4f" % self.vertFeed)
-
+
if (x != None) or (y != None) or (z != None):
if (x != None):
retstr += " X" + str("%.4f" % x)
@@ -235,7 +249,7 @@ class ObjectPocket:
if (math.sqrt((cx - sx)**2 + (cy - sy)**2) - math.sqrt((cx - ex)**2 + (cy - ey)**2)) >= eps:
print "ERROR: Illegal arc: Stand and end radii not equal"
return ""
-
+
#Set [C]CW and feed
retstr = ""
if ccw:
@@ -243,17 +257,17 @@ class ObjectPocket:
else:
retstr += "G02 F"
retstr += str(self.horizFeed)
-
+
#End location
retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey)
-
+
#Helix if requested
if ez != None:
retstr += " Z" + str("%.4f" % ez)
-
+
#Append center offsets
retstr += " I" + str("%.4f" % (cx - sx)) + " J" + str("%.4f" % (cy - sy))
-
+
return retstr + "\n"
def helicalPlunge(plungePos, rampangle, destZ, startZ):
@@ -270,14 +284,14 @@ class ObjectPocket:
helixX = plungePos.x + tool.Diameter/2. * plungeR
helixY = plungePos.y;
-
+
helixCirc = math.pi * tool.Diameter * plungeR
dzPerRev = math.sin(rampangle/180. * math.pi) * helixCirc
#Go to the start of the helix position
helixCmds += rapid(helixX, helixY)
helixCmds += rapid(z=startZ)
-
+
#Helix as required to get to the requested depth
lastZ = startZ
curZ = max(startZ-dzPerRev, destZ)
@@ -286,14 +300,14 @@ class ObjectPocket:
done = (curZ == destZ)
#NOTE: FreeCAD doesn't render this, but at least LinuxCNC considers it valid
#helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX, helixY, ez = curZ, ccw=True)
-
+
#Use two half-helixes; FreeCAD renders that correctly,
#and it fits with the other code breaking up 360-degree arcs
helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - tool.Diameter * plungeR, helixY, ez = (curZ + lastZ)/2., ccw=True)
helixCmds += arc(plungePos.x, plungePos.y, helixX - tool.Diameter * plungeR, helixY, helixX, helixY, ez = curZ, ccw=True)
lastZ = curZ
curZ = max(curZ - dzPerRev, destZ)
-
+
return helixCmds
def rampPlunge(edge, rampangle, destZ, startZ):
@@ -310,8 +324,8 @@ class ObjectPocket:
return None
if(not tool):
raise Error("Ramp plunging requires a tool!")
-
-
+
+
sPoint = edge.Vertexes[0].Point
ePoint = edge.Vertexes[1].Point
#Evidently edges can get flipped- pick the right one in this case
@@ -320,21 +334,21 @@ class ObjectPocket:
#print "FLIP"
ePoint = edge.Vertexes[-1].Point
#print "Start: " + str(sPoint) + " End: " + str(ePoint) + " Zhigh: " + prnt(startZ) + " ZLow: " + prnt(destZ)
-
+
rampDist = edge.Length
rampDZ = math.sin(rampangle/180. * math.pi) * rampDist
-
+
rampCmds += rapid(sPoint.x, sPoint.y)
rampCmds += rapid(z=startZ)
-
+
#Ramp down to the requested depth
#FIXME: This might be an arc, so handle that as well
- lastZ = startZ
+
curZ = max(startZ-rampDZ, destZ)
done = False
while not done:
done = (curZ == destZ)
-
+
#If it's an arc, handle it!
if isinstance(edge.Curve,Part.Circle):
raise Error("rampPlunge: Screw it, not handling an arc.")
@@ -343,12 +357,9 @@ class ObjectPocket:
rampCmds += feed(ePoint.x, ePoint.y, curZ)
rampCmds += feed(sPoint.x, sPoint.y)
- lastZ = curZ
curZ = max(curZ - rampDZ, destZ)
-
- return rampCmds
-
+ return rampCmds
output = ""
offsets = []
@@ -360,12 +371,12 @@ class ObjectPocket:
offsets.extend(result)
nextradius += self.radius
result = DraftGeomUtils.pocket2d(shape,nextradius)
-
+
# first move will be rapid, subsequent will be at feed rate
first = True
startPoint = None
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()
@@ -378,7 +389,7 @@ class ObjectPocket:
#Fraction of tool radius our plunge helix is to be
plungeR = obj.HelixSize
-
+
#(minimum) Fraction of tool DIAMETER to go back and forth while ramp-plunging
#FIXME: The ramp plunging should maybe even be limited to this distance; I don't know what's best
rampD = obj.RampSize
@@ -386,8 +397,8 @@ class ObjectPocket:
#Total offset from the desired pocket edge is tool radius plus the plunge helix radius
#Any point on these curves could be the center of a plunge
helixBounds = DraftGeomUtils.pocket2d(shape, self.radius * (1 + plungeR))
-
-
+
+
#Try to find a location to nicely plunge, starting with a helix, then ramp
#Can't do it without knowledge of a tool
plungePos = None
@@ -400,7 +411,7 @@ class ObjectPocket:
#Since we're going to start machining either the inner-most
#edge or the outer (depending on StartAt setting), try to
#plunge near that location
-
+
if helixBounds and obj.UseEntry:
#Edge is easy- pick a point on helixBounds and go with it
if obj.StartAt == 'Edge':
@@ -408,7 +419,7 @@ class ObjectPocket:
#Center is harder- use a point from the first offset, check if it works
else:
plungePos = offsets[0].Edges[0].Vertexes[0].Point
-
+
#If it turns out this is invalid for some reason, nuke plungePos
[perp,idx] = DraftGeomUtils.findPerpendicular(plungePos, shape.Edges)
if not perp or perp.Length < self.radius * (1 + plungeR):
@@ -416,8 +427,7 @@ class ObjectPocket:
#FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds
#Or some math to prove that it has to be (doubt that's true)
#Maybe reverse helixBounds and pick off that?
-
-
+
#If we didn't find a place to helix, how about a ramp?
if not plungePos and obj.UseEntry:
#Check first edge of our offsets
@@ -429,7 +439,6 @@ class ObjectPocket:
else:
print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1])
#FIXME: There's got to be a smarter way to find a place to ramp
-
#For helix-ing/ramping, know where we were last time
#FIXME: Can probably get this from the "machine"?
@@ -509,13 +518,13 @@ class ObjectPocket:
self.horizFeed = toolLoad.HorizFeed.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
self.radius = tool.Diameter/2
- obj.ToolNumber= toolLoad.ToolNumber
+ obj.ToolNumber= toolLoad.ToolNumber
if obj.Base:
for b in obj.Base:
print "object base: " + str(b)
- import Part, PathScripts.PathKurveUtils, DraftGeomUtils
+ import Part, PathScripts.PathKurveUtils
if "Face" in b[1]:
print "inside"
shape = getattr(b[0].Shape,b[1])
@@ -528,7 +537,6 @@ class ObjectPocket:
wire = Part.Wire(edges)
shape = None
-
# output = ""
if obj.Algorithm == "OCC Native":
if shape == None:
@@ -540,7 +548,7 @@ class ObjectPocket:
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')
@@ -564,8 +572,7 @@ class ObjectPocket:
##This puts out some interesting information from libarea
print a.text()
########
-
-
+
a.Reorder()
output += self.buildpathlibarea(obj, a)
@@ -587,7 +594,7 @@ class _CommandSetPocketStartPoint:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
-
+
def setpoint(self,point,o):
obj=FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
@@ -636,7 +643,7 @@ class CommandPathPocket:
return not FreeCAD.ActiveDocument is None
def Activated(self):
-
+
# check that the selection contains exactly what we want
# selection = FreeCADGui.Selection.getSelectionEx()
# if len(selection) != 1:
@@ -672,18 +679,18 @@ class CommandPathPocket:
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"))
FreeCADGui.addModule("PathScripts.PathPocket")
-
- FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Pocket")')
+
+ FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Pocket")')
FreeCADGui.doCommand('PathScripts.PathPocket.ObjectPocket(obj)')
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('PathScripts.PathPocket.ViewProviderPocket(obj.ViewObject)')
-
+
FreeCADGui.doCommand('from PathScripts import PathUtils')
FreeCADGui.doCommand('obj.StepOver = 1.0')
@@ -698,7 +705,7 @@ class CommandPathPocket:
FreeCADGui.doCommand('obj.HelixSize = 0.75')
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
-
+
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
@@ -716,14 +723,14 @@ class TaskPanel:
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
- def getFields(self):
+ def getFields(self):
if self.obj:
if hasattr(self.obj,"StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
@@ -748,7 +755,7 @@ class TaskPanel:
def open(self):
self.s =SelObserver()
# install the function mode resident
- FreeCADGui.Selection.addObserver(self.s)
+ FreeCADGui.Selection.addObserver(self.s)
def addBase(self):
# check that the selection contains exactly what we want
@@ -761,13 +768,14 @@ class TaskPanel:
if s.HasSubObjects:
for i in s.SubElementNames:
self.obj.Proxy.addpocketbase(self.obj, s.Object, i)
- else:
+ else:
self.obj.Proxy.addpocketbase(self.obj, s.Object)
+ self.setupUi() #defaults may have changed. Reload.
self.form.baseList.clear()
- for i in self.obj.Base:
+ for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name + "." + i[1])
-
+
def deleteBase(self):
dlist = self.form.baseList.selectedItems()
newlist = []
@@ -787,7 +795,7 @@ class TaskPanel:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# sub = o.Shape.getElement(objstring[2])
- if objstring[2] != "":
+ if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj,objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
@@ -829,7 +837,7 @@ class TaskPanel:
if index >= 0:
self.form.algorithmSelect.setCurrentIndex(index)
- for i in self.obj.Base:
+ for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name + "." + i[1])
#Connect Signals and Slots
@@ -840,35 +848,35 @@ class TaskPanel:
self.form.reorderBase.clicked.connect(self.reorderBase)
#Depths
- self.form.startDepth.editingFinished.connect(self.getFields)
+ 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
+ import PathScripts.PathSelection as PST
PST.pocketselect()
def __del__(self):
- import PathScripts.PathSelection as PST
+ 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:
+if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Pocket',CommandPathPocket())
FreeCADGui.addCommand('Set_PocketStartPoint',_CommandSetPocketStartPoint())
diff --git a/src/Mod/Path/PathScripts/PathProfile.py b/src/Mod/Path/PathScripts/PathProfile.py
index aeea2a426..42327dce3 100644
--- a/src/Mod/Path/PathScripts/PathProfile.py
+++ b/src/Mod/Path/PathScripts/PathProfile.py
@@ -59,10 +59,10 @@ class ObjectProfile:
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','libareal']
+ obj.Algorithm = ['OCC Native','libarea']
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("Path","The tool number in use"))
- obj.ToolNumber = (0,0,1000,1)
+ obj.ToolNumber = (0,0,1000,1)
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
@@ -72,7 +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"))
-
+
#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"))
@@ -121,6 +121,24 @@ class ObjectProfile:
def addprofilebase(self, obj, ss, sub=""):
baselist = obj.Base
+ if len(baselist) == 0: #When adding the first base object, guess at heights
+ try:
+ bb = ss.Shape.BoundBox #parent boundbox
+ subobj = ss.Shape.getElement(sub)
+ fbb = subobj.BoundBox #feature boundbox
+ obj.StartDepth = bb.ZMax
+ obj.ClearanceHeight = bb.ZMax + 5.0
+ obj.SafeHeight = bb.ZMax + 3.0
+
+ if fbb.ZMax < bb.ZMax:
+ obj.FinalDepth = fbb.ZMax
+ else:
+ obj.FinalDepth = bb.ZMin
+ except:
+ obj.StartDepth = 5.0
+ obj.ClearanceHeight = 10.0
+ obj.SafeHeight = 8.0
+
item = (ss, sub)
if item in baselist:
FreeCAD.Console.PrintWarning("this object already in the list"+ "\n")
@@ -164,7 +182,7 @@ class ObjectProfile:
output = ""
if obj.StartPoint and obj.UseStartPoint:
- startpoint = obj.StartPoint
+ startpoint = obj.StartPoint
else:
startpoint = None
@@ -198,7 +216,7 @@ print "y - " + str(point.y)
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.
@@ -212,7 +230,7 @@ print "y - " + str(point.y)
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, \
@@ -241,17 +259,17 @@ print "y - " + str(point.y)
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25
- obj.ToolNumber= 0
+ 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
+ obj.ToolNumber= toolLoad.ToolNumber
if obj.Base:
for b in obj.Base:
-
+
# we only consider the outer wire if this is a Face
#shape = getattr(obj.Base[0][0].Shape,obj.Base[0][1])
shape = getattr(b[0].Shape,b[1])
@@ -259,7 +277,7 @@ print "y - " + str(point.y)
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()
@@ -268,10 +286,10 @@ print "y - " + str(point.y)
edgelist = wire.Edges
edgelist = Part.__sortEdges__(edgelist)
-
+
if obj.Algorithm == "OCC Native":
output += self._buildPathOCC(obj, wire)
-
+
else:
try:
import area
@@ -325,7 +343,7 @@ class _CommandAddTag:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
-
+
def setpoint(self,point,o):
obj=FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
@@ -334,7 +352,7 @@ class _CommandAddTag:
h = obj.heights
l = obj.lengths
a = obj.angles
-
+
x = point.x
y = point.y
z = float(0.0)
@@ -360,7 +378,7 @@ class _CommandSetStartPoint:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
-
+
def setpoint(self,point,o):
obj=FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
@@ -377,7 +395,7 @@ class _CommandSetEndPoint:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
-
+
def setpoint(self,point,o):
obj=FreeCADGui.Selection.getSelection()[0]
obj.EndPoint.x = point.x
@@ -396,7 +414,7 @@ class CommandPathProfile:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
-
+
def Activated(self):
#import Path
#from PathScripts import PathProject, PathUtils, PathKurveUtils
@@ -416,7 +434,7 @@ class CommandPathProfile:
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
-
+
FreeCADGui.doCommand('obj.SafeHeight = '+ str(ztop + 2.0))
FreeCADGui.doCommand('obj.Side = "Left"')
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
@@ -441,14 +459,14 @@ class TaskPanel:
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
- FreeCADGui.Selection.removeObserver(self.s)
+ FreeCADGui.Selection.removeObserver(self.s)
- def getFields(self):
+ def getFields(self):
if self.obj:
if hasattr(self.obj,"StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
@@ -483,7 +501,7 @@ class TaskPanel:
def open(self):
self.s =SelObserver()
# install the function mode resident
- FreeCADGui.Selection.addObserver(self.s)
+ FreeCADGui.Selection.addObserver(self.s)
def addBase(self):
# check that the selection contains exactly what we want
@@ -496,13 +514,13 @@ class TaskPanel:
if s.HasSubObjects:
for i in s.SubElementNames:
self.obj.Proxy.addprofilebase(self.obj, s.Object, i)
- else:
+ else:
self.obj.Proxy.addprofilebase(self.obj, s.Object)
-
+ self.setupUi() #defaults may have changed. Reload.
self.form.baseList.clear()
- for i in self.obj.Base:
+ for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name + "." + i[1])
-
+
def deleteBase(self):
dlist = self.form.baseList.selectedItems()
newlist = []
@@ -522,7 +540,7 @@ class TaskPanel:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# sub = o.Shape.getElement(objstring[2])
- if objstring[2] != "":
+ if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj,objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
@@ -557,7 +575,7 @@ class TaskPanel:
h = []
l = []
a = []
-
+
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):
@@ -655,7 +673,7 @@ class TaskPanel:
self.form.direction.setCurrentIndex(index)
- for i in self.obj.Base:
+ for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name + "." + i[1])
for i in range(len(self.obj.locs)):
@@ -677,14 +695,14 @@ class TaskPanel:
self.form.reorderBase.clicked.connect(self.reorderBase)
#Depths
- self.form.startDepth.editingFinished.connect(self.getFields)
+ 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)
@@ -695,7 +713,7 @@ class TaskPanel:
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)
@@ -704,11 +722,11 @@ class TaskPanel:
class SelObserver:
def __init__(self):
- import PathScripts.PathSelection as PST
+ import PathScripts.PathSelection as PST
PST.profileselect()
def __del__(self):
- import PathScripts.PathSelection as PST
+ import PathScripts.PathSelection as PST
PST.clear()
def addSelection(self,doc,obj,sub,pnt): # Selection object
@@ -716,7 +734,7 @@ class SelObserver:
FreeCADGui.updateGui()
-if FreeCAD.GuiUp:
+if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Profile',CommandPathProfile())
FreeCADGui.addCommand('Add_Tag',_CommandAddTag())
diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py
index f15740644..bcac2670b 100644
--- a/src/Mod/Path/PathScripts/PathSelection.py
+++ b/src/Mod/Path/PathScripts/PathSelection.py
@@ -35,10 +35,7 @@ def equals(p1,p2):
v = Vector(p2.X,p2.Y,p2.Z)
vector = (u.sub(v))
isNull = (round(vector.x,p)==0 and round(vector.y,p)==0 and round(vector.z,p)==0)
- return isNull
-
-
-
+ return isNull
def segments(poly):
''' A sequence of (x,y) numeric coordinates pairs '''
@@ -67,6 +64,11 @@ class EGate:
def allow(self,doc,obj,sub):
return (sub[0:4] == 'Edge')
+class MESHGate:
+ def allow(self,doc,obj,sub):
+ print obj.TypeId[0:4] == 'Mesh'
+ return (obj.TypeId[0:4] == 'Mesh')
+
class ENGRAVEGate:
def allow(self,doc,obj,sub):
return (obj.Name[0:11] == 'ShapeString')
@@ -79,15 +81,15 @@ class DRILLGate:
obj = obj.Shape
except:
return False
- if obj.ShapeType == 'Vertex':
+ if obj.ShapeType == 'Vertex':
drillable = True
- elif obj.ShapeType == 'Edge':
+ elif obj.ShapeType == 'Edge':
if isinstance(obj.Curve, Part.Circle):
- drillable = True
- elif obj.ShapeType == 'Face':
+ drillable = True
+ elif obj.ShapeType == 'Face':
if isinstance(obj.Edges[0].Curve, Part.Circle):
- drillable = True
- elif obj.ShapeType == 'Wire':
+ drillable = True
+ elif obj.ShapeType == 'Wire':
if isinstance(obj.Edges[0].Curve, Part.Circle):
drillable = True
elif obj.ShapeType == 'Solid':
@@ -111,7 +113,7 @@ class PROFILEGate:
return False
- if obj.ShapeType == 'Edge':
+ if obj.ShapeType == 'Edge':
profileable = True
elif obj.ShapeType == 'Face':
@@ -124,12 +126,12 @@ class PROFILEGate:
if sub[0:4] == 'Edge':
profileable = True
- elif obj.ShapeType == 'Wire':
+ 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:
@@ -143,7 +145,7 @@ class POCKETGate:
return False
- if obj.ShapeType == 'Edge':
+ if obj.ShapeType == 'Edge':
pocketable = False
elif obj.ShapeType == 'Face':
@@ -156,12 +158,12 @@ class POCKETGate:
# if sub[0:4] == 'Edge':
# pocketable = True
- # elif obj.ShapeType == 'Wire':
+ # 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
@@ -183,19 +185,20 @@ def drillselect():
def engraveselect():
FreeCADGui.Selection.addSelectionGate(ENGRAVEGate())
- FreeCAD.Console.PrintWarning("Engrave Select Mode\n")
+ FreeCAD.Console.PrintWarning("Engraving Select Mode\n")
def profileselect():
FreeCADGui.Selection.addSelectionGate(PROFILEGate())
- FreeCAD.Console.PrintWarning("Profile Select Mode\n")
+ FreeCAD.Console.PrintWarning("Profiling Select Mode\n")
def pocketselect():
FreeCADGui.Selection.addSelectionGate(POCKETGate())
- FreeCAD.Console.PrintWarning("Pocket Select Mode\n")
+ FreeCAD.Console.PrintWarning("Pocketing Select Mode\n")
+def surfaceselect():
+ FreeCADGui.Selection.addSelectionGate(MESHGate())
+ FreeCAD.Console.PrintWarning("Surfacing Select Mode\n")
def clear():
FreeCADGui.Selection.removeSelectionGate()
FreeCAD.Console.PrintWarning("Free Select\n")
-
-
diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py
index 708bf3bbe..a84070b27 100644
--- a/src/Mod/Path/PathScripts/PathSurface.py
+++ b/src/Mod/Path/PathScripts/PathSurface.py
@@ -23,11 +23,10 @@
#***************************************************************************
import FreeCAD,Path
-from FreeCAD import Vector
-from PathScripts import PathUtils,PathSelection,PathProject
+from PathScripts import PathUtils
if FreeCAD.GuiUp:
- import FreeCADGui, PathGui
+ import FreeCADGui
from PySide import QtCore, QtGui
from DraftTools import translate
from pivy import coin
@@ -52,12 +51,12 @@ except AttributeError:
class ObjectSurface:
-
def __init__(self,obj):
- obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object(s)","The base geometry of this toolpath"))
+ obj.addProperty("App::PropertyLinkSubList","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("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 Dropcutter', 'OCL Waterline']
@@ -69,22 +68,48 @@ class ObjectSurface:
#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::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::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."))
- #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.Proxy = self
+
+ def addsurfacebase(self, obj, ss, sub=""):
+ baselist = obj.Base
+ if len(baselist) == 0: #When adding the first base object, guess at heights
+ try:
+ bb = ss.Shape.BoundBox #parent boundbox
+ subobj = ss.Shape.getElement(sub)
+ fbb = subobj.BoundBox #feature boundbox
+ obj.StartDepth = bb.ZMax
+ obj.ClearanceHeight = bb.ZMax + 5.0
+ obj.SafeHeight = bb.ZMax + 3.0
+
+ if fbb.ZMax < bb.ZMax:
+ obj.FinalDepth = fbb.ZMax
+ else:
+ obj.FinalDepth = bb.ZMin
+ except:
+ obj.StartDepth = 5.0
+ obj.ClearanceHeight = 10.0
+ obj.SafeHeight = 8.0
+
+ item = (ss, sub)
+ if item in baselist:
+ FreeCAD.Console.PrintWarning("this object already in the list"+ "\n")
+ else:
+ baselist.append (item)
+ obj.Base = baselist
+ self.execute(obj)
+
+
def __getstate__(self):
return None
@@ -93,7 +118,6 @@ class ObjectSurface:
def _waterline(self,obj, s, bb):
import ocl
-# from PathScripts.PathUtils import fmt
from PathScripts.PathUtils import depth_params, fmt
import time
@@ -104,7 +128,7 @@ class ObjectSurface:
for loop in loops:
p = loop[0]
loopstring = "(loop begin)" +"\n"
- loopstring += "G0 Z" + str(obj.SafeHeight) +"\n"
+ loopstring += "G0 Z" + str(obj.SafeHeight.Value) +"\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:]:
@@ -117,54 +141,21 @@ class ObjectSurface:
nloop = nloop+1
waterlinestring += loopstring
waterlinestring += "(waterline end)" +"\n"
-
return waterlinestring
- # 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)
-
+ depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value)
# stlfile = "../../stl/gnu_tux_mod.stl"
# surface = STLSurfaceSource(stlfile)
-
surface = s
- t_before = time.time()
-
+ t_before = time.time()
zheights= depthparams.get_depths()
-
- wl = ocl.Waterline()
+ wl = ocl.Waterline()
#wl = ocl.AdaptiveWaterline() # this is slower, ca 60 seconds on i7 CPU
wl.setSTL(surface)
diam = 0.5
- length= 10
+ length= 10.0
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
@@ -194,36 +185,35 @@ class ObjectSurface:
cutter = ocl.CylCutter(self.radius*2, 5)
pdc = ocl.PathDropCutter() # create a pdc
pdc.setSTL(s)
- pdc.setCutter(cutter)
- pdc.minimumZ = 0.25
+ pdc.setCutter(cutter)
+ pdc.minimumZ = 0.25
pdc.setSampling(obj.SampleInterval)
-
- # some parameters for this "zigzig" pattern
+
+ # 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
+ if (n % 2 == 0): #even
l = ocl.Line(p1,p2) # line-object
else: #odd
l = ocl.Line(p2,p1) # line-object
path.append( l ) # add the line to the path
-
+
pdc.setPath( path )
-
+
# run drop-cutter on the path
t_before = time.time()
pdc.run()
@@ -231,70 +221,66 @@ class ObjectSurface:
print "calculation took ", t_after-t_before," s"
#retrieve the points
- clp = pdc.getCLPoints()
+ clp = pdc.getCLPoints()
print "points received: " + str(len(clp))
#generate the path commands
output = ""
- output += "G0 Z" + str(obj.ClearanceHeight) + "\n"
+ output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\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"
-
+ output += "G1 Z" + str(clp[0].z) + " F" + str(self.vertFeed) + "\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
+ toolLoad = PathUtils.getLastToolLoad(obj)
+ if toolLoad == None:
+ self.vertFeed = 100
+ self.horizFeed = 100
self.radius = 0.25
-
-
- mesh = obj.Base[0]
- if mesh.TypeId.startswith('Mesh'):
- mesh = mesh.Mesh
- bb = mesh.BoundBox
+ obj.ToolNumber= 0
else:
- bb = mesh.Shape.BoundBox
- mesh = MeshPart.meshFromShape(mesh.Shape,MaxLength=2)
+ 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
- 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)
+ if obj.Base:
+ for b in obj.Base:
+ 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
+
+ mesh = b[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
@@ -315,10 +301,6 @@ class ViewProviderSurface:
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
@@ -327,9 +309,13 @@ class ViewProviderSurface:
# 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
@@ -351,48 +337,51 @@ class CommandPathSurfacing:
def Activated(self):
# check that the selection contains exactly what we want
- selection = FreeCADGui.Selection.getSelectionEx()
- if len(selection) != 1:
- FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
- return
- if not len(selection[0].SubObjects) == 0:
- FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\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("PathSurface","Please select only edges or a single face\n"))
- return
+ # selection = FreeCADGui.Selection.getSelectionEx()
+ # if len(selection) != 1:
+ # FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
+ # return
+ # if not len(selection[0].SubObjects) == 0:
+ # FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\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("PathSurface","Please select only edges or a single face\n"))
+ # return
- 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
+ # 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:
- FreeCAD.Console.PrintError(translate("PathSurface","Cannot work with this object\n"))
- return
+ # #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:
+ # FreeCAD.Console.PrintError(translate("PathSurface","Cannot work with this object\n"))
+ # return
# if everything is ok, execute and register the transaction in the undo/redo stack
+
+ ztop = 10
+ zbottom = 0
+
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.ObjectSurface(obj)')
FreeCADGui.doCommand('obj.Active = True')
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))
@@ -405,9 +394,153 @@ class CommandPathSurfacing:
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.doCommand('obj.ViewObject.startEditing()')
-if FreeCAD.GuiUp:
+class TaskPanel:
+ def __init__(self):
+ self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/SurfaceEdit.ui")
+ #self.form = FreeCADGui.PySideUic.loadUi(":/SurfaceEdit.ui")
+
+ def accept(self):
+ self.getFields()
+
+ FreeCADGui.ActiveDocument.resetEdit()
+ FreeCADGui.Control.closeDialog()
+ FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.Selection.removeObserver(self.s)
+
+ def reject(self):
+ FreeCADGui.Control.closeDialog()
+ FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.Selection.removeObserver(self.s)
+
+ def getFields(self):
+ if self.obj:
+ if hasattr(self.obj,"StartDepth"):
+ self.obj.StartDepth = self.form.startDepth.text()
+ if hasattr(self.obj,"FinalDepth"):
+ self.obj.FinalDepth = self.form.finalDepth.text()
+ if hasattr(self.obj,"SafeHeight"):
+ self.obj.SafeHeight = self.form.safeHeight.text()
+ if hasattr(self.obj,"ClearanceHeight"):
+ self.obj.ClearanceHeight = self.form.clearanceHeight.text()
+ if hasattr(self.obj,"StepDown"):
+ self.obj.StepDown = self.form.stepDown.value()
+ if hasattr(self.obj,"Algorithm"):
+ self.obj.Algorithm = str(self.form.algorithmSelect.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 len(selection) != 1:
+ FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
+ return
+
+ if not len(selection[0].SubObjects) == 0:
+ FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
+ return
+
+ sel = selection[0].Object
+ #get type of object
+ if sel.TypeId.startswith('Mesh'):
+ #it is a mesh already
+ print 'was already mesh'
+
+ #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):
+ print 'this is a solid Part object'
+
+ else:
+ FreeCAD.Console.PrintError(translate("PathSurface","Cannot work with this object\n"))
+ return
+
+ self.obj.Proxy.addsurfacebase(self.obj, sel)
+
+ self.setupUi() #defaults may have changed. Reload.
+ self.form.baseList.clear()
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name)
+
+ def deleteBase(self):
+ dlist = self.form.baseList.selectedItems()
+ for d in dlist:
+ newlist = []
+ for i in self.obj.Base:
+ if not i[0].Name == d.text():
+ newlist.append (i)
+ self.obj.Base = newlist
+ self.form.baseList.takeItem(self.form.baseList.row(d))
+ self.obj.Proxy.execute(self.obj)
+ FreeCAD.ActiveDocument.recompute()
+
+ def itemActivated(self):
+ FreeCADGui.Selection.clearSelection()
+ slist = self.form.baseList.selectedItems()
+ for i in slist:
+ o = FreeCAD.ActiveDocument.getObject(i.text())
+ FreeCADGui.Selection.addSelection(o)
+ FreeCADGui.updateGui()
+
+ def reorderBase(self):
+ newlist = []
+ for i in range(self.form.baseList.count()):
+ s = self.form.baseList.item(i).text()
+ obj = FreeCAD.ActiveDocument.getObject(s)
+ newlist.append(obj)
+ self.obj.Base=newlist
+ self.obj.Proxy.execute(self.obj)
+ FreeCAD.ActiveDocument.recompute()
+
+ def getStandardButtons(self):
+ return int(QtGui.QDialogButtonBox.Ok)
+
+ def setupUi(self):
+ self.form.startDepth.setText(str(self.obj.StartDepth.Value))
+ self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
+ self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
+ self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
+
+ for i in self.obj.Base:
+ self.form.baseList.addItem(i[0].Name)
+
+ #Connect Signals and Slots
+ self.form.startDepth.editingFinished.connect(self.getFields)
+ self.form.finalDepth.editingFinished.connect(self.getFields)
+ self.form.safeHeight.editingFinished.connect(self.getFields)
+ self.form.clearanceHeight.editingFinished.connect(self.getFields)
+
+ self.form.addBase.clicked.connect(self.addBase)
+ self.form.deleteBase.clicked.connect(self.deleteBase)
+ self.form.reorderBase.clicked.connect(self.reorderBase)
+
+ self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
+
+class SelObserver:
+ def __init__(self):
+ import PathScripts.PathSelection as PST
+ PST.surfaceselect()
+
+ 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
FreeCADGui.addCommand('Path_Surfacing',CommandPathSurfacing())