在VTK中,属性数据和点都用数据数组(data arrays)表示。某些属性数据(例如法线、张量)需要具有与其定义一致的元组(在计算机编程中,元组(tuple)用来表示存储多种数据类型的有序值集。元组中的各个值以逗号分隔,例如“(2.0, 3.4, 5.0)”是一个三元组的示例)大小,例如,点、向量和法线需要元组大小为3的数据数组;张量的元组大小为9(即3x3矩阵)。标量对元组大小没有任何要求。
1 数据数组(vtkDataArray)
考虑数据的大小和范围,必须谨慎管理内存以创建高效的可视化系统。在VTK中,使用连续数据数组(continuous data arrays)作为大多数数据结构的基础。与其他数据结构(例如链表或指向结构体的指针数组)相比,连续数组的创建、删除和遍历速度更快。
VTK中决定用数据数组而非对象数组(例如,为单元和点使用单独的类)的原因是,对象的构造和析构是有性能成本的。从性能的角度看,面向对象的方法适用在应用程序层,而不是在实现层。
连续数组也可以轻松地通过网络传输,特别是如果数组中的信息是与计算机地址无关的内容。内存独立性避免了将信息从一个内存位置映射到另外一个内存位置的开销。因此,在VTK中,根据“id”(索引)访问信息。数组数组(vtkDataArray)默认的偏移量是0,就像C++数组一样。也就是说,给定了n个数据值,使用id(0、1、2、...、n-1)依次访问这些值。下图是VTK中连续数组vtkFloatArray的实现。
array是指向内存的指针。数组的长度由Size给出。数组是动态的,因此尝试插入超出分配大小的数据会自动做Resize()处理。MaxId是一个整数偏移量,定义插入数据的结尾。如果未插入任何数据,则MaxId等于-1,否则,MaxId是一个整数值,0 ≤ MaxId ≤ Size。
2 数据元组
许多可视化数据由多个组件定义。x-y-z坐标三元组或RGBA颜色像素值就是两个这样的例子。为了在连续的数据数组中表示此类数据,引入了元组。如下图所示,连续数组被分组为具有NumberOfComponents个组件的较小的子数组,这些子数组称为元组。
3 数据对象(vtkDataObject)
vtkDataObject是可视化数据的通用表示,其派生的子类从VTK: vtkDataObject Class Reference中的类图可以看到。很少有算法直接对数据对象进行操作,大多数算法都需要指定数据的组织结构才能处理,数据集(vtkDataSet)是其中一个例子,其指定了数据的组织结构,其类图如下:
在VTK中实现了五种数据集:vtkPolyData, vtkImageData, vtkStructuredGrid, vtkRectilinearGrid, and vtkUnstructuredGrid. 非结构化的点数据集没有被现实,但是它能使用vtkPolyData或者vtkUnstructuredGrid来表示。
VTK对每种数据集类型使用了不同的内部数据表示。通过使用不同的的表示,可以最大限度地减少数据结构内存需求并实现高效的访问方法。本来可以使用vtkUnstructuredGrid来表示所有数据集类型,但对于大数据来说,内存和计算开销是不可接受的。
vtkPolyData
与vtkImageData和vtkStructuredGrid不同,vtkPolyData的拓扑结构不规则,因此必须明确地表示数据集的拓扑结构和几何形状。vtkPolyData中的点数据使用vtkPoints类表示。
VTK中使用vtkCellArray来表示单元的拓扑结构,该类是每个单元的连接列表,列表的结构是一串整数(如下图),列表中的第一个数字是计数,下一个数字序列是单元连接。
(连接列表中的每个数字都是点坐标列表实例的索引。)计数序列后跟连接列表,重复进行,直到枚举每个单元。vtkCellArray还维护列表中的单元数和列表中的当前位置(用于遍历)等其他信息。
单元的类型(参见VTK----VTK数据结构详解(几何篇)-CSDN博客)信息不直接表示在vtkPolyData中,而是通过维护四个单独的列表来间接表示,这四个单独的列表分别表示顶点(vertices)、线(lines)、多边形(polygons)和三角形带(triangle strips)。顶点列表表示类型为vtkVertex和vtkPolyVertext的单元。线列表表示为类型vtkLine和vtkPolyLine的单元。多边形列表表示类型为vtkTriangle、vtkQuad和vtkPolygon的单元。三角形带列表表示为vtkTriangleStrip的单元。因此,单元类型可以从定义单元的特定列表及其定义单元的点数中得知。这四个单元列表还将单元分为0维、1维和2维类型。这很有用,因为可视化算法通常会以不同的方式处理不同拓扑顺序的数据。
vtkUnstructuredGrid
就表示拓扑结构和几何形状的能力而言,vtkUnstructuredGrid数据集类型是最通用的。点和单元都使用vtkPoints和vtkCellArray的派生类明确表示。vtkUnstructuredGrid类与vtkPolyData类类似,不同之处在于vtkUnstructuredGrid必须能够表示所有单元类型,而不仅仅是vtkPolyData的有限图形类型(即顶点、线、三角形和三角形带)。
vtkUnstructuredGrid的另一个显著特征是以不同的方式表示类型信息。在vtkPolyData中,将单元分为四个单独的列表,从而间接的表示单元的类型。在vtkUnstructuredGrid中,添加了附加类vtkCellType来明确表示单元类型。
vtkCellTypes是一个补充信息数组。对于每个单元,一个整数标志定义单元类型。另一个变量用于记录单元在对应的vtkCellArray中的位置。(如下图)
除了表示单元类型之外,此设计还支持对单元的随机访问。由于单元连接列表的长度各不相同,因此vtkCellArray无法在不从原点开始遍历其数据结构的情况下找到特定的单元。但是,使用添加的vtkCellTypes类,可以通过使用偏移(offset)值直接访问单元。
vtkCellTypes也可以添加到vtkPolyData数据表示中——事实上已经这样做了。但是,添加的原因不是为了表示单元类型,而是为了提供对单元的随机访问并启用许多拓扑操作。
以下是vtkUnstructuredGrid能表示的所有单元类型:
// These are all the cells that vtkUnstructuredGrid can represent. Used by// GetCell() (and similar) methods.vtkVertex* Vertex;vtkPolyVertex* PolyVertex;vtkBezierCurve* BezierCurve;vtkBezierQuadrilateral* BezierQuadrilateral;vtkBezierHexahedron* BezierHexahedron;vtkBezierTriangle* BezierTriangle;vtkBezierTetra* BezierTetra;vtkBezierWedge* BezierWedge;vtkLagrangeCurve* LagrangeCurve;vtkLagrangeQuadrilateral* LagrangeQuadrilateral;vtkLagrangeHexahedron* LagrangeHexahedron;vtkLagrangeTriangle* LagrangeTriangle;vtkLagrangeTetra* LagrangeTetra;vtkLagrangeWedge* LagrangeWedge;vtkLine* Line;vtkPolyLine* PolyLine;vtkTriangle* Triangle;vtkTriangleStrip* TriangleStrip;vtkPixel* Pixel;vtkQuad* Quad;vtkPolygon* Polygon;vtkTetra* Tetra;vtkVoxel* Voxel;vtkHexahedron* Hexahedron;vtkWedge* Wedge;vtkPyramid* Pyramid;vtkPentagonalPrism* PentagonalPrism;vtkHexagonalPrism* HexagonalPrism;vtkQuadraticEdge* QuadraticEdge;vtkQuadraticTriangle* QuadraticTriangle;vtkQuadraticQuad* QuadraticQuad;vtkQuadraticPolygon* QuadraticPolygon;vtkQuadraticTetra* QuadraticTetra;vtkQuadraticHexahedron* QuadraticHexahedron;vtkQuadraticWedge* QuadraticWedge;vtkQuadraticPyramid* QuadraticPyramid;vtkQuadraticLinearQuad* QuadraticLinearQuad;vtkBiQuadraticQuad* BiQuadraticQuad;vtkTriQuadraticHexahedron* TriQuadraticHexahedron;vtkTriQuadraticPyramid* TriQuadraticPyramid;vtkQuadraticLinearWedge* QuadraticLinearWedge;vtkBiQuadraticQuadraticWedge* BiQuadraticQuadraticWedge;vtkBiQuadraticQuadraticHexahedron* BiQuadraticQuadraticHexahedron;vtkBiQuadraticTriangle* BiQuadraticTriangle;vtkCubicLine* CubicLine;vtkConvexPointSet* ConvexPointSet;vtkPolyhedron* Polyhedron;vtkEmptyCell* EmptyCell;
4 数据属性
数据属性与数据集的结构相关联。数据集模型建立在点和单元上,因此将数据属性与点和单元关联起来也很自然而然。(与点关联的属性称为点属性,与单元关联的属性称为单元属性)中间结构(例如单元边或面)没有明确的类型表示,所以无法轻松将数据属性与它们进行关联。数据属性的设计基于以下原理:
- 数据采集和数值模拟系统通常在点位置或单元中心位置测量和/或计算结果。
- 边界属性信息(例如,在边或面上的)可以作为单元的数据进行保存,并根据单元的拓扑结构进行排序。
- VTK的数据模型基于点和单元的原因是基于内存和性能考虑的。在单元边界上表示属性数据需要做扩展,以支持少数需要支持单元边界上关联属性数据的情况。如果将来需要更复杂的数据结构来表示边界属性数据,最好将其封装到单个类中,而不是在整个系统中强制抽象。
维护单元数据和点数据表示的一个困难是数据中可能出现不一致。例如,如果单元的标量值是0.5,而其点的标量值不是0.5,那么哪个时正确的?可以设计优先级方案来解决这种情况。VTK中使用vtkPointData和vtkCellData表示数据属性,它们都是vtkFieldData的子类。vtkDataSetAttributes类用于协调数据从一个过程对象到另一个过程对象的移动。它提供了在输入(input)和输出(output)之间的复制、插入和移动数据的方法。
vtkDataSetAttributes类的另一个重要特性是它提供了分配数据数组来表示特定数据属性的能力。例如,方法SetScalars()用于指定哪个数据数组将被视为字段中的标量。
每个数据集点与其属性数据之间存在一一对应关系。点属性通过点ID访问。例如,要访问数据集实例aDataSet中点ID 129的标量值,如下:
DataSet -> GetPointData ()-> GetScalars ()-> GetTuple (129);