VTK的Python接口
翻译和修改自:https://github.com/Kitware/VTK/tree/master/Wrapping/Python
英文原作者:David Gobbi
有关VTK的Python包装器的说明
STL 容器
VTK提供’std :: vector’和Python序列之间的转换,例如“tuple”和“list”。 如果C ++方法返回vector,Python方法将返回一个tuple:
C++: const std::vector<std::string>& GetPaths()
C++: std::vector<std::string> GetPaths()
Python: GetPaths() -> Tuple[str]
如果C ++方法接vector,则Python方法可以是传递了具有兼容值的任何序列(Sequence):
C++: void SetPaths(const std::vector<std::string>& paths)
C++: void SetPaths(std::vector<std::string> paths)
Python: SetPaths(paths: Sequence[str]) -> None
此外,如果C ++方法接受非常量向量引用,然后可以向Python方法传递可变的序列(Sequence)(例如list):
C++: void GetPaths(std::vector<std::string>& paths)
Python: GetPaths(paths: MutableSequence[str]) -> None
std :: vector的值类型必须为std :: string或基本数字类型,例如“ double”或“ int”(包括“ signed char”和“ unsigned char”,但不包括“ char”)。
内建文件
VTK头文件和html手册页中所有可用的文档也可以通过python获得。
如果您想查看某个类可用的方法,例如:
>>> dir(vtk.vtkActor)
或者,等效地,
>>> a = vtk.vtkActor()
>>> dir(a)
还可以从内置的“文档字符串”中检索有关VTK类和方法的文档:
>>> help(vtk.vtkActor)
>>> help(vtk.vtkActor.SetUserTransform)
对于方法文档,该方法的所有不同“签名”均以Python格式和原始C ++格式给出:
>>> help(vtkActor.SetPosition)
SetPosition(...)
V.SetPosition(float, float, float)
C++: virtual void SetPosition(double _arg1, double _arg2, double _arg3)
V.SetPosition([float, float, float])
C++: virtual void SetPosition(double _arg[3])
Set/Get/Add the position of the Prop3D in world coordinates.
特殊性
删除vtkObject
由于python提供了一种自动垃圾收集机制,因此没有与vtk的delete()直接等价的方法。一旦从python内部或其他vtk对象中没有对该对象的剩余引用,该对象将被删除。通过使用python’del’命令(即’del o’)可以去掉对对象的本地引用,如果对对象的本地引用是python中对该对象的最后一个剩余引用,则这将导致调用delete()。
模板类
模板类在VTK中很少见。 在使用它们的地方,可以像在C ++中一样实例化它们,除了将[ ]括号用于模板参数而不是<>括号:
>>> v = vtkVector['float64',3]([1.0, 2.0, 3.0])
>>> a = vtkDenseArray[str]()
只能使用有限范围的模板args,通常由typedef和C ++代码中的其他类使用args决定。 可以通过在模板上调用help()来找到可用于特定模板的允许参数组合的列表:
>>> help(vtkVector)
这些类型通常以字符串形式给出,形式为“ int32”,“ uint16”,“ float32”,“ float64”,“ bool”,“ char”,“ str”,“ vtkVariant”。 如果类型的名称与可接受的类型字符串之一相同,则也可以使用Python类型对象:
>>> a = vtkDenseArray[int]()
请注意,python’int’与C ++'long’的大小相同,而python’float’与C ++'double’的大小相同。 为了与python数组模块兼容,允许使用以下列表中的单字符类型代码:“?”,“ c”,“ b”,“ B”,“ h”,“ H”,“ i”,“ I” ',‘l’,‘L’,‘q’,‘Q’,‘f’,‘d’。 python数组文档解释了这些含义。
运算符的重载
python中包装了一些有用的运算符:[]运算符被包装用于索引和项目分配,但是由于它依赖于提示来猜测哪些索引超出范围,因此仅被包装用于vtkVector和其他一些类 。
比较运算符’<’’<=’’==’’> =’’>'被包装为所有在C ++中具有这些运算符的类。
包装了用于打印的“ <<”运算符,并由python的“ print()”和“ str()”命令使用。
引用传递
仅可以使用vtkCommonCore Python模块中的vtk.reference()来传递在C++中可变但在Python中不可变的值的引用(例如字符串,int和float):
>>> plane = vtk.vtkPlane()
>>> t = vtk.reference(0.0)
>>> x = [0.0, 0.0, 0.0]
>>> plane.IntersectWithLine([0, 0, -1], [0, 0, 1], t, x)
>>> print(t)
0.5
观察者,事件和CallData
Simple callback
与C ++中的操作类似,每次在给定对象上调用VTK事件时,都可以调用python函数:
>>> def onObjectModified(object, event):
>>> print('object: %s - event: %s' % (object.GetClassName(), event))
>>>
>>> o = vtkObject()
>>> o.AddObserver(vtkCommand.ModifiedEvent, onObjectModified)
1
>>> o.Modified()
object: vtkObject - event: ModifiedEvent
Callback with CallData
如果有与事件关联的’CallData’值,则在C ++中,必须使用reinterpret_cast将其从void*强制转换为期望的类型。 例如,请参阅 http://www.vtk.org/Wiki/VTK/Examples/Cxx/Interaction/CallData
python中的等效项是在关联的python回调上设置CallDataType属性。 支持的CallDataType是vtk.VTK_STRING,vtk.VTK_OBJECT,vtk.VTK_INT,vtk.VTK_LONG,vtk.VTK_DOUBLE,vtk.VTK _FLOAT
例如:
>>> def onError(object, event, calldata):
>>> print('object: %s - event: %s - msg: %s' % (object.GetClassName(),
event, calldata))
>>>
>>> onError.CallDataType = vtk.VTK_INT
>>>
>>> lt = vtkLookupTable()
>>> lt.AddObserver(vtkCommand.ErrorEvent, onError)
1
>>> lt.SetTableRange(2,1)
object: vtkLookupTable - event: ErrorEvent - msg: ERROR:
In /home/jchris/Projects/VTK6/Common/Core/vtkLookupTable.cxx, line 122
vtkLookupTable (0x6b40b30): Bad table range: [2, 1]
为了方便起见,还可以在首先使用’calldata_type’装饰器声明函数的位置指定CallDataType:
>>> @calldata_type(vtk.VTK_INT)
>>> def onError(object, event, calldata):
>>> print('object: %s - event: %s - msg: %s' % (object.GetClassName(),
event, calldata))
子类化VTK类
可以从Python内部对VTK类进行子类化,但是无法正确覆盖该类的虚方法。 VTK C ++代码将看不到python级别的代码,因此从C ++调用虚拟方法时,将不会调用您在Python内部定义的方法。 仅当您在Python中调用该方法时,才会执行该方法。
因此,例如,将vtkInteractorStyle子类化以提供自定义python交互是不合理的。相反,您必须通过将观察者添加到vtkInteractor对象来执行此操作。
类方法的调用
在C ++中,如果要从超类调用方法,则可以执行以下操作:
vtkActor *a = vtkActor::New();
a->vtkProp3D::SetPosition(10,20,50);
python中的等效项是
>>> a = vtkActor()
>>> vtkProp3D.SetPosition(a,10,20,50)
Void 指针
作为一项特殊功能,可以将需要“ void *”的C ++方法传递给任何支持“缓冲区”协议的python对象,其中包括字符串对象,numpy数组甚至VTK数组。 使用此功能时应格外小心。
在Python中,在C ++中返回“ void *”的方法将返回带有十六进制数字的字符串,该字符串给出了内存地址。
将数据从Python传输到VTK
如果要从VTK中访问Python中的大量数据(例如,数值数组),则可以使用vtkDataArray.SetVoidArray()方法进行操作。
仅从VTK对象的地址创建Python对象
实例化一个类时,可以提供一个十六进制字符串,其中包含现有vtk对象的地址,例如
t = vtkTransform('_1010e068_vtkTransform_p')
该字符串遵循SWIG修改约定。 如果指定对象的包装已经存在,则将使用该包装,而不是创建新的包装。 如果要使用vtkpython的此功能,请三思。
具有“ pythonic”等效项的VTK C ++方法
SafeDownCast(): 不必要,Python已经知道真实类型
IsA(): Python提供了内置的isinstance()方法。
IsTypeOf(): Python提供了一个内置的issubclass()方法。
GetClassName(): 此信息由o .__ class __.__ name__提供
特殊VTK类型
除了从vtkObjectBase派生的VTK对象外,VTK中还有许多轻量级类型,例如vtkTimeStamp或vtkVariant。这些通常可以与vtkObjects区别开来,因为它们没有C ++的’:: New()'构造方法。
这些类型与vtkObject派生类的包装方式略有不同。内存管理的细节有所不同,因为Python实际上将对象的副本保留在其“包装器”中,而对于vtkObjects,它仅保留了一个指针。
这些类型的不完整列表如下:vtkVariant,vtkTimeStamp,vtkArrayCoordinates,vtkArrayExtents,vtkArrayExtentsList,vtkArrayRange
自动转换
这些特殊类型可以具有多个构造函数,并且这些构造函数可以用于VTK方法的自动类型转换。例如,vtkVariantArray具有方法InsertNextItem(vtkVariant v),而vtkVariant具有构造函数vtkVariant(int x)。因此,可以这样做:
>>> variantArray.InsertNextItem(1)
包装器将自动从“ 1”构造一个vtkVariant,然后将其作为参数传递给InsertNextItem。
比较和映射
某些特殊类型可以按值排序,而某些可以用作dict键。 排序要求存在比较运算符,例如’<’’<=’’==’’> =’’>’,并且这些运算符不会自动包装。 使用对象作为dict键需要计算哈希值。 vtkVariant和vtkTimeStamp支持比较和哈希处理,其他类型将视情况进行支持。
可以轻松地对所有vtkObject进行哈希处理而又很难对vtk特殊类型进行哈希处理的原因是,vtkObjects是按内存地址进行哈希处理的。 对于特殊类型,不能这样做,因为它们必须按值而不是按地址进行散列。 即 vtkVariant(1)必须与其他所有vtkVariant(1)相等,即使存在各种实例且具有不同的内存地址。
VTK-Python提供的特殊属性
特殊的vtk对象属性:
o.__class__ 该对象是其实例的类
o.__doc__ 类的描述(从C ++头文件获得)
o.__this__ 包含VTK对象地址的字符串
特殊方法属性:
m.__doc__ 方法的描述(从C ++头文件获得)
vtk类的特殊属性:
c.__bases__ 该类的基类的元组(vtkObject为空)
c.__doc__ 类的描述(从C ++头文件获得)
c.__name__ 类的名称,与GetClassName()返回的名称相同