OCC pocket handles large curves better now. Needs testing

initial commit
This commit is contained in:
sliptonic 2016-05-14 14:01:58 -05:00 committed by Yorik van Havre
parent be03c2ad26
commit a0f332feb0
10 changed files with 333 additions and 200 deletions

View File

@ -1,31 +1,32 @@
#***************************************************************************
#* (c) Yorik van Havre (yorik@uncreated.net) 2014 *
#* *
#* This file is part of the FreeCAD CAx development system. *
#* *
#* 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. *
#* *
#* FreeCAD 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 Lesser General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with FreeCAD; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************/
# ***************************************************************************
# * (c) Yorik van Havre (yorik@uncreated.net) 2014 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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. *
# * *
# * FreeCAD 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 Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with FreeCAD; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************/
class PathWorkbench ( Workbench ):
class PathWorkbench (Workbench):
"Path workbench"
def __init__(self):
self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/Path/Resources/icons/PathWorkbench.svg"
self.__class__.Icon = FreeCAD.getResourceDir(
) + "Mod/Path/Resources/icons/PathWorkbench.svg"
self.__class__.MenuText = "Path"
self.__class__.ToolTip = "Path workbench"
@ -65,59 +66,73 @@ class PathWorkbench ( Workbench ):
from PathScripts import PathEngrave
from PathScripts import PathSurface
from PathScripts import PathRemote
from PathScripts import PathSanity
# build commands list
projcmdlist = ["Path_Project", "Path_ToolTableEdit","Path_Post","Path_Inspect"]
prepcmdlist = ["Path_Plane","Path_Fixture","Path_LoadTool","Path_ToolLenOffset","Path_Comment","Path_Stop","Path_FaceProfile","Path_FacePocket","Path_Custom","Path_FromShape"]
opcmdlist = ["Path_Profile","Path_Pocket","Path_Drilling","Path_Engrave","Path_Surfacing"]
modcmdlist = ["Path_Copy","Path_CompoundExtended","Path_Dressup","Path_Hop","Path_Array","Path_SimpleCopy"]
projcmdlist = ["Path_Project", "Path_ToolTableEdit",
"Path_Post", "Path_Inspect", "Path_Sanity"]
prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_LoadTool", "Path_ToolLenOffset", "Path_Comment",
"Path_Stop", "Path_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_FromShape"]
opcmdlist = ["Path_Profile", "Path_Pocket",
"Path_Drilling", "Path_Engrave", "Path_Surfacing"]
modcmdlist = ["Path_Copy", "Path_CompoundExtended",
"Path_Dressup", "Path_Hop", "Path_Array", "Path_SimpleCopy"]
remotecmdlist = ["Path_Remote"]
# Add commands to menu and toolbar
def QT_TRANSLATE_NOOP(scope, text):
def QT_TRANSLATE_NOOP(scope, text):
return text
def translate(context,text):
return QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8).encode("utf8")
self.appendToolbar(translate("Path","Project Setup"),projcmdlist)
self.appendToolbar(translate("Path","Partial Commands"),prepcmdlist)
self.appendToolbar(translate("Path","New Operations"),opcmdlist)
self.appendToolbar(translate("Path","Path Modification"),modcmdlist)
self.appendMenu([translate("Path","Path"),translate("Path","Project Setup")],projcmdlist)
self.appendMenu([translate("Path","Path"),translate("Path","Partial Commands")],prepcmdlist)
self.appendMenu([translate("Path","Path"),translate("Path","New Operations")],opcmdlist)
self.appendMenu([translate("Path","Path"),translate("Path","Path Modification")],modcmdlist)
self.appendMenu([translate("Path","Path"),translate("Path","Remote Operations")],remotecmdlist)
def translate(context, text):
return QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8).encode("utf8")
self.appendToolbar(translate("Path", "Project Setup"), projcmdlist)
self.appendToolbar(translate("Path", "Partial Commands"), prepcmdlist)
self.appendToolbar(translate("Path", "New Operations"), opcmdlist)
self.appendToolbar(translate("Path", "Path Modification"), modcmdlist)
self.appendMenu([translate("Path", "Path"), translate(
"Path", "Project Setup")], projcmdlist)
self.appendMenu([translate("Path", "Path"), translate(
"Path", "Partial Commands")], prepcmdlist)
self.appendMenu([translate("Path", "Path"), translate(
"Path", "New Operations")], opcmdlist)
self.appendMenu([translate("Path", "Path"), translate(
"Path", "Path Modification")], modcmdlist)
self.appendMenu([translate("Path", "Path"), translate(
"Path", "Remote Operations")], remotecmdlist)
# Add preferences pages
import os
FreeCADGui.addPreferencePage(FreeCAD.getHomePath()+os.sep+"Mod"+os.sep+"Path"+os.sep+"PathScripts"+os.sep+"DlgSettingsPath.ui","Path")
Log ('Loading Path workbench... done\n')
FreeCADGui.addPreferencePage(FreeCAD.getHomePath(
) + os.sep + "Mod" + os.sep + "Path" + os.sep + "PathScripts" + os.sep + "DlgSettingsPath.ui", "Path")
Log('Loading Path workbench... done\n')
def GetClassName(self):
return "Gui::PythonWorkbench"
def Activated(self):
# update the translation engine
FreeCADGui.updateLocale()
Msg("Path workbench activated\n")
def Deactivated(self):
Msg("Path workbench deactivated\n")
def ContextMenu(self, recipient):
if len(FreeCADGui.Selection.getSelection()) == 1:
if FreeCADGui.Selection.getSelection()[0].isDerivedFrom("Path::Feature"):
self.appendContextMenu("",["Path_Inspect"])
if "Profile" in FreeCADGui.Selection.getSelection()[0].Name:
self.appendContextMenu("",["Add_Tag"])
self.appendContextMenu("",["Set_StartPoint"])
self.appendContextMenu("",["Set_EndPoint"])
if "Remote" in FreeCADGui.Selection.getSelection()[0].Name:
self.appendContextMenu("",["Refresh_Path"])
self.appendContextMenu("", ["Path_Inspect"])
if "Profile" in FreeCADGui.Selection.getSelection()[0].Name:
self.appendContextMenu("", ["Add_Tag"])
self.appendContextMenu("", ["Set_StartPoint"])
self.appendContextMenu("", ["Set_EndPoint"])
if "Remote" in FreeCADGui.Selection.getSelection()[0].Name:
self.appendContextMenu("", ["Refresh_Path"])
Gui.addWorkbench(PathWorkbench())
FreeCAD.addImportType("GCode (*.nc *.gc *.ncc *.ngc *.cnc *.tap *.gcode)","PathGui")
FreeCAD.addExportType("GCode (*.nc *.gc *.ncc *.ngc *.cnc *.tap *.gcode)","PathGui")
FreeCAD.addImportType(
"GCode (*.nc *.gc *.ncc *.ngc *.cnc *.tap *.gcode)", "PathGui")
FreeCAD.addExportType(
"GCode (*.nc *.gc *.ncc *.ngc *.cnc *.tap *.gcode)", "PathGui")

