2.1 图形模型
VTK的图形模型和实现类
VTK的图形模型,主要有以下几个核心类组成:
1)渲染交互器:实现用户和渲染窗口之间的交互操作。
2)渲染窗口(RenderW indow):实现类为 vtk RenderW indow。
3)渲染器( Render ):实现类为 vtkRe nder。
4)灯光(Light):实现类为 vtkLight 。
5)相机(Ca mera):实现类为 vtkCamera 。
6)角色( Ac tor):实现类为 vtkActor。
7)属性(Property):实现类为 vtkProperty。
8)变换(Tra ns form):实现类为 vtk Trans form。
9)映射(Mapper):实现类为 vtkMapper。
2.2 VTK 类的扩展规范
2.2.1 扩展注意事项
VTK 提供了用户扩展它的机制,既然用户可以访问 VTK 的源代码,那么用户就可以增加 VTK 类去扩展它。但是在扩展 VTK 类之前,用户还必须考虑一些基本的问题:
1) 代码是否符合 VTK 的编写规范
2) 是否有代码的文档
3) 代码是否具有通用性
4) 代码是否要求修改系统
5) 代码功能是否与存在的功能重复
6) 代码是否已经在 VTK 中存在
如果考虑过上述问题,用户就可以编写的 VTK 类了。VTK 要求它的代码有一致的编程风格。一致的代码风格使代码易读、易调试、易维护、易测试和易扩展。
2.2.2 编码风格
以下是一些编程风格:
1) 变量、函数和类名要用大写字母开头。变量和函数必须一直用大写字母开头,不提倡用静态变量(如果用了必须也以大写字母开头)。比如SetNumberOfPoint()和 PickList 分别为函数和变量的例子。
2) 类名必须以 vtk 开始,后面紧接类名的大写字母。比如 vtkActor 或者vtkPolyData 就是类名。vtk 前缀允许 VTK 的类库同其他类库混合。
3) 在方法中使用 this->pointers 。比如 this->Visibility 、 this->Property 和this->Excute()。this->pointers 的运用可以改善代码的可理解性和可读性。变量、函数和类名应该使用单词全拼。也可以用单词的缩写,但是缩写的每个字母都要大写,比如:vtkPolyDataConnectivity 和 vtkLODActor。
5) 预处理变量要用大写来书写,使用―_‖分隔单词。预处理变量应该以 VTK_开始,比如:VTK_LARGE_FLOAT。
6) 实例变量一般是 Protect 或者 Privite 类型。对实例变量的访问要用 Set/Get方法,VTK 提供了 Set/Get 宏定义,用户可以直接用他们进行访问。
7) 用//注释代码。可以这样来写://Description:对代码的注释,如果注释多于一行,则后面每一行都得用//开始几乎每一个 VTK 的对象都有一些标准的方法。大多数方法都被 vtkObject 类定义并执行了。并且大多数对象都继承 vtkObject 类。当然,继承父类的子类同样要根据实际需要重新执行继承的函数和方法。比如 New()方法就应该被每一个实体类执行,然而 Delete()方法就直接继承 vtkObject 的方法即可。
2.2.3 类的基本方法
在编写新的 VTK 类之前必须熟悉以下类的基本方法:
1) New():这是一个静态类方法,用它进行对象的初始化。用户称这个方法为对象工厂,因为它可以产生类的实例。在 VTK 中,每一个 New()方法都要对应一个 Delete()方法。
2) Instance=NewInstance():这是一个虚的构造函数。调用这个方法可以使对象产生一个跟它同类型的实例,并返回一个指向该对象的指针。
3) Delete():用这个方法去删除由 New()或者 NewInstance()方法产生的对象。根据被删除对象的实际情况,这个方法不会直接删除一个对象。只有当一个对象的引用计数器为 0 的时候,该对象才会被删除。
4) DebugOn/DebugOff():打开或关闭 debugging 信息,这个方法可由 vtkObject对象继承。
5) Print():打印出对象和父类的信息。Print 这个方法在 vtkObject 中被定义,要求每一个类执行 PrintSelf。PrintSelf 方法在一个链中被调用,每一个子类调用它父类的 PrintSelf 方法并打印的实例变量。
6) Name=GetClassName():以字符串的形式返回一个类的名字。这个方法被用来调试信息。
7) Flag=IsA(className):如果这个类名是一个父类或者跟本来这个类是同一个类型的,就返回非 0 的数。
8) *ptr=<class>::SafeDownCast(vtkObject *O):这是一个静态类方法,将一个通用类转化到具体类。如果 ptr 返回 Null,则转化失败;否则 ptr 将指向一个类的实例。
9) Modified():这个方法更新内部对象的更改时间,这个值必须保证唯一并且递增。
10) Mtime=GetMTime():返回对象最后修改的时间。通常这个方法由 vtkObject对象继承,有时需要重载它。
上面是一些基本的 VTK 函数,每一个类都必须定义这些函数,这样才符合VTK 的规范。从上面用户可以知道每一个用 New()方法产生的对象,都必须用Delete()方法删除掉。New()方法被称为对象工厂,因为它被用来产生类的对象。除了上面的基本函数,VTK 的类还必须具有构造函数和析构函数:
vtkX()—构造函数
~vtkX()—析构函数
构造函数和析构函数必须申明为 Protect 类型。还要申明
Operator=(const vtkX&)—等于操作
vtkX(const vtkX&)—复制构造函数
这两个函数必须被申明为 private 类型。而且不用被执行,作用是防止编译器自动产生对象。这也意味着用户不能调用这些函数。
2.2.4 数据访问方法
VTK 的数据访问主要分为数组的访问和数据集的访问,VTK 提供访问的基本方法,子类继承这些方法并提供许多针对不同子类的访问方法。
1) 数据数组
数据数组在类 vtkDataArray 和他的子类中执行,是构建许多 VTK 数据对象的基础。数据数组表示内部数据在连续的数组空间中并且可以动态分配内部存储空间。数据数组主要用来表示几何(vtkPoints),属性数据(scalars, vectors, normals,tensors, texture coordinates)和场数据。数据数组基于数据元组的抽象也提供内部数据的接口。在元组的抽象图中,vtkDataArray 将数据表示成元组的集合,每一个元组有相同的分量数和相同的数据类型。
其他的各种数据类型可以用元组数组的形式来表示,比如用户想表示浮点类型的向量数据。用户可以创建 vtkFloatArray 类(vtkDataArray 的子类,每一个元组分量为 3)来表示向量。这样,向量的数量就是元组的数量。
下面研究部分访问 vtkDataArray 的方法,这些方法被所有子类继承,就是说子类可以调用这些方法。当然子类可以有针对本身数据特点的访问方法。
(1) dataArray = NewInstance():创建当前数据类型的数据数组。
(2) type = GetDataType():返回数据类型。
(3) SetNumberOfCompoents():设置每个元组的分量数。
(4)GetNumberOfCompoents():获得每个元组的分量数。
(5)SetNumberOfTuples(number):设置数组中元组的个数。这个方法将分配存储空间,并和前面的 SetNumberOfComponents()方法来确定空间大小。
(6)numTuples = GetNumberOfTuples():返回元组数量。
(7)tuple = GetTuple(i):返回指向第 i 个元组的指针。
(8)SetTuple(i, tuple):确定第 i 个位置的元组。这个方法不执行范围检查,速度比 InsertTuple 快。
(9)InsertTuple(i, tuple):在位置 i 插入数据。这个方法进行范围检查,如果可能将会分配存储空间。
(10)c= GetComponent(i, j):获得第 i 个元组的 j 个分量。
基于 Paraview 扩展与实现——(6)