PEP8 cleanup
This commit is contained in:
parent
eeec4f88a3
commit
2f17f11049
|
@ -1,29 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD,Path
|
||||
from PySide import QtCore,QtGui
|
||||
import FreeCAD
|
||||
import Path
|
||||
from PySide import QtCore, QtGui
|
||||
from PathScripts import PathUtils
|
||||
|
||||
FreeCADGui = None
|
||||
|
@ -35,6 +36,7 @@ if FreeCAD.GuiUp:
|
|||
# Qt tanslation handling
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
|
||||
def translate(context, text, disambig=None):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
|
@ -44,47 +46,46 @@ except AttributeError:
|
|||
|
||||
class ObjectDrilling:
|
||||
|
||||
def __init__(self, obj):
|
||||
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"))
|
||||
|
||||
def __init__(self,obj):
|
||||
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("PathProject", "The height where feed starts and height during retract tool when path is finished"))
|
||||
|
||||
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("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.setEditorMode('ToolNumber',1) #make this read only
|
||||
# Tool Properties
|
||||
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", translate("PathProfile", "The tool number in use"))
|
||||
obj.ToolNumber = (0, 0, 1000, 1)
|
||||
obj.setEditorMode('ToolNumber', 1) # make this read only
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state):
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def execute(self,obj):
|
||||
def execute(self, obj):
|
||||
output = ""
|
||||
toolLoad = PathUtils.getLastToolLoad(obj)
|
||||
if toolLoad == None:
|
||||
if toolLoad is None:
|
||||
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
|
||||
obj.ToolNumber= toolLoad.ToolNumber
|
||||
obj.ToolNumber = toolLoad.ToolNumber
|
||||
|
||||
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
|
||||
if tool == None:
|
||||
if tool is None:
|
||||
self.radius = 0.25
|
||||
else:
|
||||
self.radius = tool.Diameter/2
|
||||
|
@ -94,11 +95,11 @@ class ObjectDrilling:
|
|||
for loc in obj.Base:
|
||||
|
||||
if "Face" in loc[1] or "Edge" in loc[1]:
|
||||
s = getattr(loc[0].Shape,loc[1])
|
||||
s = getattr(loc[0].Shape, loc[1])
|
||||
else:
|
||||
s = loc[0].Shape
|
||||
|
||||
if s.ShapeType in ['Face', 'Wire', 'Edge' ]:
|
||||
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
|
||||
|
@ -107,40 +108,43 @@ class ObjectDrilling:
|
|||
Y = s.Point.y
|
||||
Z = s.Point.z
|
||||
|
||||
locations.append(FreeCAD.Vector(X,Y,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"
|
||||
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)
|
||||
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 += 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
|
||||
|
||||
|
||||
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
|
||||
if len(baselist) == 0: # When adding the first base object, guess at heights
|
||||
try:
|
||||
bb = ss.Shape.BoundBox #parent boundbox
|
||||
bb = ss.Shape.BoundBox # parent boundbox
|
||||
subobj = ss.Shape.getElement(sub)
|
||||
fbb = subobj.BoundBox #feature boundbox
|
||||
fbb = subobj.BoundBox # feature boundbox
|
||||
obj.StartDepth = bb.ZMax
|
||||
obj.ClearanceHeight = bb.ZMax + 5.0
|
||||
obj.SafeHeight = bb.ZMax + 3.0
|
||||
|
@ -157,34 +161,35 @@ class ObjectDrilling:
|
|||
obj.RetractHeight = 6.0
|
||||
|
||||
if item in baselist:
|
||||
FreeCAD.Console.PrintWarning("Drillable location already in the list"+ "\n")
|
||||
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n")
|
||||
else:
|
||||
baselist.append (item)
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
|
||||
class _ViewProviderDrill:
|
||||
def __init__(self,obj): #mandatory
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
|
||||
def __getstate__(self): #mandatory
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state): #mandatory
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def getIcon(self): #optional
|
||||
def getIcon(self):
|
||||
return ":/icons/Path-Drilling.svg"
|
||||
|
||||
def onChanged(self,obj,prop): #optional
|
||||
def onChanged(self, obj, prop):
|
||||
# this is executed when a property of the VIEW PROVIDER changes
|
||||
pass
|
||||
|
||||
def updateData(self,obj,prop): #optional
|
||||
def updateData(self, obj, prop):
|
||||
# this is executed when a property of the APP OBJECT changes
|
||||
pass
|
||||
|
||||
def setEdit(self,vobj,mode=0):
|
||||
def setEdit(self, vobj, mode=0):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
taskd = TaskPanel()
|
||||
taskd.obj = vobj.Object
|
||||
|
@ -192,28 +197,28 @@ class _ViewProviderDrill:
|
|||
taskd.setupUi()
|
||||
return True
|
||||
|
||||
|
||||
def unsetEdit(self,vobj,mode): #optional
|
||||
def unsetEdit(self, vobj, mode):
|
||||
# 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"),
|
||||
return {'Pixmap': 'Path-Drilling',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Drilling", "Drilling"),
|
||||
'Accel': "P, D",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Drilling","Creates a Path Drilling object")}
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Drilling", "Creates a Path Drilling object")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
def Activated(self):
|
||||
|
||||
# if everything is ok, execute and register the transaction in the undo/redo stack
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_Drilling","Create Drilling"))
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_Drilling", "Create Drilling"))
|
||||
FreeCADGui.addModule("PathScripts.PathDrilling")
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Drilling")')
|
||||
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)')
|
||||
|
@ -229,9 +234,9 @@ class CommandPathDrilling:
|
|||
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(":/panels/DrillingEdit.ui")
|
||||
|
||||
def accept(self):
|
||||
|
@ -249,32 +254,31 @@ class TaskPanel:
|
|||
|
||||
def getFields(self):
|
||||
if self.obj:
|
||||
if hasattr(self.obj,"StartDepth"):
|
||||
if hasattr(self.obj, "StartDepth"):
|
||||
self.obj.StartDepth = self.form.startDepth.text()
|
||||
if hasattr(self.obj,"FinalDepth"):
|
||||
if hasattr(self.obj, "FinalDepth"):
|
||||
self.obj.FinalDepth = self.form.finalDepth.text()
|
||||
if hasattr(self.obj,"PeckDepth"):
|
||||
if hasattr(self.obj, "PeckDepth"):
|
||||
self.obj.PeckDepth = self.form.peckDepth.text()
|
||||
if hasattr(self.obj,"SafeHeight"):
|
||||
if hasattr(self.obj, "SafeHeight"):
|
||||
self.obj.SafeHeight = self.form.safeHeight.text()
|
||||
if hasattr(self.obj,"ClearanceHeight"):
|
||||
if hasattr(self.obj, "ClearanceHeight"):
|
||||
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
|
||||
if hasattr(self.obj,"RetractHeight"):
|
||||
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
|
||||
self.s = SelObserver()
|
||||
FreeCADGui.Selection.addObserver(self.s)
|
||||
|
||||
def addBase(self):
|
||||
# check that the selection contains exactly what we want
|
||||
# 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"))
|
||||
FreeCAD.Console.PrintError(translate("PathProject", "Please select at least one Drillable Location\n"))
|
||||
return
|
||||
for s in selection:
|
||||
if s.HasSubObjects:
|
||||
|
@ -283,19 +287,18 @@ class TaskPanel:
|
|||
else:
|
||||
self.obj.Proxy.addDrillableLocation(self.obj, s.Object)
|
||||
|
||||
self.setupUi() #defaults may have changed. Reload.
|
||||
self.setupUi() # defaults may have changed. Reload.
|
||||
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)
|
||||
newlist.append(i)
|
||||
self.obj.Base = newlist
|
||||
self.form.baseList.takeItem(self.form.baseList.row(d))
|
||||
# self.obj.Proxy.execute(self.obj)
|
||||
|
@ -307,9 +310,9 @@ class TaskPanel:
|
|||
for i in slist:
|
||||
objstring = i.text().partition(".")
|
||||
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
|
||||
# sub = o.Shape.getElement(objstring[2])
|
||||
# sub = o.Shape.getElement(objstring[2])
|
||||
if objstring[2] != "":
|
||||
FreeCADGui.Selection.addSelection(obj,objstring[2])
|
||||
FreeCADGui.Selection.addSelection(obj, objstring[2])
|
||||
else:
|
||||
FreeCADGui.Selection.addSelection(obj)
|
||||
|
||||
|
@ -324,7 +327,7 @@ class TaskPanel:
|
|||
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
|
||||
item = (obj, str(objstring[2]))
|
||||
newlist.append(item)
|
||||
self.obj.Base=newlist
|
||||
self.obj.Base = newlist
|
||||
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
@ -340,12 +343,11 @@ class TaskPanel:
|
|||
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
|
||||
# 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)
|
||||
|
@ -356,6 +358,7 @@ class TaskPanel:
|
|||
|
||||
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
|
||||
|
||||
|
||||
class SelObserver:
|
||||
def __init__(self):
|
||||
import PathScripts.PathSelection as PST
|
||||
|
@ -365,13 +368,13 @@ class SelObserver:
|
|||
import PathScripts.PathSelection as PST
|
||||
PST.clear()
|
||||
|
||||
def addSelection(self,doc,obj,sub,pnt): # Selection object
|
||||
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj +')')
|
||||
def addSelection(self, doc, obj, sub, pnt):
|
||||
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Drilling',CommandPathDrilling())
|
||||
FreeCADGui.addCommand('Path_Drilling', CommandPathDrilling())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathDrilling... done\n")
|
||||
|
|
|
@ -1,30 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD,FreeCADGui,Path,Draft
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import Path
|
||||
import Draft
|
||||
|
||||
from PySide import QtCore,QtGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PathScripts import PathUtils
|
||||
|
||||
"""Path Engrave object and FreeCAD command"""
|
||||
|
@ -32,6 +35,7 @@ from PathScripts import PathUtils
|
|||
# Qt tanslation handling
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
|
||||
def translate(context, text, disambig=None):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
|
@ -41,26 +45,25 @@ 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::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.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.setEditorMode('ToolNumber',1) #make this read only
|
||||
# Tool Properties
|
||||
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"))
|
||||
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("Path","Rapid Safety Height between locations."))
|
||||
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")
|
||||
# Depth Properties
|
||||
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Path", "The height needed to clear clamps and obstructions"))
|
||||
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("Path", "Rapid Safety Height between locations."))
|
||||
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")
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderEngrave(obj.ViewObject)
|
||||
|
@ -70,25 +73,25 @@ class ObjectPathEngrave:
|
|||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state):
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def execute(self,obj):
|
||||
def execute(self, obj):
|
||||
output = ""
|
||||
|
||||
toolLoad = PathUtils.getLastToolLoad(obj)
|
||||
if toolLoad == None:
|
||||
if toolLoad is None:
|
||||
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
|
||||
obj.ToolNumber= toolLoad.ToolNumber
|
||||
obj.ToolNumber = toolLoad.ToolNumber
|
||||
|
||||
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
|
||||
if tool == None:
|
||||
if tool is None:
|
||||
self.radius = 0.25
|
||||
else:
|
||||
self.radius = tool.Diameter/2
|
||||
|
@ -102,14 +105,15 @@ class ObjectPathEngrave:
|
|||
if obj.Algorithm == "OCC Native":
|
||||
output += self.buildpathocc(obj, wires)
|
||||
|
||||
#print output
|
||||
# print output
|
||||
if output == "":
|
||||
output +="G0"
|
||||
output += "G0"
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
|
||||
def buildpathocc(self, obj, wires):
|
||||
import Part,DraftGeomUtils
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
output = "G90\nG21\nG40\n"
|
||||
output += "G0 Z" + str(obj.ClearanceHeight.Value)
|
||||
|
||||
|
@ -119,7 +123,7 @@ class ObjectPathEngrave:
|
|||
offset = wire
|
||||
|
||||
# reorder the wire
|
||||
offset = DraftGeomUtils.rebaseWire(offset,obj.StartVertex)
|
||||
offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex)
|
||||
|
||||
# we create the path from the offset shape
|
||||
last = None
|
||||
|
@ -127,11 +131,11 @@ class ObjectPathEngrave:
|
|||
if not last:
|
||||
# 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(self.vertFeed)+ "\n" #Vertical feed to depth
|
||||
if isinstance(edge.Curve,Part.Circle):
|
||||
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(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
|
||||
if point == last: # edges can come flipped
|
||||
point = edge.Vertexes[0].Point
|
||||
center = edge.Curve.Center
|
||||
relcenter = center.sub(last)
|
||||
|
@ -143,27 +147,27 @@ 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(self.horizFeed)
|
||||
output += " F " + str(self.horizFeed)
|
||||
output += "\n"
|
||||
last = point
|
||||
else:
|
||||
point = edge.Vertexes[-1].Point
|
||||
if point == last: # edges can come flipped
|
||||
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(self.horizFeed)
|
||||
output += "\n"
|
||||
output += " F " + str(self.horizFeed)
|
||||
output += "\n"
|
||||
last = point
|
||||
output += "G0 Z " + str(obj.SafeHeight.Value)
|
||||
return output
|
||||
|
||||
def addShapeString(self, obj, ss):
|
||||
baselist = obj.Base
|
||||
if len(baselist) == 0: #When adding the first base object, guess at heights
|
||||
if len(baselist) == 0: # When adding the first base object, guess at heights
|
||||
try:
|
||||
bb = ss.Shape.BoundBox #parent boundbox
|
||||
bb = ss.Shape.BoundBox # parent boundbox
|
||||
subobj = ss.Shape.getElement(sub)
|
||||
fbb = subobj.BoundBox #feature boundbox
|
||||
fbb = subobj.BoundBox # feature boundbox
|
||||
obj.StartDepth = bb.ZMax
|
||||
obj.ClearanceHeight = bb.ZMax + 5.0
|
||||
obj.SafeHeight = bb.ZMax + 3.0
|
||||
|
@ -179,24 +183,24 @@ class ObjectPathEngrave:
|
|||
|
||||
item = (ss, "")
|
||||
if item in baselist:
|
||||
FreeCAD.Console.PrintWarning("ShapeString already in the Engraving list"+ "\n")
|
||||
FreeCAD.Console.PrintWarning("ShapeString already in the Engraving list" + "\n")
|
||||
|
||||
else:
|
||||
baselist.append (item)
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
|
||||
class _ViewProviderEngrave:
|
||||
|
||||
def __init__(self,vobj):
|
||||
def __init__(self, vobj):
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self,vobj):
|
||||
def attach(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
return
|
||||
|
||||
def setEdit(self,vobj,mode=0):
|
||||
def setEdit(self, vobj, mode=0):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
taskd = TaskPanel()
|
||||
taskd.obj = vobj.Object
|
||||
|
@ -210,43 +214,42 @@ class _ViewProviderEngrave:
|
|||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state):
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
|
||||
class CommandPathEngrave:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Path-Engrave',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Engrave","ShapeString Engrave"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Engrave","Creates an Engraving Path around a Draft ShapeString")}
|
||||
return {'Pixmap': 'Path-Engrave',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Engrave", "ShapeString Engrave"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Engrave", "Creates an Engraving Path around a Draft ShapeString")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
def Activated(self):
|
||||
|
||||
# if everything is ok, execute and register the transaction in the undo/redo stack
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Engrave Path")
|
||||
FreeCADGui.addModule("PathScripts.PathFaceProfile")
|
||||
FreeCADGui.addModule("PathScripts.PathUtils")
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","PathEngrave")')
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "PathEngrave")')
|
||||
FreeCADGui.doCommand('PathScripts.PathEngrave.ObjectPathEngrave(obj)')
|
||||
|
||||
FreeCADGui.doCommand('obj.ClearanceHeight = 10')
|
||||
FreeCADGui.doCommand('obj.StartDepth= 0')
|
||||
FreeCADGui.doCommand('obj.FinalDepth= -0.1' )
|
||||
FreeCADGui.doCommand('obj.SafeHeight= 5.0' )
|
||||
FreeCADGui.doCommand('obj.FinalDepth= -0.1')
|
||||
FreeCADGui.doCommand('obj.SafeHeight= 5.0')
|
||||
|
||||
#FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
|
||||
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
|
||||
|
||||
|
||||
class TaskPanel:
|
||||
def __init__(self):
|
||||
#self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/EngraveEdit.ui")
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/EngraveEdit.ui")
|
||||
|
||||
def accept(self):
|
||||
|
@ -264,33 +267,32 @@ class TaskPanel:
|
|||
|
||||
def getFields(self):
|
||||
if self.obj:
|
||||
if hasattr(self.obj,"StartDepth"):
|
||||
if hasattr(self.obj, "StartDepth"):
|
||||
self.obj.StartDepth = self.form.startDepth.text()
|
||||
if hasattr(self.obj,"FinalDepth"):
|
||||
if hasattr(self.obj, "FinalDepth"):
|
||||
self.obj.FinalDepth = self.form.finalDepth.text()
|
||||
if hasattr(self.obj,"SafeHeight"):
|
||||
if hasattr(self.obj, "SafeHeight"):
|
||||
self.obj.SafeHeight = self.form.safeHeight.text()
|
||||
if hasattr(self.obj,"ClearanceHeight"):
|
||||
if hasattr(self.obj, "ClearanceHeight"):
|
||||
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
|
||||
|
||||
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def open(self):
|
||||
self.s =SelObserver()
|
||||
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
|
||||
# check that the selection contains exactly what we want
|
||||
selection = FreeCADGui.Selection.getSelectionEx()
|
||||
|
||||
if not len(selection) >= 1:
|
||||
FreeCAD.Console.PrintError(translate("Path_Engrave","Please select at least one ShapeString\n"))
|
||||
FreeCAD.Console.PrintError(translate("Path_Engrave", "Please select at least one ShapeString\n"))
|
||||
return
|
||||
for s in selection:
|
||||
if not Draft.getType(s.Object) == "ShapeString":
|
||||
FreeCAD.Console.PrintError(translate("Path_Engrave","Please select at least one ShapeString\n"))
|
||||
FreeCAD.Console.PrintError(translate("Path_Engrave", "Please select at least one ShapeString\n"))
|
||||
return
|
||||
self.obj.Proxy.addShapeString(self.obj, s.Object)
|
||||
|
||||
|
@ -304,11 +306,9 @@ class TaskPanel:
|
|||
newlist = []
|
||||
for i in self.obj.Base:
|
||||
if not i[0].Name == d.text():
|
||||
newlist.append (i)
|
||||
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()
|
||||
|
@ -321,10 +321,10 @@ class TaskPanel:
|
|||
def reorderBase(self):
|
||||
newlist = []
|
||||
for i in range(self.form.baseList.count()):
|
||||
s = self.form.baseList.item(i).text()
|
||||
s = self.form.baseList.item(i).text()
|
||||
obj = FreeCAD.ActiveDocument.getObject(s)
|
||||
newlist.append(obj)
|
||||
self.obj.Base=newlist
|
||||
self.obj.Base = newlist
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
@ -340,7 +340,7 @@ class TaskPanel:
|
|||
for i in self.obj.Base:
|
||||
self.form.baseList.addItem(i[0].Name)
|
||||
|
||||
#Connect Signals and Slots
|
||||
# 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)
|
||||
|
@ -362,10 +362,9 @@ class SelObserver:
|
|||
import PathScripts.PathSelection as PST
|
||||
PST.clear()
|
||||
|
||||
def addSelection(self,doc,obj,sub,pnt): # Selection object
|
||||
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj +')')
|
||||
def addSelection(self, doc, obj, sub, pnt):
|
||||
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Engrave',CommandPathEngrave())
|
||||
FreeCADGui.addCommand('Path_Engrave', CommandPathEngrave())
|
||||
|
|
|
@ -1,142 +1,144 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2015 Dan Falck <ddfalck@gmail.com> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2015 Dan Falck <ddfalck@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
''' Used for CNC machine to load cutting Tool ie M6T3'''
|
||||
|
||||
import FreeCAD,FreeCADGui,Path,PathGui
|
||||
import PathScripts, PathUtils
|
||||
from PathScripts import PathProject
|
||||
from PySide import QtCore,QtGui
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import Path
|
||||
# import PathGui
|
||||
import PathScripts
|
||||
import PathUtils
|
||||
# from PathScripts import PathProject
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
# Qt tanslation handling
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
|
||||
def translate(context, text, disambig=None):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def translate(context, text, disambig=None):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
class LoadTool:
|
||||
def __init__(self,obj):
|
||||
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber","Tool","The active tool")
|
||||
obj.ToolNumber = (0,0,10000,1)
|
||||
obj.addProperty("App::PropertyFloat", "SpindleSpeed", "Tool","The speed of the cutting spindle in RPM")
|
||||
obj.addProperty("App::PropertyEnumeration", "SpindleDir", "Tool","Direction of spindle rotation")
|
||||
obj.SpindleDir = ['Forward','Reverse']
|
||||
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"))
|
||||
def __init__(self, obj):
|
||||
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", translate("Tool Number", "The active tool"))
|
||||
obj.ToolNumber = (0, 0, 10000, 1)
|
||||
obj.addProperty("App::PropertyFloat", "SpindleSpeed", "Tool", translate("Spindle Speed", "The speed of the cutting spindle in RPM"))
|
||||
obj.addProperty("App::PropertyEnumeration", "SpindleDir", "Tool", translate("Spindle Dir", "Direction of spindle rotation"))
|
||||
obj.SpindleDir = ['Forward', 'Reverse']
|
||||
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
|
||||
mode = 2
|
||||
obj.setEditorMode('Placement',mode)
|
||||
obj.setEditorMode('Placement', mode)
|
||||
|
||||
|
||||
|
||||
def execute(self,obj):
|
||||
def execute(self, obj):
|
||||
commands = ""
|
||||
commands = 'M6T'+str(obj.ToolNumber)+'\n'
|
||||
|
||||
if obj.SpindleDir =='Forward':
|
||||
commands +='M3S'+str(obj.SpindleSpeed)+'\n'
|
||||
if obj.SpindleDir == 'Forward':
|
||||
commands += 'M3S' + str(obj.SpindleSpeed) + '\n'
|
||||
|
||||
else:
|
||||
commands +='M4S'+str(obj.SpindleSpeed)+'\n'
|
||||
commands += 'M4S' + str(obj.SpindleSpeed) + '\n'
|
||||
|
||||
obj.Path = Path.Path(commands)
|
||||
obj.Label = "Tool"+str(obj.ToolNumber)
|
||||
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
def onChanged(self, obj, prop):
|
||||
mode = 2
|
||||
obj.setEditorMode('Placement',mode)
|
||||
#if prop == "ToolNumber":
|
||||
proj = PathUtils.findProj()
|
||||
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()
|
||||
|
||||
|
||||
g.touch()
|
||||
|
||||
|
||||
class _ViewProviderLoadTool:
|
||||
def __init__(self,vobj): #mandatory
|
||||
def __init__(self, vobj):
|
||||
vobj.Proxy = self
|
||||
mode = 2
|
||||
vobj.setEditorMode('LineWidth',mode)
|
||||
vobj.setEditorMode('MarkerColor',mode)
|
||||
vobj.setEditorMode('NormalColor',mode)
|
||||
vobj.setEditorMode('ShowFirstRapid',mode)
|
||||
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('LineWidth', mode)
|
||||
vobj.setEditorMode('MarkerColor', mode)
|
||||
vobj.setEditorMode('NormalColor', mode)
|
||||
vobj.setEditorMode('ShowFirstRapid', mode)
|
||||
vobj.setEditorMode('DisplayMode', mode)
|
||||
vobj.setEditorMode('BoundingBox', mode)
|
||||
vobj.setEditorMode('Selectable', mode)
|
||||
vobj.setEditorMode('ShapeColor', mode)
|
||||
vobj.setEditorMode('Transparency', mode)
|
||||
vobj.setEditorMode('Visibility', mode)
|
||||
|
||||
def __getstate__(self): #mandatory
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state): #mandatory
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def getIcon(self): #optional
|
||||
def getIcon(self):
|
||||
return ":/icons/Path-LoadTool.svg"
|
||||
|
||||
def onChanged(self,vobj,prop): #optional
|
||||
def onChanged(self, vobj, prop):
|
||||
mode = 2
|
||||
vobj.setEditorMode('LineWidth',mode)
|
||||
vobj.setEditorMode('MarkerColor',mode)
|
||||
vobj.setEditorMode('NormalColor',mode)
|
||||
vobj.setEditorMode('ShowFirstRapid',mode)
|
||||
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('LineWidth', mode)
|
||||
vobj.setEditorMode('MarkerColor', mode)
|
||||
vobj.setEditorMode('NormalColor', mode)
|
||||
vobj.setEditorMode('ShowFirstRapid', mode)
|
||||
vobj.setEditorMode('DisplayMode', mode)
|
||||
vobj.setEditorMode('BoundingBox', mode)
|
||||
vobj.setEditorMode('Selectable', mode)
|
||||
|
||||
def updateData(self,vobj,prop): #optional
|
||||
def updateData(self, vobj, prop):
|
||||
# this is executed when a property of the APP OBJECT changes
|
||||
pass
|
||||
|
||||
def setEdit(self,vobj,mode): #optional
|
||||
def setEdit(self, vobj, mode):
|
||||
# this is executed when the object is double-clicked in the tree
|
||||
pass
|
||||
|
||||
def unsetEdit(self,vobj,mode): #optional
|
||||
def unsetEdit(self, vobj, mode):
|
||||
# this is executed when the user cancels or terminates edit mode
|
||||
pass
|
||||
|
||||
|
||||
class CommandPathLoadTool:
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Path-LoadTool',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_LoadTool","Tool Number to Load"),
|
||||
return {'Pixmap': 'Path-LoadTool',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_LoadTool", "Tool Number to Load"),
|
||||
'Accel': "P, T",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_LoadTool","Tool Number to Load")}
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_LoadTool", "Tool Number to Load")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
def Activated(self):
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Current Tool","Tool Number to Load"))
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Current Tool", "Tool Number to Load"))
|
||||
snippet = '''
|
||||
import Path, PathScripts
|
||||
from PathScripts import PathUtils, PathLoadTool
|
||||
|
@ -153,23 +155,20 @@ PathUtils.addToProject(obj)
|
|||
|
||||
@staticmethod
|
||||
def Create():
|
||||
#FreeCADGui.addModule("PathScripts.PathLoadTool")
|
||||
import Path, PathScripts, PathUtils
|
||||
# FreeCADGui.addModule("PathScripts.PathLoadTool")
|
||||
# import Path
|
||||
import PathScripts
|
||||
import PathUtils
|
||||
|
||||
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Tool")
|
||||
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Tool")
|
||||
PathScripts.PathLoadTool.LoadTool(obj)
|
||||
PathScripts.PathLoadTool._ViewProviderLoadTool(obj.ViewObject)
|
||||
|
||||
PathUtils.addToProject(obj)
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_LoadTool', CommandPathLoadTool())
|
||||
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathLoadTool... done\n")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -142,7 +142,7 @@ class ObjectProfile:
|
|||
|
||||
item = (ss, sub)
|
||||
if item in baselist:
|
||||
FreeCAD.Console.PrintWarning("this object already in the list" + "\n")
|
||||
FreeCAD.Console.PrintWarning(translate("Path", "this object already in the list" + "\n"))
|
||||
else:
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
|
@ -247,6 +247,7 @@ print "y - " + str(point.y)
|
|||
self.horizFeed = 100
|
||||
self.radius = 0.25
|
||||
obj.ToolNumber = 0
|
||||
FreeCAD.Console.PrintWarning(translate("Path", "No tool found. Using default values for now." + "\n"))
|
||||
else:
|
||||
self.vertFeed = toolLoad.VertFeed.Value
|
||||
self.horizFeed = toolLoad.HorizFeed.Value
|
||||
|
@ -444,6 +445,9 @@ class TaskPanel:
|
|||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ProfileEdit.ui")
|
||||
self.updating = False
|
||||
|
||||
def __del__(self):
|
||||
FreeCADGui.Selection.removeObserver(self.s)
|
||||
|
||||
def accept(self):
|
||||
self.getFields()
|
||||
|
||||
|
@ -725,7 +729,7 @@ class SelObserver:
|
|||
PST.clear()
|
||||
|
||||
def addSelection(self, doc, obj, sub, pnt):
|
||||
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
|
||||
#FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD,Path
|
||||
import FreeCAD
|
||||
import Path
|
||||
from PathScripts import PathUtils
|
||||
import urllib2
|
||||
import json
|
||||
|
@ -31,12 +32,11 @@ if FreeCAD.GuiUp:
|
|||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from DraftTools import translate
|
||||
from pivy import coin
|
||||
else:
|
||||
def translate(ctxt,txt):
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
__title__="Path Remote Operation"
|
||||
__title__ = "Path Remote Operation"
|
||||
__author__ = "sliptonic (Brad Collette)"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
@ -45,6 +45,7 @@ __url__ = "http://www.freecadweb.org"
|
|||
# Qt tanslation handling
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
|
||||
def translate(context, text, disambig=None):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
|
@ -54,39 +55,39 @@ except AttributeError:
|
|||
|
||||
class ObjectRemote:
|
||||
|
||||
def __init__(self,obj):
|
||||
def __init__(self, obj):
|
||||
|
||||
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::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::PropertyString","URL", "API", translate("RemotePath", "The Base URL of the remote path service"))
|
||||
obj.addProperty("App::PropertyStringList", "proplist","Path",translate("Path","list of remote properties"))
|
||||
obj.setEditorMode('proplist',2) #make this hidden
|
||||
obj.addProperty("App::PropertyString", "URL", "API", translate("RemotePath", "The Base URL of the remote path service"))
|
||||
obj.addProperty("App::PropertyStringList", "proplist", "Path", translate("Path", "list of remote properties"))
|
||||
obj.setEditorMode('proplist', 2) # make this hidden
|
||||
|
||||
#Tool Properties
|
||||
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use"))
|
||||
# Tool Properties
|
||||
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", translate("PathProfile", "The tool number in use"))
|
||||
obj.ToolNumber = (0, 0, 1000, 0)
|
||||
obj.setEditorMode('ToolNumber',1) #make this read only
|
||||
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::PropertyFloatConstraint", "StepDown", "Step", translate("PathProject","Incremental Step Down of Tool"))
|
||||
# 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::PropertyFloatConstraint", "StepDown", "Step", 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", "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.Proxy = self
|
||||
|
||||
def addbaseobject(self, obj, ss, sub=""):
|
||||
baselist = obj.Base
|
||||
if len(baselist) == 0: #When adding the first base object, guess at heights
|
||||
if len(baselist) == 0: # When adding the first base object, guess at heights
|
||||
try:
|
||||
bb = ss.Shape.BoundBox #parent boundbox
|
||||
bb = ss.Shape.BoundBox # parent boundbox
|
||||
subobj = ss.Shape.getElement(sub)
|
||||
fbb = subobj.BoundBox #feature boundbox
|
||||
fbb = subobj.BoundBox # feature boundbox
|
||||
obj.StartDepth = bb.ZMax
|
||||
obj.ClearanceHeight = bb.ZMax + 5.0
|
||||
obj.SafeHeight = bb.ZMax + 3.0
|
||||
|
@ -102,16 +103,16 @@ class ObjectRemote:
|
|||
|
||||
item = (ss, sub)
|
||||
if item in baselist:
|
||||
FreeCAD.Console.PrintWarning("this object already in the list"+ "\n")
|
||||
FreeCAD.Console.PrintWarning("this object already in the list" + "\n")
|
||||
else:
|
||||
baselist.append (item)
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state):
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
|
@ -143,54 +144,58 @@ class ObjectRemote:
|
|||
pl = obj.proplist
|
||||
pl = []
|
||||
for prop in properties:
|
||||
obj.addProperty(prop['type'], prop['propertyname'], "Remote", prop['description'])
|
||||
obj.addProperty(
|
||||
prop['type'],
|
||||
prop['propertyname'],
|
||||
"Remote",
|
||||
prop['description'])
|
||||
pl.append(prop['propertyname'])
|
||||
print "adding: " + str(prop)
|
||||
obj.proplist = pl
|
||||
|
||||
def execute(self,obj):
|
||||
def execute(self, obj):
|
||||
output = ""
|
||||
|
||||
toolLoad = PathUtils.getLastToolLoad(obj)
|
||||
if toolLoad == None:
|
||||
if toolLoad is None:
|
||||
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
|
||||
|
||||
output += "(remote gcode goes here)"
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
|
||||
|
||||
class ViewProviderRemote:
|
||||
def __init__(self,obj): #mandatory
|
||||
# obj.addProperty("App::PropertyFloat","SomePropertyName","PropertyGroup","Description of this property")
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
|
||||
def __getstate__(self): #mandatory
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state): #mandatory
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def getIcon(self): #optional
|
||||
def getIcon(self):
|
||||
return ":/icons/Path-Remote.svg"
|
||||
|
||||
def onChanged(self,obj,prop): #optional
|
||||
def onChanged(self, obj, prop):
|
||||
# this is executed when a property of the VIEW PROVIDER changes
|
||||
pass
|
||||
|
||||
def updateData(self,obj,prop): #optional
|
||||
def updateData(self, obj, prop): # optional
|
||||
# this is executed when a property of the APP OBJECT changes
|
||||
pass
|
||||
|
||||
def setEdit(self,vobj,mode=0):
|
||||
def setEdit(self, vobj, mode=0):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
taskd = TaskPanel()
|
||||
taskd.obj = vobj.Object
|
||||
|
@ -198,37 +203,37 @@ class ViewProviderRemote:
|
|||
taskd.setupUi()
|
||||
return True
|
||||
|
||||
def unsetEdit(self,vobj,mode): #optional
|
||||
def unsetEdit(self, vobj, mode):
|
||||
# this is executed when the user cancels or terminates edit mode
|
||||
pass
|
||||
|
||||
|
||||
class _RefreshRemotePath:
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Path-Refresh',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Remote","Refresh Remote Path Data"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Remote","Refresh Remote Path Data")}
|
||||
return {'Pixmap': 'Path-Refresh',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Refresh Remote Path Data"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Refresh Remote Path Data")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
def refresh(self):
|
||||
obj=FreeCADGui.Selection.getSelection()[0]
|
||||
obj = FreeCADGui.Selection.getSelection()[0]
|
||||
values = {}
|
||||
|
||||
for i in obj.PropertiesList:
|
||||
if obj.getGroupOfProperty(i) in ["Remote"]:
|
||||
values.update({i : obj.getPropertyByName(i)})
|
||||
values.update({i: obj.getPropertyByName(i)})
|
||||
|
||||
if obj.getGroupOfProperty(i) in ["Depth"]:
|
||||
print str(i)
|
||||
values.update({i : obj.getPropertyByName(i)})
|
||||
values.update({i: obj.getPropertyByName(i)})
|
||||
|
||||
if obj.getGroupOfProperty(i) in ["Step"]:
|
||||
values.update({i : obj.getPropertyByName(i)})
|
||||
|
||||
values.update({i: obj.getPropertyByName(i)})
|
||||
|
||||
if obj.getGroupOfProperty(i) in ["Tool"]:
|
||||
tool = PathUtils.getTool(obj,obj.ToolNumber)
|
||||
tool = PathUtils.getTool(obj, obj.ToolNumber)
|
||||
if tool:
|
||||
tradius = tool.Diameter/2
|
||||
tlength = tool.LengthOffset
|
||||
|
@ -238,10 +243,9 @@ class _RefreshRemotePath:
|
|||
tlength = 1
|
||||
ttype = "undefined"
|
||||
|
||||
values.update({"tool_diameter" : tradius})
|
||||
values.update({"tool_length" : tlength})
|
||||
values.update({"tool_type" : ttype})
|
||||
|
||||
values.update({"tool_diameter": tradius})
|
||||
values.update({"tool_length": tlength})
|
||||
values.update({"tool_type": ttype})
|
||||
|
||||
payload = json.dumps(values)
|
||||
|
||||
|
@ -256,7 +260,6 @@ class _RefreshRemotePath:
|
|||
print "service not defined or not responding"
|
||||
return
|
||||
|
||||
|
||||
path = data['path']
|
||||
output = ""
|
||||
for command in path:
|
||||
|
@ -264,33 +267,31 @@ class _RefreshRemotePath:
|
|||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
|
||||
|
||||
def Activated(self):
|
||||
self.refresh()
|
||||
|
||||
|
||||
class CommandPathRemote:
|
||||
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Path-Remote',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Remote","Remote"),
|
||||
return {'Pixmap': 'Path-Remote',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Remote"),
|
||||
'Accel': "P, R",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Remote","Request a Path from a remote cloud service")}
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Request a Path from a remote cloud service")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
def Activated(self):
|
||||
ztop = 10.0
|
||||
zbottom = 0.0
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_Remote","Create remote path operation"))
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_Remote", "Create remote path operation"))
|
||||
FreeCADGui.addModule("PathScripts.PathRemote")
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Remote")')
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Remote")')
|
||||
FreeCADGui.doCommand('PathScripts.PathRemote.ObjectRemote(obj)')
|
||||
FreeCADGui.doCommand('obj.Active = True')
|
||||
FreeCADGui.doCommand('PathScripts.PathRemote.ViewProviderRemote(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))
|
||||
|
@ -304,9 +305,9 @@ class CommandPathRemote:
|
|||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
|
||||
|
||||
|
||||
class TaskPanel:
|
||||
def __init__(self):
|
||||
#self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/RemoteEdit.ui")
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/RemoteEdit.ui")
|
||||
|
||||
def accept(self):
|
||||
|
@ -327,41 +328,31 @@ class TaskPanel:
|
|||
self.obj.URL = self.form.remoteURL.text()
|
||||
print "getRemote:320"
|
||||
|
||||
#self.form.label_a = QtGui.QLabel(self.form.remoteProperties)
|
||||
#self.form.label_a.setObjectName("label_a")
|
||||
#self.form.formLayoutREMOTE.setWidget(0, QtGui.QFormLayout.LabelRole, self.form.label_a)
|
||||
#self.form.sampleLE = QtGui.QLineEdit(self.form.remoteProperties)
|
||||
#self.form.sampleLE.setObjectName("sampleLE")
|
||||
#self.form.formLayoutREMOTE.setWidget(0, QtGui.QFormLayout.FieldRole, self.form.sampleLE)
|
||||
##self.formLayout_2.setWidget(1, QtGui.QFormLayout.SpanningRole, self.remoteProperties)
|
||||
|
||||
|
||||
def getFields(self):
|
||||
if self.obj:
|
||||
if hasattr(self.obj,"StartDepth"):
|
||||
if hasattr(self.obj, "StartDepth"):
|
||||
self.obj.StartDepth = float(self.form.startDepth.text())
|
||||
if hasattr(self.obj,"FinalDepth"):
|
||||
if hasattr(self.obj, "FinalDepth"):
|
||||
self.obj.FinalDepth = float(self.form.finalDepth.text())
|
||||
if hasattr(self.obj,"SafeHeight"):
|
||||
if hasattr(self.obj, "SafeHeight"):
|
||||
self.obj.SafeHeight = float(self.form.safeHeight.text())
|
||||
if hasattr(self.obj,"ClearanceHeight"):
|
||||
if hasattr(self.obj, "ClearanceHeight"):
|
||||
self.obj.ClearanceHeight = float(self.form.clearanceHeight.text())
|
||||
if hasattr(self.obj,"StepDown"):
|
||||
if hasattr(self.obj, "StepDown"):
|
||||
self.obj.StepDown = float(self.form.stepDown.value())
|
||||
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def open(self):
|
||||
self.s =SelObserver()
|
||||
# install the function mode resident
|
||||
self.s = SelObserver()
|
||||
FreeCADGui.Selection.addObserver(self.s)
|
||||
|
||||
def addBase(self):
|
||||
# check that the selection contains exactly what we want
|
||||
# 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 suitable object\n"))
|
||||
FreeCAD.Console.PrintError(translate("PathProject", "Please select at least one suitable object\n"))
|
||||
return
|
||||
for s in selection:
|
||||
if s.HasSubObjects:
|
||||
|
@ -370,7 +361,7 @@ class TaskPanel:
|
|||
else:
|
||||
self.obj.Proxy.addbaseobject(self.obj, s.Object)
|
||||
|
||||
self.setupUi() #defaults may have changed. Reload.
|
||||
self.setupUi() # defaults may have changed. Reload.
|
||||
self.form.baseList.clear()
|
||||
for i in self.obj.Base:
|
||||
self.form.baseList.addItem(i[0].Name + "." + i[1])
|
||||
|
@ -381,7 +372,7 @@ class TaskPanel:
|
|||
newlist = []
|
||||
for i in self.obj.Base:
|
||||
if not i[0].Name == d.text():
|
||||
newlist.append (i)
|
||||
newlist.append(i)
|
||||
self.obj.Base = newlist
|
||||
self.form.baseList.takeItem(self.form.baseList.row(d))
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
@ -398,10 +389,10 @@ class TaskPanel:
|
|||
def reorderBase(self):
|
||||
newlist = []
|
||||
for i in range(self.form.baseList.count()):
|
||||
s = self.form.baseList.item(i).text()
|
||||
s = self.form.baseList.item(i).text()
|
||||
obj = FreeCAD.ActiveDocument.getObject(s)
|
||||
newlist.append(obj)
|
||||
self.obj.Base=newlist
|
||||
self.obj.Base = newlist
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
@ -411,16 +402,15 @@ class TaskPanel:
|
|||
def changeURL(self):
|
||||
from urlparse import urlparse
|
||||
t = self.form.remoteURL.text()
|
||||
if t == '' and self.obj.URL != '': #if the url was deleted, cleanup.
|
||||
if t == '' and self.obj.URL != '': # if the url was deleted, cleanup.
|
||||
self.obj.URL = ''
|
||||
|
||||
if urlparse(t).scheme != '' and t != self.obj.URL: #validate new url.
|
||||
if urlparse(t).scheme != '' and t != self.obj.URL: # validate new url.
|
||||
self.obj.URL = t
|
||||
#next make sure the property fields reflect the current attached service
|
||||
# next make sure the property fields reflect the current attached service
|
||||
for p in self.obj.proplist:
|
||||
print p
|
||||
|
||||
|
||||
def setupUi(self):
|
||||
self.form.startDepth.setText(str(self.obj.StartDepth))
|
||||
self.form.finalDepth.setText(str(self.obj.FinalDepth))
|
||||
|
@ -431,7 +421,7 @@ class TaskPanel:
|
|||
for i in self.obj.Base:
|
||||
self.form.baseList.addItem(i[0].Name)
|
||||
|
||||
#Connect Signals and Slots
|
||||
# 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)
|
||||
|
@ -443,24 +433,23 @@ class TaskPanel:
|
|||
self.form.reorderBase.clicked.connect(self.reorderBase)
|
||||
|
||||
self.form.remoteURL.editingFinished.connect(self.changeURL)
|
||||
#self.form.remoteURL.returnPressed.connect(self.testOne)
|
||||
|
||||
|
||||
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 +')')
|
||||
def addSelection(self, doc, obj, sub, pnt):
|
||||
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Remote',CommandPathRemote())
|
||||
FreeCADGui.addCommand('Refresh_Path',_RefreshRemotePath())
|
||||
FreeCADGui.addCommand('Path_Remote', CommandPathRemote())
|
||||
FreeCADGui.addCommand('Refresh_Path', _RefreshRemotePath())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathRemote... done\n")
|
||||
|
|
|
@ -125,6 +125,11 @@ class PROFILEGate:
|
|||
|
||||
elif obj.ShapeType == 'Compound':
|
||||
profileable = True
|
||||
if sub[0:4] == 'Face':
|
||||
profileable = True
|
||||
|
||||
if sub[0:4] == 'Edge':
|
||||
profileable = True
|
||||
|
||||
elif obj.ShapeType == 'Face':
|
||||
profileable = True
|
||||
|
|
|
@ -1,65 +1,61 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2014 Dan Falck <ddfalck@gmail.com> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2014 Dan Falck <ddfalck@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
'''PathUtils -common functions used in PathScripts for filterig, sorting, and generating gcode toolpath data '''
|
||||
import FreeCAD
|
||||
import Part
|
||||
from FreeCAD import Vector
|
||||
import FreeCADGui
|
||||
import math
|
||||
import DraftGeomUtils
|
||||
from DraftGeomUtils import geomType
|
||||
import DraftVecUtils
|
||||
import PathScripts
|
||||
from PathScripts import PathProject
|
||||
|
||||
|
||||
|
||||
def cleanedges(splines,precision):
|
||||
def cleanedges(splines, precision):
|
||||
'''cleanedges([splines],precision). Convert BSpline curves, Beziers, to arcs that can be used for cnc paths.
|
||||
Returns Lines as is. Filters Circle and Arcs for over 180 degrees. Discretizes Ellipses. Ignores other geometry. '''
|
||||
edges = []
|
||||
for spline in splines:
|
||||
if geomType(spline)=="BSplineCurve":
|
||||
if geomType(spline) == "BSplineCurve":
|
||||
arcs = spline.Curve.toBiArcs(precision)
|
||||
for i in arcs:
|
||||
edges.append(Part.Edge(i))
|
||||
|
||||
elif geomType(spline)=="BezierCurve":
|
||||
newspline=spline.Curve.toBSpline()
|
||||
elif geomType(spline) == "BezierCurve":
|
||||
newspline = spline.Curve.toBSpline()
|
||||
arcs = newspline.toBiArcs(precision)
|
||||
for i in arcs:
|
||||
edges.append(Part.Edge(i))
|
||||
|
||||
elif geomType(spline)=="Ellipse":
|
||||
edges = curvetowire(spline, 1.0) #fixme hardcoded value
|
||||
elif geomType(spline) == "Ellipse":
|
||||
edges = curvetowire(spline, 1.0) # fixme hardcoded value
|
||||
|
||||
elif geomType(spline)=="Circle":
|
||||
arcs=filterArcs(spline)
|
||||
elif geomType(spline) == "Circle":
|
||||
arcs = filterArcs(spline)
|
||||
for i in arcs:
|
||||
edges.append(Part.Edge(i))
|
||||
|
||||
elif geomType(spline)=="Line":
|
||||
elif geomType(spline) == "Line":
|
||||
edges.append(spline)
|
||||
|
||||
else:
|
||||
|
@ -67,71 +63,80 @@ def cleanedges(splines,precision):
|
|||
|
||||
return edges
|
||||
|
||||
def curvetowire(obj,steps):
|
||||
|
||||
def curvetowire(obj, steps):
|
||||
'''adapted from DraftGeomUtils, because the discretize function changed a bit '''
|
||||
points = obj.copy().discretize(Distance = eval('steps'))
|
||||
points = obj.copy().discretize(Distance=eval('steps'))
|
||||
p0 = points[0]
|
||||
edgelist = []
|
||||
for p in points[1:]:
|
||||
edge = Part.makeLine((p0.x,p0.y,p0.z),(p.x,p.y,p.z))
|
||||
edge = Part.makeLine((p0.x, p0.y, p0.z), (p.x, p.y, p.z))
|
||||
edgelist.append(edge)
|
||||
p0 = p
|
||||
return edgelist
|
||||
|
||||
def fmt(val): return format(val, '.4f') #fixme set at 4 decimal places for testing
|
||||
|
||||
def isSameEdge(e1,e2):
|
||||
# fixme set at 4 decimal places for testing
|
||||
def fmt(val): return format(val, '.4f')
|
||||
|
||||
|
||||
def isSameEdge(e1, e2):
|
||||
"""isSameEdge(e1,e2): return True if the 2 edges are both lines or arcs/circles and have the same
|
||||
points - inspired by Yorik's function isSameLine"""
|
||||
if not (isinstance(e1.Curve,Part.Line) or isinstance(e1.Curve,Part.Circle)):
|
||||
if not (isinstance(e1.Curve, Part.Line) or isinstance(e1.Curve, Part.Circle)):
|
||||
return False
|
||||
if not (isinstance(e2.Curve,Part.Line) or isinstance(e2.Curve,Part.Circle)):
|
||||
if not (isinstance(e2.Curve, Part.Line) or isinstance(e2.Curve, Part.Circle)):
|
||||
return False
|
||||
if type(e1.Curve) <> type(e2.Curve):
|
||||
if type(e1.Curve) != type(e2.Curve):
|
||||
return False
|
||||
if isinstance(e1.Curve,Part.Line):
|
||||
if (DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point)):
|
||||
if isinstance(e1.Curve, Part.Line):
|
||||
if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)):
|
||||
return True
|
||||
elif (DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point)):
|
||||
elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)):
|
||||
return True
|
||||
if isinstance(e1.Curve,Part.Circle):
|
||||
center = False; radius= False; endpts=False
|
||||
if isinstance(e1.Curve, Part.Circle):
|
||||
center = False
|
||||
radius = False
|
||||
endpts = False
|
||||
if e1.Curve.Center == e2.Curve.Center:
|
||||
center = True
|
||||
if e1.Curve.Radius == e2.Curve.Radius:
|
||||
radius = True
|
||||
if (DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point)):
|
||||
if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)):
|
||||
endpts = True
|
||||
elif (DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point)):
|
||||
elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)):
|
||||
endpts = True
|
||||
if (center and radius and endpts):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def segments(poly):
|
||||
''' A sequence of (x,y) numeric coordinates pairs '''
|
||||
return zip(poly, poly[1:] + [poly[0]])
|
||||
|
||||
|
||||
def check_clockwise(poly):
|
||||
'''
|
||||
check_clockwise(poly) a function for returning a boolean if the selected wire is clockwise or counter clockwise
|
||||
based on point order. poly = [(x1,y1),(x2,y2),(x3,y3)]
|
||||
'''
|
||||
clockwise = False
|
||||
if (sum(x0*y1 - x1*y0 for ((x0, y0), (x1, y1)) in segments(poly))) < 0:
|
||||
if (sum(x0 * y1 - x1 * y0 for ((x0, y0), (x1, y1)) in segments(poly))) < 0:
|
||||
clockwise = not clockwise
|
||||
return clockwise
|
||||
|
||||
|
||||
def filterArcs(arcEdge):
|
||||
'''filterArcs(Edge) -used to split arcs that over 180 degrees. Returns list '''
|
||||
s = arcEdge
|
||||
if isinstance(s.Curve,Part.Circle):
|
||||
splitlist =[]
|
||||
angle = abs(s.LastParameter-s.FirstParameter)
|
||||
if isinstance(s.Curve, Part.Circle):
|
||||
splitlist = []
|
||||
angle = abs(s.LastParameter - s.FirstParameter)
|
||||
overhalfcircle = False
|
||||
goodarc = False
|
||||
if (angle > math.pi):
|
||||
|
@ -139,14 +144,17 @@ def filterArcs(arcEdge):
|
|||
else:
|
||||
goodarc = True
|
||||
if not goodarc:
|
||||
arcstpt = s.valueAt(s.FirstParameter)
|
||||
arcmid = s.valueAt((s.LastParameter-s.FirstParameter)*0.5+s.FirstParameter)
|
||||
arcquad1 = s.valueAt((s.LastParameter-s.FirstParameter)*0.25+s.FirstParameter)#future midpt for arc1
|
||||
arcquad2 = s.valueAt((s.LastParameter-s.FirstParameter)*0.75+s.FirstParameter) #future midpt for arc2
|
||||
arcstpt = s.valueAt(s.FirstParameter)
|
||||
arcmid = s.valueAt(
|
||||
(s.LastParameter - s.FirstParameter) * 0.5 + s.FirstParameter)
|
||||
arcquad1 = s.valueAt(
|
||||
(s.LastParameter - s.FirstParameter) * 0.25 + s.FirstParameter) # future midpt for arc1
|
||||
arcquad2 = s.valueAt(
|
||||
(s.LastParameter - s.FirstParameter) * 0.75 + s.FirstParameter) # future midpt for arc2
|
||||
arcendpt = s.valueAt(s.LastParameter)
|
||||
# reconstruct with 2 arcs
|
||||
arcseg1 = Part.ArcOfCircle(arcstpt,arcquad1,arcmid)
|
||||
arcseg2 = Part.ArcOfCircle(arcmid,arcquad2,arcendpt)
|
||||
arcseg1 = Part.ArcOfCircle(arcstpt, arcquad1, arcmid)
|
||||
arcseg2 = Part.ArcOfCircle(arcmid, arcquad2, arcendpt)
|
||||
|
||||
eseg1 = arcseg1.toShape()
|
||||
eseg2 = arcseg2.toShape()
|
||||
|
@ -154,43 +162,50 @@ def filterArcs(arcEdge):
|
|||
splitlist.append(eseg2)
|
||||
else:
|
||||
splitlist.append(s)
|
||||
elif isinstance(s.Curve,Part.Line):
|
||||
elif isinstance(s.Curve, Part.Line):
|
||||
pass
|
||||
return splitlist
|
||||
|
||||
|
||||
def reverseEdge(e):
|
||||
if geomType(e) == "Circle":
|
||||
arcstpt = e.valueAt(e.FirstParameter)
|
||||
arcmid = e.valueAt((e.LastParameter-e.FirstParameter)*0.5+e.FirstParameter)
|
||||
arcstpt = e.valueAt(e.FirstParameter)
|
||||
arcmid = e.valueAt(
|
||||
(e.LastParameter - e.FirstParameter) * 0.5 + e.FirstParameter)
|
||||
arcendpt = e.valueAt(e.LastParameter)
|
||||
arcofCirc = Part.ArcOfCircle(arcendpt,arcmid,arcstpt)
|
||||
arcofCirc = Part.ArcOfCircle(arcendpt, arcmid, arcstpt)
|
||||
newedge = arcofCirc.toShape()
|
||||
elif geomType(e) == "Line":
|
||||
stpt = e.valueAt(e.FirstParameter)
|
||||
endpt = e.valueAt(e.LastParameter)
|
||||
newedge = Part.makeLine(endpt,stpt)
|
||||
newedge = Part.makeLine(endpt, stpt)
|
||||
|
||||
return newedge
|
||||
|
||||
def convert(toolpath,Side,radius,clockwise=False,Z=0.0,firstedge=None,vf=1.0,hf=2.0):
|
||||
|
||||
def convert(
|
||||
toolpath, Side, radius, clockwise=False, Z=0.0, firstedge=None,
|
||||
vf=1.0, hf=2.0):
|
||||
'''convert(toolpath,Side,radius,clockwise=False,Z=0.0,firstedge=None) Converts lines and arcs to G1,G2,G3 moves. Returns a string.'''
|
||||
last = None
|
||||
output = ""
|
||||
# create the path from the offset shape
|
||||
for edge in toolpath:
|
||||
if not last:
|
||||
#set the first point
|
||||
# set the first point
|
||||
last = edge.Vertexes[0].Point
|
||||
#FreeCAD.Console.PrintMessage("last pt= " + str(last)+ "\n")
|
||||
output += "G1 X"+str(fmt(last.x))+" Y"+str(fmt(last.y))+" Z"+str(fmt(Z))+" F"+str(vf)+"\n"
|
||||
if isinstance(edge.Curve,Part.Circle):
|
||||
#FreeCAD.Console.PrintMessage("arc\n")
|
||||
# FreeCAD.Console.PrintMessage("last pt= " + str(last)+ "\n")
|
||||
output += "G1 X" + str(fmt(last.x)) + " Y" + str(fmt(last.y)) + \
|
||||
" Z" + str(fmt(Z)) + " F" + str(vf) + "\n"
|
||||
if isinstance(edge.Curve, Part.Circle):
|
||||
# FreeCAD.Console.PrintMessage("arc\n")
|
||||
arcstartpt = edge.valueAt(edge.FirstParameter)
|
||||
midpt = edge.valueAt((edge.FirstParameter+edge.LastParameter)*0.5)
|
||||
midpt = edge.valueAt(
|
||||
(edge.FirstParameter + edge.LastParameter) * 0.5)
|
||||
arcendpt = edge.valueAt(edge.LastParameter)
|
||||
arcchkpt=edge.valueAt(edge.LastParameter*.99)
|
||||
# arcchkpt = edge.valueAt(edge.LastParameter * .99)
|
||||
|
||||
if DraftVecUtils.equals(last,arcstartpt):
|
||||
if DraftVecUtils.equals(last, arcstartpt):
|
||||
startpt = arcstartpt
|
||||
endpt = arcendpt
|
||||
else:
|
||||
|
@ -198,54 +213,59 @@ def convert(toolpath,Side,radius,clockwise=False,Z=0.0,firstedge=None,vf=1.0,hf=
|
|||
endpt = arcstartpt
|
||||
center = edge.Curve.Center
|
||||
relcenter = center.sub(last)
|
||||
#FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n")
|
||||
#FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n")
|
||||
#FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n")
|
||||
arc_cw = check_clockwise([(startpt.x,startpt.y),(midpt.x,midpt.y),(endpt.x,endpt.y)])
|
||||
#FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n")
|
||||
# FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n")
|
||||
# FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n")
|
||||
# FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n")
|
||||
arc_cw = check_clockwise(
|
||||
[(startpt.x, startpt.y), (midpt.x, midpt.y), (endpt.x, endpt.y)])
|
||||
# FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n")
|
||||
if arc_cw:
|
||||
output += "G2"
|
||||
else:
|
||||
output += "G3"
|
||||
output += " X"+str(fmt(endpt.x))+" Y"+str(fmt(endpt.y))+" Z"+str(fmt(Z))+" F"+str(hf)
|
||||
output += " I" + str(fmt(relcenter.x)) + " J" + str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z))
|
||||
output += " X" + str(fmt(endpt.x)) + " Y" + \
|
||||
str(fmt(endpt.y)) + " Z" + str(fmt(Z)) + " F" + str(hf)
|
||||
output += " I" + str(fmt(relcenter.x)) + " J" + \
|
||||
str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z))
|
||||
output += "\n"
|
||||
last = endpt
|
||||
#FreeCAD.Console.PrintMessage("last pt arc= " + str(last)+ "\n")
|
||||
# FreeCAD.Console.PrintMessage("last pt arc= " + str(last)+ "\n")
|
||||
else:
|
||||
point = edge.Vertexes[-1].Point
|
||||
if DraftVecUtils.equals(point , last): # edges can come flipped
|
||||
if DraftVecUtils.equals(point, last): # edges can come flipped
|
||||
point = edge.Vertexes[0].Point
|
||||
output += "G1 X"+str(fmt(point.x))+" Y"+str(fmt(point.y))+" Z"+str(fmt(Z))+" F"+str(hf)+"\n"
|
||||
output += "G1 X" + str(fmt(point.x)) + " Y" + str(fmt(point.y)) + \
|
||||
" Z" + str(fmt(Z)) + " F" + str(hf) + "\n"
|
||||
last = point
|
||||
#FreeCAD.Console.PrintMessage("line\n")
|
||||
#FreeCAD.Console.PrintMessage("last pt line= " + str(last)+ "\n")
|
||||
# FreeCAD.Console.PrintMessage("line\n")
|
||||
# FreeCAD.Console.PrintMessage("last pt line= " + str(last)+ "\n")
|
||||
return output
|
||||
|
||||
def SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5):
|
||||
|
||||
def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5):
|
||||
'''SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5) Sorts the wire and reverses it, if needed. Splits arcs over 180 degrees in two. Returns the reordered offset of the wire. '''
|
||||
if firstedge:
|
||||
edgelist = wire.Edges[:]
|
||||
if wire.isClosed():
|
||||
elindex = None
|
||||
n=0
|
||||
n = 0
|
||||
for e in edgelist:
|
||||
if isSameEdge(e,firstedge):
|
||||
# FreeCAD.Console.PrintMessage('found first edge\n')
|
||||
if isSameEdge(e, firstedge):
|
||||
# FreeCAD.Console.PrintMessage('found first edge\n')
|
||||
elindex = n
|
||||
n=n+1
|
||||
n = n + 1
|
||||
l1 = edgelist[:elindex]
|
||||
l2 = edgelist[elindex:]
|
||||
newedgelist = l2+l1
|
||||
newedgelist = l2 + l1
|
||||
|
||||
if clockwise:
|
||||
newedgelist.reverse()
|
||||
last = newedgelist.pop(-1)
|
||||
newedgelist.insert(0, last)
|
||||
|
||||
preoffset= []
|
||||
preoffset = []
|
||||
for e in newedgelist:
|
||||
if clockwise:
|
||||
if clockwise:
|
||||
r = reverseEdge(e)
|
||||
preoffset.append(r)
|
||||
else:
|
||||
|
@ -266,16 +286,16 @@ def SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5):
|
|||
elif geomType(e) == "Line":
|
||||
edgelist.append(e)
|
||||
elif geomType(e) == "BSplineCurve" or \
|
||||
geomType(e) == "BezierCurve" or \
|
||||
geomType(e) == "Ellipse":
|
||||
edgelist.append(Part.Wire(curvetowire(e,(SegLen))))
|
||||
geomType(e) == "BezierCurve" or \
|
||||
geomType(e) == "Ellipse":
|
||||
edgelist.append(Part.Wire(curvetowire(e, (SegLen))))
|
||||
|
||||
newwire = Part.Wire(edgelist)
|
||||
if Side == 'Left':
|
||||
# we use the OCC offset feature
|
||||
offset = newwire.makeOffset(radius)#tool is outside line
|
||||
# we use the OCC offset feature
|
||||
offset = newwire.makeOffset(radius) # tool is outside line
|
||||
elif Side == 'Right':
|
||||
offset = newwire.makeOffset(-radius)#tool is inside line
|
||||
offset = newwire.makeOffset(-radius) # tool is inside line
|
||||
else:
|
||||
if wire.isClosed():
|
||||
offset = newwire.makeOffset(0.0)
|
||||
|
@ -284,48 +304,57 @@ def SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5):
|
|||
|
||||
return offset
|
||||
|
||||
def MakePath(wire,Side,radius,clockwise,ZClearance,StepDown,ZStart,ZFinalDepth,firstedge=None,PathClosed=True,SegLen =0.5,VertFeed=1.0,HorizFeed=2.0):
|
||||
|
||||
def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart, ZFinalDepth, firstedge=None, PathClosed=True, SegLen=0.5, VertFeed=1.0, HorizFeed=2.0):
|
||||
''' makes the path - just a simple profile for now '''
|
||||
offset = SortPath(wire,Side,radius,clockwise,firstedge,SegLen=0.5)
|
||||
offset = SortPath(wire, Side, radius, clockwise, firstedge, SegLen=0.5)
|
||||
toolpath = offset.Edges[:]
|
||||
paths = ""
|
||||
paths += "G0 Z" + str(ZClearance)+"\n"
|
||||
paths += "G0 Z" + str(ZClearance) + "\n"
|
||||
first = toolpath[0].Vertexes[0].Point
|
||||
paths += "G0 X"+str(fmt(first.x))+"Y"+str(fmt(first.y))+"\n"
|
||||
ZCurrent = ZStart- StepDown
|
||||
paths += "G0 X" + str(fmt(first.x)) + "Y" + str(fmt(first.y)) + "\n"
|
||||
ZCurrent = ZStart - StepDown
|
||||
if PathClosed:
|
||||
while ZCurrent > ZFinalDepth:
|
||||
paths += convert(toolpath,Side,radius,clockwise,ZCurrent,firstedge,VertFeed,HorizFeed)
|
||||
ZCurrent = ZCurrent-abs(StepDown)
|
||||
paths += convert(toolpath,Side,radius,clockwise,ZFinalDepth,firstedge,VertFeed,HorizFeed)
|
||||
paths += convert(toolpath, Side, radius, clockwise,
|
||||
ZCurrent, firstedge, VertFeed, HorizFeed)
|
||||
ZCurrent = ZCurrent - abs(StepDown)
|
||||
paths += convert(toolpath, Side, radius, clockwise,
|
||||
ZFinalDepth, firstedge, VertFeed, HorizFeed)
|
||||
paths += "G0 Z" + str(ZClearance)
|
||||
else:
|
||||
while ZCurrent > ZFinalDepth:
|
||||
paths += convert(toolpath,Side,radius,clockwise,ZCurrent,firstedge,VertFeed,HorizFeed)
|
||||
paths += convert(toolpath, Side, radius, clockwise,
|
||||
ZCurrent, firstedge, VertFeed, HorizFeed)
|
||||
paths += "G0 Z" + str(ZClearance)
|
||||
paths += "G0 X"+str(fmt(first.x))+"Y"+str(fmt(first.y))+"\n"
|
||||
ZCurrent = ZCurrent-abs(StepDown)
|
||||
paths += convert(toolpath,Side,radius,clockwise,ZFinalDepth,firstedge,VertFeed,HorizFeed)
|
||||
paths += "G0 X" + str(fmt(first.x)) + "Y" + \
|
||||
str(fmt(first.y)) + "\n"
|
||||
ZCurrent = ZCurrent - abs(StepDown)
|
||||
paths += convert(toolpath, Side, radius, clockwise,
|
||||
ZFinalDepth, firstedge, VertFeed, HorizFeed)
|
||||
paths += "G0 Z" + str(ZClearance)
|
||||
return paths
|
||||
|
||||
# the next two functions are for automatically populating tool numbers/height offset numbers based on previously active toolnumbers
|
||||
# the next two functions are for automatically populating tool
|
||||
# numbers/height offset numbers based on previously active toolnumbers
|
||||
|
||||
def changeTool(obj,proj):
|
||||
|
||||
def changeTool(obj, proj):
|
||||
tlnum = 0
|
||||
for p in proj.Group:
|
||||
if not hasattr(p,"Group"):
|
||||
if isinstance(p.Proxy,PathScripts.PathLoadTool.LoadTool) and p.ToolNumber > 0:
|
||||
if not hasattr(p, "Group"):
|
||||
if isinstance(p.Proxy, PathScripts.PathLoadTool.LoadTool) and p.ToolNumber > 0:
|
||||
tlnum = p.ToolNumber
|
||||
if p == obj:
|
||||
return tlnum
|
||||
elif hasattr(p,"Group"):
|
||||
elif hasattr(p, "Group"):
|
||||
for g in p.Group:
|
||||
if isinstance(g.Proxy,PathScripts.PathLoadTool.LoadTool):
|
||||
if isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool):
|
||||
tlnum = g.ToolNumber
|
||||
if g == obj:
|
||||
return tlnum
|
||||
|
||||
|
||||
def getLastTool(obj):
|
||||
toolNum = obj.ToolNumber
|
||||
if obj.ToolNumber == 0:
|
||||
|
@ -334,11 +363,13 @@ 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.
|
||||
# This walks up the hierarchy and tries to find the closest preceding
|
||||
# ToolLoadOject (tlo).
|
||||
|
||||
import PathScripts
|
||||
tc = None
|
||||
tlo = None
|
||||
lastfound = None
|
||||
|
||||
try:
|
||||
|
@ -347,42 +378,43 @@ def getLastToolLoad(obj):
|
|||
except:
|
||||
parent = None
|
||||
|
||||
while parent != None:
|
||||
|
||||
while parent is not None:
|
||||
sibs = parent.Group
|
||||
for g in sibs:
|
||||
if isinstance(g.Proxy,PathScripts.PathLoadTool.LoadTool):
|
||||
if isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool):
|
||||
lastfound = g
|
||||
if g == child:
|
||||
tc = lastfound
|
||||
tlo = lastfound
|
||||
|
||||
if tc == None:
|
||||
if tlo is None:
|
||||
try:
|
||||
child = parent
|
||||
parent = parent.InList[0]
|
||||
parent = child.InList[0]
|
||||
except:
|
||||
parent = None
|
||||
else:
|
||||
return tc
|
||||
return tlo
|
||||
|
||||
if tc == None:
|
||||
for g in FreeCAD.ActiveDocument.Objects: #top level object
|
||||
if isinstance(g.Proxy,PathScripts.PathLoadTool.LoadTool):
|
||||
lastfound = g
|
||||
if tlo is None:
|
||||
for g in FreeCAD.ActiveDocument.Objects: # Look in top level
|
||||
if hasattr(g, "Proxy"):
|
||||
if isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool):
|
||||
lastfound = g
|
||||
if g == obj:
|
||||
tc = lastfound
|
||||
return tc
|
||||
tlo = lastfound
|
||||
return tlo
|
||||
|
||||
def getTool(obj,number=0):
|
||||
|
||||
def getTool(obj, number=0):
|
||||
"retrieves a tool from a hosting object with a tooltable, if any"
|
||||
for o in obj.InList:
|
||||
if o.TypeId == "Path::FeatureCompoundPython":
|
||||
for m in o.Group:
|
||||
if hasattr(m,"Tooltable"):
|
||||
if hasattr(m, "Tooltable"):
|
||||
return m.Tooltable.getTool(number)
|
||||
# not found? search one level up
|
||||
for o in obj.InList:
|
||||
return getTool(o,number)
|
||||
return getTool(o, number)
|
||||
return None
|
||||
|
||||
|
||||
|
@ -392,6 +424,7 @@ def findProj():
|
|||
if isinstance(o.Proxy, PathProject.ObjectPathProject):
|
||||
return o
|
||||
|
||||
|
||||
def findMachine():
|
||||
'''find machine object for the tooltable editor '''
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
|
@ -399,10 +432,11 @@ def findMachine():
|
|||
if isinstance(o.Proxy, PathScripts.PathMachine.Machine):
|
||||
return o
|
||||
|
||||
|
||||
def addToProject(obj):
|
||||
"""Adds a path obj to this document, if no PathParoject exists it's created on the fly"""
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
|
||||
if p.GetBool("pathAutoProject",True):
|
||||
if p.GetBool("pathAutoProject", True):
|
||||
project = findProj()
|
||||
if not project:
|
||||
project = PathProject.CommandProject.Create()
|
||||
|
@ -420,9 +454,10 @@ def getLastZ(obj):
|
|||
for c in g.Path.Commands:
|
||||
for n in c.Parameters:
|
||||
if n == 'Z':
|
||||
lastZ= c.Parameters['Z']
|
||||
lastZ = c.Parameters['Z']
|
||||
return lastZ
|
||||
|
||||
|
||||
def frange(start, stop, step, finish):
|
||||
x = []
|
||||
curdepth = start
|
||||
|
@ -435,7 +470,8 @@ def frange(start, stop, step, finish):
|
|||
curdepth = stop + finish
|
||||
x.append(curdepth)
|
||||
|
||||
# we might have to do a last pass or else finish round might be too far away
|
||||
# we might have to do a last pass or else finish round might be too far
|
||||
# away
|
||||
if curdepth - stop > finish:
|
||||
x.append(stop + finish)
|
||||
|
||||
|
@ -444,10 +480,182 @@ def frange(start, stop, step, finish):
|
|||
curdepth = stop
|
||||
x.append(curdepth)
|
||||
|
||||
|
||||
return x
|
||||
|
||||
def rapid(x=None, y=None, z=None):
|
||||
""" Returns gcode string to perform a rapid move."""
|
||||
retstr = "G00"
|
||||
if (x is not None) or (y is not None) or (z is not None):
|
||||
if (x is not None):
|
||||
retstr += " X" + str("%.4f" % x)
|
||||
if (y is not None):
|
||||
retstr += " Y" + str("%.4f" % y)
|
||||
if (z is not None):
|
||||
retstr += " Z" + str("%.4f" % z)
|
||||
else:
|
||||
return ""
|
||||
return retstr + "\n"
|
||||
|
||||
def feed(x=None, y=None, z=None, horizFeed=0, vertFeed=0):
|
||||
""" Return gcode string to perform a linear feed."""
|
||||
global feedxy
|
||||
retstr = "G01 F"
|
||||
if(x is None) and (y is None):
|
||||
retstr += str("%.4f" % horizFeed)
|
||||
else:
|
||||
retstr += str("%.4f" % vertFeed)
|
||||
|
||||
if (x is not None) or (y is not None) or (z is not None):
|
||||
if (x is not None):
|
||||
retstr += " X" + str("%.4f" % x)
|
||||
if (y is not None):
|
||||
retstr += " Y" + str("%.4f" % y)
|
||||
if (z is not None):
|
||||
retstr += " Z" + str("%.4f" % z)
|
||||
else:
|
||||
return ""
|
||||
return retstr + "\n"
|
||||
|
||||
def arc(cx, cy, sx, sy, ex, ey, horizFeed=0, ez=None, ccw=False):
|
||||
"""
|
||||
Return gcode string to perform an arc.
|
||||
|
||||
Assumes XY plane or helix around Z
|
||||
Don't worry about starting Z- assume that's dealt with elsewhere
|
||||
If start/end radii aren't within eps, abort.
|
||||
|
||||
cx, cy -- arc center coordinates
|
||||
sx, sy -- arc start coordinates
|
||||
ex, ey -- arc end coordinates
|
||||
ez -- ending Z coordinate. None unless helix.
|
||||
horizFeed -- horiz feed speed
|
||||
ccw -- arc direction
|
||||
"""
|
||||
|
||||
eps = 0.01
|
||||
if (math.sqrt((cx - sx)**2 + (cy - sy)**2) - math.sqrt((cx - ex)**2 + (cy - ey)**2)) >= eps:
|
||||
print "ERROR: Illegal arc: Start and end radii not equal"
|
||||
return ""
|
||||
|
||||
retstr = ""
|
||||
if ccw:
|
||||
retstr += "G03 F" + str(horizFeed)
|
||||
else:
|
||||
retstr += "G02 F" + str(horizFeed)
|
||||
|
||||
retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey)
|
||||
|
||||
if ez is not None:
|
||||
retstr += " Z" + str("%.4f" % ez)
|
||||
|
||||
retstr += " I" + str("%.4f" % (cx - sx)) + " J" + str("%.4f" % (cy - sy))
|
||||
|
||||
return retstr + "\n"
|
||||
|
||||
def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed):
|
||||
"""
|
||||
Return gcode string to perform helical entry move.
|
||||
|
||||
plungePos -- vector of the helical entry location
|
||||
destZ -- the lowest Z position or milling level
|
||||
startZ -- Starting Z position for helical move
|
||||
rampangle -- entry angle
|
||||
toold -- tool diameter
|
||||
plungeR -- the radius of the entry helix
|
||||
"""
|
||||
# toold = self.radius * 2
|
||||
|
||||
helixCmds = "(START HELICAL PLUNGE)\n"
|
||||
if(plungePos is None):
|
||||
raise Exception("Helical plunging requires a position!")
|
||||
return None
|
||||
|
||||
helixX = plungePos.x + toold/2 * plungeR
|
||||
helixY = plungePos.y
|
||||
|
||||
helixCirc = math.pi * toold * 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)
|
||||
done = False
|
||||
while not done:
|
||||
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 - toold * plungeR, helixY, horizFeed, ez=(curZ + lastZ)/2., ccw=True)
|
||||
helixCmds += arc(plungePos.x, plungePos.y, helixX - toold * plungeR, helixY, helixX, helixY, horizFeed, ez=curZ, ccw=True)
|
||||
lastZ = curZ
|
||||
curZ = max(curZ - dzPerRev, destZ)
|
||||
|
||||
return helixCmds
|
||||
|
||||
def rampPlunge(edge, rampangle, destZ, startZ):
|
||||
"""
|
||||
Return gcode string to linearly ramp down to milling level.
|
||||
|
||||
edge -- edge to follow
|
||||
rampangle -- entry angle
|
||||
destZ -- Final Z depth
|
||||
startZ -- Starting Z depth
|
||||
|
||||
FIXME: This ramps along the first edge, assuming it's long
|
||||
enough, NOT just wiggling back and forth by ~0.75 * toolD.
|
||||
Not sure if that's any worse, but it's simpler
|
||||
I think this should be changed to be limited to a maximum ramp size. Otherwise machine time will get longer than it needs to be.
|
||||
"""
|
||||
|
||||
rampCmds = "(START RAMP PLUNGE)\n"
|
||||
if(edge is None):
|
||||
raise Exception("Ramp plunging requires an edge!")
|
||||
return None
|
||||
|
||||
sPoint = edge.Vertexes[0].Point
|
||||
ePoint = edge.Vertexes[1].Point
|
||||
# Evidently edges can get flipped- pick the right one in this case
|
||||
# FIXME: This is iffy code, based on what already existed in the "for vpos ..." loop below
|
||||
if ePoint == sPoint:
|
||||
# print "FLIP"
|
||||
ePoint = edge.Vertexes[-1].Point
|
||||
|
||||
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
|
||||
|
||||
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 Exception("rampPlunge: Screw it, not handling an arc.")
|
||||
# Straight feed! Easy!
|
||||
else:
|
||||
rampCmds += feed(ePoint.x, ePoint.y, curZ)
|
||||
rampCmds += feed(sPoint.x, sPoint.y)
|
||||
|
||||
curZ = max(curZ - rampDZ, destZ)
|
||||
|
||||
return rampCmds
|
||||
|
||||
|
||||
|
||||
class depth_params:
|
||||
|
||||
def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, user_depths=None):
|
||||
self.clearance_height = clearance_height
|
||||
self.rapid_safety_space = math.fabs(rapid_safety_space)
|
||||
|
@ -459,17 +667,19 @@ class depth_params:
|
|||
|
||||
def get_depths(self):
|
||||
depths = []
|
||||
if self.user_depths != None:
|
||||
if self.user_depths is not None:
|
||||
depths = self.user_depths
|
||||
else:
|
||||
depth = self.final_depth
|
||||
depths = [depth]
|
||||
depth += self.z_finish_depth
|
||||
if depth + 0.0000001 < self.start_depth:
|
||||
if self.z_finish_depth > 0.0000001: depths.insert(0, depth)
|
||||
layer_count = int((self.start_depth - depth) / self.step_down - 0.0000001) + 1
|
||||
if self.z_finish_depth > 0.0000001:
|
||||
depths.insert(0, depth)
|
||||
layer_count = int((self.start_depth - depth) /
|
||||
self.step_down - 0.0000001) + 1
|
||||
if layer_count > 0:
|
||||
layer_depth = (self.start_depth - depth)/layer_count
|
||||
layer_depth = (self.start_depth - depth) / layer_count
|
||||
for i in range(1, layer_count):
|
||||
depth += layer_depth
|
||||
depths.append(depth)
|
||||
|
|
Loading…
Reference in New Issue
Block a user