View File

@ -74,7 +74,7 @@ class ObjectDrilling:
def execute(self, obj):
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None:
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25

View File

@ -80,7 +80,7 @@ class ObjectPathEngrave:
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None:
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25

View File

@ -1,79 +1,99 @@
# -*- 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 *
# * *
# ***************************************************************************
''' A CNC machine object to define how code is posted '''
import FreeCAD,Path
import FreeCAD
import Path
import PathScripts
from PathScripts import PathProject, PathUtils
from PySide import QtCore,QtGui
import os, sys
from PathScripts import PathUtils
from PySide import QtCore, QtGui
import os
import sys
# 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 Machine:
def __init__(self,obj):
obj.addProperty("App::PropertyString", "MachineName","Base",translate("Machine Name","Name of the Machine that will use the CNC program"))
def __init__(self, obj):
obj.addProperty("App::PropertyFile", "PostProcessor", "CodeOutput", translate("Post Processor","Select the Post Processor file for this machine"))
#obj.setEditorMode("PostProcessor",1) #set to read only
obj.addProperty("App::PropertyEnumeration", "MachineUnits","CodeOutput", translate( "Machine Units", "Units that the machine works in, ie Metric or Inch"))
obj.MachineUnits=['Metric', 'Inch']
obj.addProperty("App::PropertyString", "MachineName", "Base", translate(
"Machine Name", "Name of the Machine that will use the CNC program"))
obj.addProperty("Path::PropertyTooltable","Tooltable", "Base",translate("Tool Table","The tooltable used for this CNC program"))
obj.addProperty("App::PropertyFile", "PostProcessor", "CodeOutput", translate(
"Post Processor", "Select the Post Processor file for this machine"))
# obj.setEditorMode("PostProcessor",1) #set to read only
obj.addProperty("App::PropertyEnumeration", "MachineUnits", "CodeOutput", translate(
"Machine Units", "Units that the machine works in, ie Metric or Inch"))
obj.MachineUnits = ['Metric', 'Inch']
obj.addProperty("App::PropertyDistance", "X_Max", "Limits", translate("X Maximum Limit","The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Y_Max", "Limits", translate("Y Maximum Limit","The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Z_Max", "Limits", translate("Y Maximum Limit","The Maximum distance in X the machine can travel"))
obj.addProperty("Path::PropertyTooltable", "Tooltable", "Base", translate(
"Tool Table", "The tooltable used for this CNC program"))
obj.addProperty("App::PropertyDistance", "X_Min", "Limits", translate("X Minimum Limit","The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Y_Min", "Limits", translate("Y Minimum Limit","The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Z_Min", "Limits", translate("Y Minimum Limit","The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "X_Max", "Limits", translate(
"X Maximum Limit", "The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Y_Max", "Limits", translate(
"Y Maximum Limit", "The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Z_Max", "Limits", translate(
"Y Maximum Limit", "The Maximum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "X", "HomePosition", translate("X Home Position","Home position of machine, in X (mainly for visualization)"))
obj.addProperty("App::PropertyDistance", "Y", "HomePosition", translate("Y Home Position","Home position of machine, in Y (mainly for visualization)"))
obj.addProperty("App::PropertyDistance", "Z", "HomePosition", translate("Z Home Position","Home position of machine, in Z (mainly for visualization)"))
obj.addProperty("App::PropertyDistance", "X_Min", "Limits", translate(
"X Minimum Limit", "The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Y_Min", "Limits", translate(
"Y Minimum Limit", "The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "Z_Min", "Limits", translate(
"Y Minimum Limit", "The Minimum distance in X the machine can travel"))
obj.addProperty("App::PropertyDistance", "X", "HomePosition", translate(
"X Home Position", "Home position of machine, in X (mainly for visualization)"))
obj.addProperty("App::PropertyDistance", "Y", "HomePosition", translate(
"Y Home Position", "Home position of machine, in Y (mainly for visualization)"))
obj.addProperty("App::PropertyDistance", "Z", "HomePosition", translate(
"Z Home Position", "Home position of machine, in Z (mainly for visualization)"))
obj.Proxy = self
mode = 2
obj.setEditorMode('Placement',mode)
obj.setEditorMode('Placement', mode)
def execute(self,obj):
obj.Label = "Machine_"+str(obj.MachineName)
gcode = 'G0 X'+str(obj.X.Value)+' Y'+str(obj.Y.Value)+' Z'+str(obj.Z.Value) #need to filter this path out in post- only for visualization
def execute(self, obj):
obj.Label = "Machine_" + str(obj.MachineName)
# need to filter this path out in post- only for visualization
gcode = 'G0 X' + str(obj.X.Value) + ' Y' + \
str(obj.Y.Value) + ' Z' + str(obj.Z.Value)
obj.Path = Path.Path(gcode)
def onChanged(self,obj,prop):
def onChanged(self, obj, prop):
mode = 2
obj.setEditorMode('Placement',mode)
obj.setEditorMode('Placement', mode)
if prop == "PostProcessor":
sys.path.append(os.path.split(obj.PostProcessor)[0])
@ -81,161 +101,167 @@ class Machine:
postname = os.path.split(lessextn)[1]
exec "import %s as current_post" % postname
if hasattr (current_post, "UNITS"):
if hasattr(current_post, "UNITS"):
if current_post.UNITS == "G21":
obj.MachineUnits = "Metric"
else:
obj.MachineUnits = "Inch"
if hasattr (current_post, "MACHINE_NAME"): obj.MachineName = current_post.MACHINE_NAME
if hasattr(current_post, "MACHINE_NAME"):
obj.MachineName = current_post.MACHINE_NAME
if hasattr (current_post, "CORNER_MAX"):
if hasattr(current_post, "CORNER_MAX"):
obj.X_Max = current_post.CORNER_MAX['x']
obj.Y_Max = current_post.CORNER_MAX['y']
obj.Z_Max = current_post.CORNER_MAX['z']
if hasattr (current_post, "CORNER_MIN"):
if hasattr(current_post, "CORNER_MIN"):
obj.X_Min = current_post.CORNER_MIN['x']
obj.Y_Min = current_post.CORNER_MIN['y']
obj.Z_Min = current_post.CORNER_MIN['z']
if prop == "Tooltable":
proj = PathUtils.findProj()
proj = PathUtils.findProj()
for g in proj.Group:
if not(isinstance(g.Proxy, PathScripts.PathMachine.Machine)):
g.touch()
class _ViewProviderMachine:
def __init__(self,vobj):
def __init__(self, vobj):
vobj.Proxy = self
vobj.addProperty("App::PropertyBool","ShowLimits","Path","Switch the machine max and minimum travel bounding box on/off")
vobj.addProperty("App::PropertyBool", "ShowLimits", "Path", translate(
"ShowMinMaxTravel", "Switch the machine max and minimum travel bounding box on/off"))
mode = 2
vobj.setEditorMode('LineWidth',mode)
vobj.setEditorMode('MarkerColor',mode)
vobj.setEditorMode('NormalColor',mode)
vobj.setEditorMode('ShowFirstRapid',0)
vobj.setEditorMode('DisplayMode',mode)
vobj.setEditorMode('BoundingBox',mode)
vobj.setEditorMode('Selectable',mode)
def __getstate__(self): #mandatory
vobj.setEditorMode('LineWidth', mode)
vobj.setEditorMode('MarkerColor', mode)
vobj.setEditorMode('NormalColor', mode)
vobj.setEditorMode('ShowFirstRapid', 0)
vobj.setEditorMode('DisplayMode', mode)
vobj.setEditorMode('BoundingBox', mode)
vobj.setEditorMode('Selectable', mode)
def __getstate__(self): # mandatory
return None
def __setstate__(self,state): #mandatory
def __setstate__(self, state): # mandatory
return None
def getIcon(self): #optional
def getIcon(self): # optional
return ":/icons/Path-Machine.svg"
def attach(self,vobj):
def attach(self, vobj):
from pivy import coin
self.extentsBox = coin.SoSeparator()
vobj.RootNode.addChild(self.extentsBox)
def onChanged(self,vobj,prop):
def onChanged(self, vobj, prop):
if prop == "ShowLimits":
self.extentsBox.removeAllChildren()
if vobj.ShowLimits and hasattr(vobj,"Object"):
if vobj.ShowLimits and hasattr(vobj, "Object"):
from pivy import coin
parent = coin.SoType.fromName("SoSkipBoundingGroup").createInstance()
parent = coin.SoType.fromName(
"SoSkipBoundingGroup").createInstance()
self.extentsBox.addChild(parent)
# set pattern
pattern = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part").GetInt("GridLinePattern",0x0f0f)
pattern = FreeCAD.ParamGet(
"User parameter:BaseApp/Preferences/Mod/Part").GetInt("GridLinePattern", 0x0f0f)
defStyle = coin.SoDrawStyle()
defStyle.lineWidth = 1
defStyle.linePattern = pattern
parent.addChild(defStyle)
# set color
c = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path").GetUnsigned("DefaultExtentsColor",3418866943)
r = float((c>>24)&0xFF)/255.0
g = float((c>>16)&0xFF)/255.0
b = float((c>>8)&0xFF)/255.0
c = FreeCAD.ParamGet(
"User parameter:BaseApp/Preferences/Mod/Path").GetUnsigned("DefaultExtentsColor", 3418866943)
r = float((c >> 24) & 0xFF) / 255.0
g = float((c >> 16) & 0xFF) / 255.0
b = float((c >> 8) & 0xFF) / 255.0
color = coin.SoBaseColor()
parent.addChild(color)
# set boundbox
extents = coin.SoType.fromName("SoFCBoundingBox").createInstance()
extents = coin.SoType.fromName(
"SoFCBoundingBox").createInstance()
extents.coordsOn.setValue(False)
extents.dimensionsOn.setValue(False)
XMax, YMax, ZMax =vobj.Object.X_Max.Value , vobj.Object.Y_Max.Value , vobj.Object.Z_Max.Value
XMin, YMin, ZMin =vobj.Object.X_Min.Value , vobj.Object.Y_Min.Value , vobj.Object.Z_Min.Value
UnitParams = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units")
XMax, YMax, ZMax = vobj.Object.X_Max.Value, vobj.Object.Y_Max.Value, vobj.Object.Z_Max.Value
XMin, YMin, ZMin = vobj.Object.X_Min.Value, vobj.Object.Y_Min.Value, vobj.Object.Z_Min.Value
# UnitParams = FreeCAD.ParamGet(
# "User parameter:BaseApp/Preferences/Units")
extents.minBounds.setValue(XMax, YMax, ZMax)
extents.maxBounds.setValue(XMin, YMin, ZMin)
parent.addChild(extents)
mode = 2
vobj.setEditorMode('LineWidth',mode)
vobj.setEditorMode('MarkerColor',mode)
vobj.setEditorMode('NormalColor',mode)
vobj.setEditorMode('ShowFirstRapid',0)
vobj.setEditorMode('DisplayMode',mode)
vobj.setEditorMode('BoundingBox',mode)
vobj.setEditorMode('Selectable',mode)
vobj.setEditorMode('LineWidth', mode)
vobj.setEditorMode('MarkerColor', mode)
vobj.setEditorMode('NormalColor', mode)
vobj.setEditorMode('ShowFirstRapid', 0)
vobj.setEditorMode('DisplayMode', mode)
vobj.setEditorMode('BoundingBox', mode)
vobj.setEditorMode('Selectable', mode)
def updateData(self,vobj,prop): #optional
def updateData(self, vobj, prop): # optional
# this is executed when a property of the APP OBJECT changes
pass
def setEdit(self,vobj,mode=0): #optional
def setEdit(self, vobj, mode=0): # optional
# this is executed when the object is double-clicked in the tree
pass
def unsetEdit(self,vobj,mode=0): #optional
def unsetEdit(self, vobj, mode=0): # optional
# this is executed when the user cancels or terminates edit mode
pass
def doubleClicked(self,vobj):
def doubleClicked(self, vobj):
from PathScripts import TooltableEditor
TooltableEditor.edit(vobj.Object.Name)
class CommandPathMachine:
def GetResources(self):
return {'Pixmap' : 'Path-Machine',
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathMachine","Machine Object"),
return {'Pixmap': 'Path-Machine',
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathMachine", "Machine Object"),
'Accel': "P, M",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathMachine","Create a Machine object")}
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathMachine", "Create a Machine object")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
return FreeCAD.ActiveDocument is not None
def Activated(self):
FreeCAD.ActiveDocument.openTransaction(translate("PathMachine","Create a Machine object"))
FreeCAD.ActiveDocument.openTransaction(
translate("PathMachine", "Create a Machine object"))
CommandPathMachine.Create()
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
@staticmethod
def Create():
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Machine")
obj = FreeCAD.ActiveDocument.addObject(
"Path::FeaturePython", "Machine")
Machine(obj)
_ViewProviderMachine(obj.ViewObject)
PathUtils.addToProject(obj)
UnitParams = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units")
UnitParams = FreeCAD.ParamGet(
"User parameter:BaseApp/Preferences/Units")
if UnitParams.GetInt('UserSchema') == 0:
obj.MachineUnits = 'Metric'
#metric mode
# metric mode
else:
obj.MachineUnits = 'Inch'
obj.ViewObject.ShowFirstRapid = False
return obj
if FreeCAD.GuiUp:
if FreeCAD.GuiUp:
# register the FreeCAD command
import FreeCADGui
FreeCADGui.addCommand('Path_Machine',CommandPathMachine())
FreeCADGui.addCommand('Path_Machine', CommandPathMachine())
FreeCAD.Console.PrintLog("Loading PathMachine... done\n")

View File

@ -74,8 +74,8 @@ class ObjectPocket:
obj.addProperty("App::PropertyDistance", "MaterialAllowance", "Pocket", translate("PathProject", "Amount of material to leave"))
obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket", translate("PathProject", "Start pocketing at center or boundary"))
obj.StartAt = ['Center', 'Edge']
obj.addProperty("App::PropertyFloatConstraint", "StepOver", "Pocket", translate("PathProject", "Amount to step over on each pass"))
obj.StepOver = (0.0, 0.01, 100.0, 0.5)
obj.addProperty("App::PropertyPercent", "StepOver", "Pocket", translate("PathProject", "Percent of cutter diameter to step over on each pass"))
#obj.StepOver = (0.0, 0.01, 100.0, 0.5)
obj.addProperty("App::PropertyBool", "KeepToolDown", "Pocket", translate("PathProject", "Attempts to avoid unnecessary retractions."))
obj.addProperty("App::PropertyBool", "ZigUnidirectional", "Pocket", translate("PathProject", "Lifts tool at the end of each pass to respect cut mode."))
obj.addProperty("App::PropertyBool", "UseZigZag", "Pocket", translate("PathProject", "Use Zig Zag pattern to clear area."))
@ -118,22 +118,7 @@ class ObjectPocket:
if baselist is None:
baselist = []
if len(baselist) == 0: # When adding the first base object, guess at heights
# try:
# bb = ss.Shape.BoundBox # parent boundbox
# subobj = ss.Shape.getElement(sub)
# fbb = subobj.BoundBox # feature boundbox
# obj.StartDepth = bb.ZMax
# obj.ClearanceHeight = bb.ZMax + 5.0
# obj.SafeHeight = bb.ZMax + 3.0
# if fbb.ZMax < bb.ZMax:
# obj.FinalDepth = fbb.ZMax
# else:
# obj.FinalDepth = bb.ZMin
# except:
# obj.StartDepth = 5.0
# obj.ClearanceHeight = 10.0
# obj.SafeHeight = 8.0
try:
bb = ss.Shape.BoundBox # parent boundbox
@ -197,7 +182,7 @@ class ObjectPocket:
obj.FinalDepth.Value)
extraoffset = obj.MaterialAllowance.Value
stepover = obj.StepOver
stepover = (self.radius * 2) * (float(obj.StepOver)/100)
use_zig_zag = obj.UseZigZag
zig_angle = obj.ZigZagAngle
from_center = (obj.StartAt == "Center")
@ -242,22 +227,23 @@ class ObjectPocket:
# Build up the offset loops
output = ""
offsets = []
nextradius = self.radius
nextradius = (self.radius * 2) * (float(obj.StepOver)/100)
result = DraftGeomUtils.pocket2d(shape, nextradius)
print "did we get something: " + str(result)
while result:
print "Adding " + str(len(result)) + " wires"
offsets.extend(result)
nextradius += self.radius
nextradius += (self.radius * 2) * (float(obj.StepOver)/100)
result = DraftGeomUtils.pocket2d(shape, nextradius)
# revert the list so we start with the outer wires
if obj.StartAt != 'Edge':
offsets.reverse()
plungePos = None
rampEdge = None
if obj.UseEntry:
# Try to find an entry location
plungePos = None
toold = self.radius*2
helixBounds = DraftGeomUtils.pocket2d(shape, self.radius * (1 + obj.HelixSize))
@ -279,7 +265,6 @@ class ObjectPocket:
# Maybe reverse helixBounds and pick off that?
if plungePos is None: # If we didn't find a place to helix, how about a ramp?
rampEdge = None
FreeCAD.Console.PrintMessage(translate("PathPocket", "Attempting ramp entry.\n"))
if (offsets[0].Edges[0].Length >= toold * rampD) and not (isinstance(offsets[0].Edges[0].Curve, Part.Circle)):
rampEdge = offsets[0].Edges[0]
@ -305,6 +290,7 @@ class ObjectPocket:
first = True
# loop over successive wires
for currentWire in offsets:
#output += PathUtils.convert(currentWire.Edges, "on", 1)
last = None
for edge in currentWire.Edges:
if not last:
@ -363,7 +349,7 @@ class ObjectPocket:
def execute(self, obj):
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None:
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25
@ -371,13 +357,14 @@ class ObjectPocket:
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
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
if tool is None:
self.radius = 0.25
else:
self.radius = tool.Diameter/2
# if tool is None:
# self.radius = 0.25
# else:
# self.radius = tool.Diameter/2
if obj.Base:
for b in obj.Base:
@ -514,7 +501,7 @@ class CommandPathPocket:
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('PathScripts.PathPocket.ViewProviderPocket(obj.ViewObject)')
FreeCADGui.doCommand('from PathScripts import PathUtils')
FreeCADGui.doCommand('obj.StepOver = 1.0')
FreeCADGui.doCommand('obj.StepOver = 100')
FreeCADGui.doCommand('obj.ClearanceHeight = 10') # + str(bb.ZMax + 2.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop))

View File

@ -258,7 +258,7 @@ print "y - " + str(point.y)
import Part # math #DraftGeomUtils
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None:
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25

View File

@ -157,7 +157,7 @@ class ObjectRemote:
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad is None:
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25

View File

@ -0,0 +1,100 @@
# ***************************************************************************
# * (c) Sliptonic (shopinthewoods@gmail.com) 2016 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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. *
# * *
# * FreeCAD 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 Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with FreeCAD; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************/
'''This file has utilities for checking and catching common errors in FreeCAD
Path projects. Ideally, the user could execute these utilities from an icon
to make sure tools are selected and configured and defaults have been revised'''
from PySide import QtCore, QtGui
import FreeCAD
import FreeCADGui
import PathScripts.PathUtils as PU
# 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)
def review(obj):
"checks the selected project for common errors"
for item in obj.Group:
print "Checking: " + item.Label
if item.Name[:4] == "Tool":
if item.ToolNumber == 0:
FreeCAD.Console.PrintWarning(translate("Path_Sanity", "Tool Controller: " + str(item.Label) + " is using ID 0 which is the default\n"))
else:
tool = PU.getTool(item, item.ToolNumber)
if tool is None:
FreeCAD.Console.PrintError(translate("Path_Sanity", "Tool Controller: " + str(item.Label) + " is using tool: " + str(item.ToolNumber) + " which is invalid\n"))
continue
if tool.Diameter == 0:
FreeCAD.Console.PrintError(translate("Path_Sanity", "Tool Controller: " + str(item.Label) + " is using tool: " + str(item.ToolNumber) + " which has a zero diameter\n"))
if item.HorizFeed == 0:
FreeCAD.Console.PrintWarning(translate("Path_Sanity", "Tool Controller: " + str(item.Label) + " has a 0 value for the Horizontal feed rate\n"))
if item.VertFeed == 0:
FreeCAD.Console.PrintWarning(translate("Path_Sanity", "Tool Controller: " + str(item.Label) + " has a 0 value for the Vertical feed rate\n"))
if item.SpindleSpeed == 0:
FreeCAD.Console.PrintWarning(translate("Path_Sanity", "Tool Controller: " + str(item.Label) + " has a 0 value for the spindle speed\n"))
if item.Name[:7] == "Machine":
if len(item.Tooltable.Tools) == 0:
FreeCAD.Console.PrintWarning(translate("Path_Sanity", "Machine: " + str(item.Label) + " has no tools defined in the tool table\n"))
class CommandPathSanity:
def GetResources(self):
return {'Pixmap' : 'Path-Sanity',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Sanity","Check the Path project for common errors"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Sanity","Check the Path Project for common errors")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelection()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate("Path_Sanity","Please select a path Project to check\n"))
return
if not(selection[0].TypeId == "Path::FeatureCompoundPython"):
FreeCAD.Console.PrintError(translate("Path_Sanity","Please select a path project to check\n"))
return
# if everything is ok, execute
FreeCADGui.addModule("PathScripts.PathSanity")
FreeCADGui.doCommand('PathScripts.PathSanity.review(FreeCAD.ActiveDocument.' + selection[0].Name + ')')
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Sanity',CommandPathSanity())

View File

@ -241,7 +241,7 @@ class ObjectSurface:
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad == None:
if toolLoad == None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25

View File

@ -26,6 +26,7 @@ import FreeCAD
import Part
import math
from DraftGeomUtils import geomType
from DraftGeomUtils import findWires
import DraftVecUtils
import PathScripts
from PathScripts import PathProject
@ -271,9 +272,11 @@ def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5):
sortedpreoff = Part.__sortEdges__(preoffset)
wire = Part.Wire(sortedpreoff)
#wire = findWires(sortedpreoff)[0]
else:
sortedpreoff = Part.__sortEdges__(edgelist)
wire = Part.Wire(sortedpreoff)
#wire = findWires(sortedpreoff)[0]
edgelist = []
for e in wire.Edges:
@ -287,7 +290,9 @@ def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5):
geomType(e) == "BezierCurve" or \
geomType(e) == "Ellipse":
edgelist.append(Part.Wire(curvetowire(e, (SegLen))))
newwire = Part.Wire(edgelist)
#newwire = Part.Wire(edgelist)
sortededges = Part.__sortEdges__(edgelist)
newwire = findWires(sortededges)[0]
if Side == 'Left':
# we use the OCC offset feature