A quick look at some common syntax errors you’ll see if you copy and paste Python code into the script editor. Also, I get on my mini-soap box and tell you you got to know the language syntax if you want to script 😉
http://vimeo.com/27061025
Category Archives: Python
Writing particle point positions to a CSV file
One of the nice things about Python is the convenience of modules like CSV.
A point cloud is an X3DObject, so you could just get the point positions the same way you would for a mesh. But the recommended way to do it is with ICEAttribute.GetDataArrayChunk or, for small point clouds, ICEAttribute.DataArray.
import csv
from siutils import si # Application
from siutils import sidict # Dictionary
from siutils import log # LogMessage
# Get a CSV writer object
# http://docs.python.org/release/2.5.2/lib/module-csv.html
csvWriter = csv.writer(open('cloud1.csv', 'wb'), delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
# PointCloud is an X3DObject, so you can simply get points at current frame
# For large point clouds, use the ICEAttribute object instead
points = sidict.GetObject( "pointcloud" ).ActivePrimitive.Geometry.Points;
for p in points:
#print "(%s, %s, %s)" % ( p.Position.X, p.Position.Y, p.Position.Z )
csvWriter.writerow([p.Position.X, p.Position.Y, p.Position.Z])
# Use the ICEAttribute.DataArray for PointPositions
# For large point clouds, use ICEAttribute.GetDataArrayChunk
points = sidict.GetObject( "pointcloud" ).ActivePrimitive.Geometry.ICEAttributes("PointPosition").DataArray
for p in points:
log( "%s, %s, %s" % (p.X, p.Y, p.Z) )
csvWriter.writerow([p.X, p.Y, p.Z])
Update: The above script will write the CSV file in %XSI_BINDIR%. Changing the output location is an exercise left to the reader 😉 as is using GetDataArrayChunck (but for that you can copy the example in the docs).
Python PolygonMesh.Set example
This simple example shows how to pass in the vertex and polygon data in Python.
Application.CreatePrim("Cube", "MeshSurface", "", "")
oCube = Application.Selection(0)
# tuple of tuples
# one tuple for the X coordinate, one for the Y, and one for the Z
verts = ((-0.5, 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 5.0), (-0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.0), (-0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -18.0))
# tuple of polygon data
polys = (4, 0, 2, 3, 1, 4, 0, 1, 5, 4, 4, 0, 4, 6, 2, 4, 1, 3, 7, 5, 4, 2, 6, 7, 3, 4, 4, 5, 7, 6)
Application.FreezeObj(oCube)
oCube.ActivePrimitive.Geometry.Set(verts,polys)
To help understand the vertex and polyon data, consider this simple polygon mesh:

Given the above polygon mesh, this snippet:
oCube = Application.Selection(0) data = oCube.ActivePrimitive.Geometry.Get2() verts = data[0] polys = data[1] print verts print polys
would print this:
# ((-3.0, 4.0, 1.0, -2.0), (0.0, -4.0, 0.0, 0.0), (1.0, -4.0, 5.0, 3.0)) # (4, 0, 1, 2, 3)
A brief history of the Python multi-dispatch issue
For the most part, this is no longer a problem, although there may be a few cases where you have to use win32com.client.dynamic.Dispatch. A huge effort was put in to XSI 6.0 to get rid of this “dispatch” issue.
The main problem was that XSI used a technique called “Multi-Dispatch” rather than normal inheritance to organize the interfaces supported by each object in the Scripting Object Model. In the original SDK, this was designed to maintain binary ompatibility for the now-obsolete COM C++ API.
The problem was that because Python used optimizations to read and compile the contents of typelibs rather than communicating with XSI directly via IDispatch, objects did not always appear to have all the methods and properties that they are supposed to.
For XSI 6.0, the OM hierarchy was overhauled to use derivation and inheritance instead of the multi-dispatch mechanism.
Prior to XSI 6.0, the workaround was the __init__.py file hack, as described in this 2005 post to the XSI Mailing List by Jerry Gamache:
—–Original Message—–
From: owner-xsi@Softimage.COM [mailto:owner-xsi@Softimage.COM] On Behalf Of Jerry Gamache
Sent: March-17-05 2:23 PM
To: XSI@Softimage.COM
Subject: RE: avoiding using get value with pythonXSI sometimes return objects with an incorrectly set (as per PythonWin standards) multi-dispatch interface.
The way to work around that is to re-wrap the object in a dynamic dispatch. This allows you to skip the Application.GetValue:
def dispFix( badDispatch ): import win32com.client.dynamic # Re-Wraps a bad dispatch into a working one: return win32com.client.dynamic.Dispatch(badDispatch) # Let's see if this works: Application.CreatePrim("Sphere", "MeshSurface", "", "") Application.ApplyHairOp("sphere", "") oHair = Application.GetValue("hair").ActivePrimitive.ConstructionHistory.Find("HairGenOp") try: Application.LogMessage(oHair.Parameters['EmitterMeshSubdlevel'].Value) except: Application.LogMessage("Incorrect dispatch pointer") oHair = dispFix(oHair) Application.LogMessage(oHair.Parameters['EmitterMeshSubdlevel'].Value) # or, as a single long line: dispFix(Application.GetValue("hair") .ActivePrimitive.ConstructionHistory .Find("HairGenOp") ).Parameters['EmitterMeshSubdlevel'].Value = 1If that really really annoys you and you don’t want to dispFix at all, there is a way to make sure everything works, but you need to modify a Python file to always return dynamic dispatches:
Change %PYTHONPATH%\Lib\site-packages\win32com\client\__init__.py
Look for the function called __WrapDispatch
And comment all lines except the last one that begins with “return dynamic.Dispatch( … ”
Of course it is always a good idea to backup files you are about to modify.
Getting the selected ICE nodes
The context for custom menu callbacks gives you access to the current view instance, so you can use the selection view attribute to get the selected ICE nodes. See line 35 in the example.
import win32com.client
from win32com.client import constants
null = None
false = 0
true = 1
def XSILoadPlugin( in_reg ):
in_reg.Author = "blairs"
in_reg.Name = "My_ICETreeUserTool_Plugin"
in_reg.Major = 1
in_reg.Minor = 0
in_reg.RegisterMenu(constants.siMenuICEViewToolsID,"My_ICETreeUserTool_Menu",false,false)
#RegistrationInsertionPoint - do not remove this line
return true
def XSIUnloadPlugin( in_reg ):
strPluginName = in_reg.Name
Application.LogMessage(str(strPluginName) + str(" has been unloaded."),constants.siVerbose)
return true
def My_ICETreeUserTool_Menu_Init( in_ctxt ):
oMenu = in_ctxt.Source
oMenu.AddCallbackItem("My ICE Tree User Tool","OnMyICETreeUserTool")
return true
def OnMyICETreeUserTool( in_ctxt ):
itv = in_ctxt.GetAttribute("Target")
LogMessage( 'View: ' + itv.Name )
# get the selected nodes
nodes = itv.GetAttributeValue('selection')
LogMessage( 'Selected nodes: ' + nodes )
Installing Python modules in the Softimage Python site-packages
To get a Python module like PIL to work with the Python installed with Softimage, you will need to edit the registry. I tested this on my system, where I do not have any Python installed, except the Python installed with Softimage.
The PIL installer is looking in the registry for that Python install path, so we must edit the registry to put in the path to the Softimage Python.
You can use regedit to add the registry entry
HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.6\InstallPath
Then set the “(Default)” value to
C:\Program Files\Autodesk\Softimage 2011 Subscription Advantage Pack\Application\python
If you do have an external Python installed, you can just temporarily change the “(Default)” value to point to the Softimage install of Python.
Hat Tip: leendert68
Also: mabxsi suggests an alternative approach that avoids editing the registry
Python not available in Softimage 2011 SAP after you uninstall 2011 SP1
To get Python back, you need to run runonce.bat.
Getting the contents of docked views
I was recently asked whether it’s possible to find docked FxTree views and figure out 1) what specific tree is loaded, and 2) what nodes are selected in the Fx tree.
You can find docked Fx Tree views, but unfortunately there’s no way to find out what’s in that view.
Here’s a Python snippet that finds docked Fx Tree views:
# Find docked Fx Tree views
oVM = Application.Desktop.ActiveLayout.Views.Filter( "View Manager" )
oFxTreeViews = oVM(0).Views.Filter( "Fx Tree" )
for view in oFxTreeViews:
Application.LogMessage(view.Name+": "+view.Type)
In the XSI SDK, you use attributes to access the contents of a view, and there are no attributes defined for Fx Tree views.
For example, here’s how it works for an ICE Tree view:
# Find docked ICE Tree views oVM = Application.Desktop.ActiveLayout.Views.Filter( "View Manager" ) oICETreeViews = oVM(0).Views.Filter( "ICE Tree" ) # Get the ICE tree that is loaded into the view Application.LogMessage( oICETreeViews(0).GetAttributeValue( "container" ) ); # Get the selected nodes in the ICE tree Application.LogMessage( oICETreeViews(0).GetAttributeValue( "selection" ) );
PyQT ImportError: DLL load failed: The specified procedure could not be found
Several customers have hit this error when using PyQT with Softimage.
# INFO : Traceback (most recent call last): # File "somefile.py", line X, in <module> # from PyQt4 import QtGui # ImportError: DLL load failed: The specified procedure could not be found.
On Windows, Softimage 2011 includes four Qt DLLs in the %XSI_BINDIR% folder.
- QtCore4.dll
- QtGui4.dll
- QtOpenGL4.dll
- QtXml4.dll
We don’t use the Qt DLLs. I believe the idea was to ship the Qt dlls for plugins that use Qt, so that the dlls were already in place. So, you can rename the DLLs to .bak to avoid the error.
References:
conflict with QT DLLs inside Softimage 2011.5
Scripting – struggling to get pyQt to work
Python gotcha – Forgetting the parentheses after a method name
Technically, I suppose this is not really a gotcha. But for someone like me who has to switch between scripting languages frequently, it’s a potential “gotcha”.
In Python, functions and methods are legitimate objects. That’s why you can do this:
App = Application LogMsg = App.LogMessage ClassName = App.ClassName
but sometimes you might forget the parentheses after a name, and unlike JScript, you won’t get a syntax error (at least not for the missing parentheses). For example, this little snippet will give you a “# AttributeError: ‘NoneType’ object has no attribute ‘AddKey'” error:
param = Application.Dictionary.GetObject( "null.kine.local.rotx" )
if str(param.Source) == 'None':
param.AddFcurve
fcurve = param.Source
fcurve.AddKey( 10, 90 )
fcurve.AddKey( 20, 45 )
In JScript, you’d get a syntax error for the missing parentheses. I’m not saying that that is better 😉 it’s just a difference you have to be aware of.
param = Dictionary.GetObject( "null.kine.local.rotx" ) param.AddFcurve // ERROR : Object doesn't support this property or method - [line 3]
Some related links:

