MeVisLab Scripting Reference
Open Inventor Wrappers


MeVisLab contains Python wrappers for the whole Open Inventor toolkit. This allows to:

The wrappers are inside of the Inventor Python package and are organized as follows:

  • Inventor
    • actions
    • base
    • details
    • draggers
    • elements
    • engines
    • events
    • fields
    • manips
    • nodekits
    • nodes
    • projectors
    • sensors


The Inventor.base module contains all the linear algebra classes and some base classes like SoType and SoBase. This is different to the C++ Inventor, where these classes are in the root directory and the the misc directory.

The following shows an example of doing a plane/line intersection:

1 from Inventor import base
3 plane = base.SbPlane(base.SbVec3f(0,0,1), 45)
4 line = base.SbLine(base.SbVec3f(0,0,1), base.SbVec3f(0,0,100))
5 result = plane.intersect(line)

Linear algebra is available in single and double precision, denoted by a "f" postfix for float and a "d" postfix for double. Some single precision classes do not have a "f" postfix, e.g. SbPlane, SbRotation, SbMatrix, while the double precision versions always have a "d" postfix.

The MLABField classes accept both single and double precision on setValue(), but always return double precision versions, since they use double precision internally.

Each linear algebra class has a conversion method to convert to the other precision, e.g. SbVec3f.toVec3d(), SbVec3d.toVec3f(), SbMatrix.toMatrixd(), SbMatrixd.toMatrix(), ...


The Inventor.base module contains all basic Inventor nodes and can be used to construct scene graphs in Python. The fields of Inventor nodes and engines can be accessed by their name. Use getValue()/setValue() to read/write a field's value. A scene graph can be stored in a MLABSoNodeField, so you can create a macro module that internally builds a scene graph and outputs the scene via an MLABSoNodeField.

1 from Inventor import base
2 from Inventor import nodes
4 def createScene():
5  group = nodes.SoGroup()
7  cam = nodes.SoOrthographicCamera()
8  group.addChild(cam)
10  cube = nodes.SoCube()
11  cube.width.setValue(2)
12  cube.height.setValue(4)
13  cube.depth.setValue(6)
14  group.addChild(cube)
16  cube2 = nodes.SoCube()
17  cube2.width.setValue(2)
18  cube2.height.setValue(4)
19  cube2.depth.setValue(6)
20  group.addChild(cube2)
22  # store the group in the "output" MLABSoNodeField of a macro module:
23  ctx.field("output").setObject(group)


The Inventor.actions module contains all Inventor actions. You can use it to e.g. get the bounding box of a scene or to search for a node in the scene.

1 from Inventor import base
2 from Inventor import nodes
3 from Inventor import actions
5 action = actions.SoGetBoundingBoxAction(base.SbViewportRegion(256,256))
7 group = nodes.SoGroup()
8 cube = nodes.SoCube()
9 cube.width.setValue(2)
10 cube.height.setValue(4)
11 cube.depth.setValue(6)
12 group.addChild(cube)
14 action.apply(group)
15 box = action.getBoundingBox()


The Inventor.fields defines all core Inventor fields. Fields are exposed as properties of the nodes/engines they are contained in. Field values can be set/get via setValue()/setValues() and getValue()/getValues(). Fields with multiple values (e.g. SoMFFloat, SoMFVec3f, ...) support NumPy arrays in their setValues() methods and return a read-only NumPy array in getValues(). To efficiently set values, you can either create a NumPy array and set it via setValues() (this causes an extra copy), or you can use the setNum() and startEditing()/finishEditing() methods to directly work on the field data using a NumPy array that contains a direct pointer to the field data.

The MLABField offers the MLABField::inventorField() method to access the underlying SoField of an MLABField that wraps an Inventor field. This allows to e.g. use the SoMFVec3f API to set multiple vector values on an MLABField that wraps a SoMFVec3f, without the need to use setStringValue().

1 from Inventor import base
2 from Inventor import nodes
3 import numpy
5 prop = nodes.SoVertexProperty()
7 # Using an extra NumPy array:
8 array = numpy.ndarray([10,3],dtype='f')
9 for i in range(10):
10  array[i] = (i,i+1,i+2)
11 # Set the vertex field from a numpy array
12 prop.vertex.setValues(0, array)
14 # Alternative: using a NumPy array that uses the direct memory of the field
15 # (This is the fastest way of setting the field's value)
17 # Set number of needed elements
18 prop.vertex.setNum(5)
19 # Get the numpy array using startEditing()
20 array = prop.vertex.startEditing()
21 for i in range(5):
22  array[i] = (i,i-1,i-2)
23 # Finish the editing.
24 prop.vertex.finishEditing()
25 # NOTE: Do not access the array, nor keep a reference to it AFTER finishEditing()!
26 array = None


The Inventor.sensors module contains all Inventor sensors. You can use it to listen to fields and nodes, or to create a timer.

1 cube = None
3 def fieldChanged(sensor):
4  print "field changed"
6 def createFieldSensor():
7  global cube
8  cube = nodes.SoCube()
9  sensor = sensors.SoFieldSensor(fieldChanged)
10  sensor.attach(cube.width)
11  cube.width = 12

NOTE: Inventor sensors are triggered via a delayed queue, so you will not get an immediate notification if a field changes, you will get it later on when the Inventor queue is processed.

Deriving your own Inventor SoNode

The Inventor wrappers offer to derive from a SoNode (or any derived class) from within Python. It is possible to implement the GLRender method and to use PyOpenGL to do the actual rendering. Using the Inventor.elements and the SoState of an action, it is possible to read/write to all available Inventor elements in the state. There is currently no example for this, but we will add one soon.


Various places in Open Inventor take static C callback functions. Most places have been overloaded with methods that take a Python callable instead. Please note that these callables are not reference counted by the callback setter function, so you need to keep a reference of the function around in Python. Normal member functions will be ref-counted anyways, so this is mainly a problem when you want to use local functions or lambdas as callback functions, in which case you need to store them in a Python variable that lives longer than the C++ object on which you are setting the callback.