254 lines
11 KiB
Python
254 lines
11 KiB
Python
# -*- 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 *
|
|
# * *
|
|
# ***************************************************************************
|
|
''' A CNC machine object to define how code is posted '''
|
|
|
|
import FreeCAD
|
|
import Path
|
|
import PathScripts
|
|
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", "Name of the Machine that will use the CNC program")
|
|
|
|
obj.addProperty("App::PropertyFile", "PostProcessor", "CodeOutput", "Select the Post Processor file for this machine")
|
|
obj.addProperty("App::PropertyEnumeration", "MachineUnits", "CodeOutput", "Units that the machine works in, ie Metric or Inch")
|
|
obj.MachineUnits = ['Metric', 'Inch']
|
|
|
|
obj.addProperty("Path::PropertyTooltable", "Tooltable", "Base", "The tooltable used for this CNC program")
|
|
|
|
obj.addProperty("App::PropertyDistance", "X_Max", "Limits", "The Maximum distance in X the machine can travel")
|
|
obj.addProperty("App::PropertyDistance", "Y_Max", "Limits", "The Maximum distance in X the machine can travel")
|
|
obj.addProperty("App::PropertyDistance", "Z_Max", "Limits", "The Maximum distance in X the machine can travel")
|
|
|
|
obj.addProperty("App::PropertyDistance", "X_Min", "Limits", "The Minimum distance in X the machine can travel")
|
|
obj.addProperty("App::PropertyDistance", "Y_Min", "Limits", "The Minimum distance in X the machine can travel")
|
|
obj.addProperty("App::PropertyDistance", "Z_Min", "Limits", "The Minimum distance in X the machine can travel")
|
|
|
|
obj.addProperty("App::PropertyDistance", "X", "HomePosition", "Home position of machine, in X (mainly for visualization)")
|
|
obj.addProperty("App::PropertyDistance", "Y", "HomePosition", "Home position of machine, in Y (mainly for visualization)")
|
|
obj.addProperty("App::PropertyDistance", "Z", "HomePosition", "Home position of machine, in Z (mainly for visualization)")
|
|
|
|
obj.Proxy = self
|
|
mode = 2
|
|
obj.setEditorMode('Placement', mode)
|
|
|
|
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):
|
|
mode = 2
|
|
obj.setEditorMode('Placement', mode)
|
|
|
|
if prop == "PostProcessor":
|
|
sys.path.append(os.path.split(obj.PostProcessor)[0])
|
|
lessextn = os.path.splitext(obj.PostProcessor)[0]
|
|
postname = os.path.split(lessextn)[1]
|
|
|
|
exec "import %s as current_post" % postname
|
|
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, "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"):
|
|
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()
|
|
for g in proj.Group:
|
|
if not(isinstance(g.Proxy, PathScripts.PathMachine.Machine)):
|
|
g.touch()
|
|
|
|
|
|
class _ViewProviderMachine:
|
|
|
|
def __init__(self, vobj):
|
|
vobj.Proxy = self
|
|
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
|
|
return None
|
|
|
|
def __setstate__(self, state): # mandatory
|
|
return None
|
|
|
|
def getIcon(self): # optional
|
|
return ":/icons/Path-Machine.svg"
|
|
|
|
def attach(self, vobj):
|
|
from pivy import coin
|
|
self.extentsBox = coin.SoSeparator()
|
|
vobj.RootNode.addChild(self.extentsBox)
|
|
|
|
def onChanged(self, vobj, prop):
|
|
|
|
if prop == "ShowLimits":
|
|
self.extentsBox.removeAllChildren()
|
|
if vobj.ShowLimits and hasattr(vobj, "Object"):
|
|
from pivy import coin
|
|
parent = coin.SoType.fromName(
|
|
"SoSkipBoundingGroup").createInstance()
|
|
self.extentsBox.addChild(parent)
|
|
# set pattern
|
|
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
|
|
color = coin.SoBaseColor()
|
|
parent.addChild(color)
|
|
# set boundbox
|
|
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")
|
|
|
|
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)
|
|
|
|
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
|
|
# this is executed when the object is double-clicked in the tree
|
|
pass
|
|
|
|
def unsetEdit(self, vobj, mode=0): # optional
|
|
# this is executed when the user cancels or terminates edit mode
|
|
pass
|
|
|
|
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"),
|
|
'Accel': "P, M",
|
|
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathMachine", "Create a Machine object")}
|
|
|
|
def IsActive(self):
|
|
return FreeCAD.ActiveDocument is not None
|
|
|
|
def Activated(self):
|
|
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")
|
|
Machine(obj)
|
|
_ViewProviderMachine(obj.ViewObject)
|
|
|
|
PathUtils.addToProject(obj)
|
|
|
|
UnitParams = FreeCAD.ParamGet(
|
|
"User parameter:BaseApp/Preferences/Units")
|
|
if UnitParams.GetInt('UserSchema') == 0:
|
|
obj.MachineUnits = 'Metric'
|
|
# metric mode
|
|
else:
|
|
obj.MachineUnits = 'Inch'
|
|
|
|
obj.ViewObject.ShowFirstRapid = False
|
|
return obj
|
|
|
|
if FreeCAD.GuiUp:
|
|
# register the FreeCAD command
|
|
import FreeCADGui
|
|
FreeCADGui.addCommand('Path_Machine', CommandPathMachine())
|
|
|
|
|
|
FreeCAD.Console.PrintLog("Loading PathMachine... done\n")
|