vtk教程第五章 基本数据表示

46 篇文章 19 订阅
12 篇文章 14 订阅

在第4章中,我们开发了可视化过程的实用定义:将信息映射到图形原语。我们看到了这种映射是如何通过一个或多个步骤进行的,每个步骤将数据从一种形式或数据表示转换为另一种形式或数据表示。在本章中,我们将研究用于可视化的常见数据表单。我们的目标是让您熟悉这些表单,以便使用本文提供的工具和技术可视化您自己的数据。

5.1介绍

为了设计数据的表示方案,我们需要了解可能遇到的数据。我们还需要牢记设计目标,这样我们才能设计有效的数据结构和访问方法。接下来的两节将讨论这些问题。

描述可视化数据

由于我们的目标是可视化数据,显然我们需要了解数据的特性。这些知识将帮助我们创建有用的数据模型和强大的可视化系统。如果没有对数据的清晰理解,我们就有可能设计出不灵活且有限的可视化系统。下面我们将描述数据的重要特征。这些特征是数据的离散性,无论它是规则的还是不规则的,以及它的拓扑维数。兼容的镶嵌。

首先,可视化数据是离散的。这是因为我们使用数字计算机来获取、分析和表示数据,并且通常在有限数量的点上测量或采样信息。因此,所有信息都必须以离散形式表示。考虑将简单的连续函数可视化。如果我们使用的是传统的数字计算机,我们必须离散化这个方程来操作它所代表的数据(我们忽略了符号/模拟计算机和方法)。例如,要绘制这个方程,我们要在某个区间(-1,1)对函数进行采样,然后在这个区间内的一系列离散点上计算函数的y值。得到的点((x0,y0), (x1,y1), (x2,y2),…(xn,yn))用直线段将点连接起来。

因此,我们的(连续)数据是由离散抽样表示的。由于数据的离散性,我们对数据值之间的区域一无所知。在前面的例子中,我们知道数据是由函数生成的,但是,一般来说,当我们测量甚至计算数据时,我们不能推断点之间的数据值。这带来了一个严重的问题,因为一个重要的可视化活动是确定任意位置的数据值。例如,我们可能探测数据并希望得到数据值,即使探测位置不在已知点上。

这个问题有一个显而易见的解决方案:插值。我们假定相邻数据值之间存在关系。通常这是一个线性函数,但我们可以使用二次、三次、样条或其他插值函数。第8章更详细地讨论了插值函数,但现在只说插值函数在已知点之间生成数据值就足够了。

可视化数据的第二个重要特征是其结构可以是规则的或不规则的(或者,结构化或非结构化)。常规数据在数据点之间具有固有的关系。例如,如果我们在一个等间隔的点集合上采样,我们不需要存储所有的点坐标,只需要存储区间的起始位置、点之间的间距和点的总数。这些点的位置是隐式已知的,可以利用这一点来节省计算机内存。

不规则的数据称为不规则数据。不规则数据的优势在于,我们可以在变化快的地方更密集地表示信息,而在变化不大的地方则不那么密集。因此,不规则数据允许我们创建自适应的表示形式,这在有限的计算资源下是有益的。

将数据描述为规则或不规则可以让我们对数据做出有用的假设。正如我们刚才看到的,我们可以更紧凑地存储常规数据。通常,我们也可以相对于不规则数据更有效地计算规则数据。另一方面,不规则数据在表示数据时给予了我们更多的自由,可以表示没有规则模式的数据。

最后,数据有一个拓扑维度。在我们的例子中,数据的维数是1,因为我们只有一个自变量x。数据可能是任何维数,从0D点到1D曲线、2D曲面、3D体积,甚至高维区域。

数据的维度很重要,因为它意味着可视化和数据表示的适当方法。例如,在1D中,我们自然地使用x-y图、柱状图或饼图,并将数据存储为1D值列表。对于2D数据,我们可以将数据存储在矩阵中,并将其与变形曲面图(即高度场-参见练习4.2)可视化。

在本章和第8章中,我们将展示这些特征:离散、规则/不规则和数据维,如何塑造我们的可视化数据模型。当你阅读这些章节时,请记住这些特点。

图5-1数据集架构数据集由具有拓扑和几何属性的组织结构以及与该结构相关联的属性数据组成。

设计规范

可视化数据包括与外部数据的接口、映射到内部形式、处理数据以及在计算机显示设备上生成图像。我们提出了一个问题:我们应该使用哪种或哪种形式来表示数据?当然,我们有很多选择。表示的选择很重要,因为它影响到外部数据接口的能力和整个可视化系统的性能。为了解决这个问题,我们使用以下设计标准:

紧凑。可视化数据往往很大,因此我们需要紧凑的存储方案来最小化计算机内存需求。

非常高效。数据必须在计算上可访问。我们希望在常数时间内检索和存储数据(即,与数据大小无关)。这一要求为我们提供了开发时间复杂度为线性或O(n)的算法的机会。

可映射。有两种类型的映射。首先,数据表示需要有效地映射到图形原语。这确保了数据的快速交互式显示。其次,我们必须能够轻松地将外部数据转换为内部可视化数据结构。否则,我们将承受复杂的转换过程或不灵活的软件带来的负担。

最小覆盖。单一的数据表示不能有效地描述所有可能的数据类型。我们也不希望遇到的每种数据类型都有不同的数据表示形式。因此,我们需要一个最小的数据表示集,以平衡效率和数据类型的数量。

简单。应用计算的一个主要经验是,简单的设计比复杂的设计更可取。简单的设计更容易理解,因此也更容易优化。简单的价值怎么强调都不为过。本文中的许多算法和数据表示都赋予该设计准则高优先级。本章的其余部分将描述基于这些设计标准的常见可视化数据表单。我们的基本抽象是数据对象,它是各种具体可视化数据类型的通称,这些数据类型是数据对象的子类。

5.2数据对象

VTK中最常见的数据形式是数据对象。数据对象可以看作是没有任何形式的数据集合。数据对象表示由可视化管道处理的数据(参见前一章和图4 - 2)。就其本身而言,数据对象携带的有用信息很少。只有当它们被组织成某种结构时,它们才提供了一种我们可以用可视化算法进行操作的形式。

5.3数据集

具有组织结构的数据对象和相关联的数据属性(如图5 - 1所示)构成数据集。数据集是一个抽象的形式;我们将结构的表示和实现留给它的具体子类。VTK中的大多数算法(或过程对象)操作在数据集上。

该结构由拓扑结构和几何结构两部分组成。拓扑是在某些几何变换下不变的属性的集合[Weiler86]。这里我们考虑转换:旋转、平移和非均匀缩放。几何是拓扑的实例化,是三维空间中位置的规范。例如,说一个多边形是一个“三角形”,就指定了拓扑。通过提供点坐标,我们可以指定几何形状。

数据集属性是与几何和/或拓扑相关的补充信息。这个信息可以是某一点的温度值,也可以是单元的惯性质量。

我们的数据集模型假设结构由单元格和点组成。单元格指定拓扑结构,而点指定几何结构。典型的属性包括标量、向量、法线、纹理坐标和张量。

将数据集的结构定义为单元格和点的集合是数据离散性质的直接结果。点位于已知数据的位置,单元格允许我们在点之间进行插值。我们将在以下部分详细描述数据集结构和属性。

5.4细胞类型

数据集由一个或多个单元格组成(图5 - 2和图5 - 4)。单元格是可视化系统的基本构件。单元格是通过结合指定类型和有序的点列表来定义的。有序列表(通常称为连通性列表)与类型规范相结合,隐式地定义单元的拓扑结构。x-y-z点坐标定义单元格几何形状。

图5 - 3显示了一种细胞类型,即六面体。有序列表是索引到点坐标列表中的点id序列。这个单元格的拓扑结构是隐式已知的:我们知道(8,10)是六面体的12条边之一,而(8,10,22,21)是它的六个面之一。

在数学上,我们用符号Ci表示单元格。然后,单元格是一个有序的点序列,其中是一组n维点(这里n=3)。单元格的类型决定了点的顺序或单元格拓扑结构。点的数量n定义

图5-2 VTK中发现的线性单元格类型。数字定义了定义点的顺序。

图5-3六面体单元示例。拓扑由点列表的顺序隐式定义。

用Ing表示单元格的大小。单元格在什么时候“使用”一个点。因此有了“使用集”

所有单元格的集合都在使用吗:pi

“使用”和“使用集”的重要性将在第8章探讨数据集的拓扑结构时显现出来。虽然我们在三维中定义点,但细胞可能在拓扑维度上有所不同。顶点、直线、三角形和四面体分别是拓扑上的0、1、2和3-D细胞的示例,它们嵌入三维几何空间中。细胞也可以是初级的或复合的。复合细胞由一个或多个原代细胞组成,而原代细胞不能分解为其他原代细胞类型的组合。例如,三角形带由一个或多个三角形组成,以紧凑的形式排列。三角形带是一个复合单元,因为它可以被分解成三角形,这些三角形是初级单元。当然,可能的细胞类型有无限多种。在可视化工具包中,每个单元格类型都是根据应用程序需要选择的。我们已经看到了一些单元格类型:顶点、直线、多边形和三角形条带(图3 - 19)是如何被用来向图形子系统或库表示几何图形的。其他单元类型如四面体和六面体在数值模拟中也很常见。通过贯穿本书的可视化实践,每一种单元格类型的效用将变得显而易见。对可视化工具包中发现的单元格类型的描述——包括它们的线性、非线性或其他分类——将在以下部分给出。

线性细胞

线性单元格的特征是线性或常数插值函数(参见269页的“插值函数”了解更多信息)。因此,尺寸为1或更大的单元格具有直边的特征。因此,任何边都可以用两个顶点id (v1,v2)来表示。以下是目前在VTK中发现的线性单元格。

顶点。顶点是一个基本的零维单元格。它是由一个点定义的。

Polyvertex。多顶点是一个复合零维单元格。多顶点由任意顺序的点列表定义。Ci pi pi Î Ci Up i () pi Up i () Ci:pi Ci = {Î} 8 10 1 6 22 7 5图5 - 3六面体单元示例。拓扑由点列表的顺序隐式定义。点列表x-y-z x-y-z x-y-z x-y-z x-y-z定义:类型:六面体连通性:(8,10,1,6,21,22,5,7)21 5.4单元类型127行。

线。这条线是主要的一维单元格。它由两点定义。沿直线的方向是从第一点到第二点。

多段线。折线是由一条或多条相连的线组成的复合一维单元。折线由n+1个点的有序列表定义,其中n是折线中的行数。每对点(i, i+1)定义一条直线。

三角形。三角形是一个二维单元格。三角形由三个点组成的逆时针顺序列表定义。点的顺序用右手定则指定曲面法线的方向。

三角地带。三角形带是由一个或多个三角形组成的复合二维单元。定义三角形带的点不必在一个平面上。三角形带是由n+2个点的有序列表定义的,其中n是三角形的数量。点的顺序是这样的,每三个点的集合定义一个三角形。

四边形。这个四边形是一个初等二维单元。它是由平面上四个点的有序列表定义的。这个四边形是凸的,它的边不能相交。点围绕四边形逆时针排列,使用右手法则定义曲面法线。

像素。像素是由四个点的有序列表定义的主要二维单元格。该单元在拓扑上等价于添加几何约束的四边形。像素的每条边都垂直于它的相邻边,并平行于其中一个坐标轴x-y-z。因此,像素的法线也平行于其中一个坐标轴。定义像素的点的顺序不同于四边形单元。点按轴坐标增加的方向排列,从x开始,然后是y,然后是z。像素是四边形的一种特殊情况,用于提高计算性能。一个重要的注意事项是,这里给出的像素单元的定义不同于通常的像素定义。通常像素被认为是图像中的常值“图像元素”(参见第51页的“图形硬件”)。这里给出的定义意味着四个图像元素构成像素单元的四个角点。我们通常使用术语像素来描述像素单元,但该术语的含义会因上下文而异。

多边形。多边形是一个原始的二维单元。多边形由平面上三个或三个以上点的有序列表定义。多边形法线隐式地定义为使用右手定则将其点按逆时针顺序排列。

多边形可以是非凸的,但可以没有内部循环,也不能自相交。多边形有n条边,其中n是多边形中的点数。

四面体。四面体是一个初级的三维细胞。四面体由四个非平面点组成的列表来定义。四面体有6条边和4个三角形面,如图5 - 2所示。

六面体。六面体是由六个四边形面、十二个边和八个顶点组成的初级三维单元。六面体由8个点的有序列表定义,如图5 - 2所示。面和边不能与任何其他面和边相交,六面体必须是凸的。

体素。体素是主要的三维细胞。体素在拓扑上等价于附加几何约束的六面体。体素的每个面都垂直于坐标x-y-z轴之一。定义点列表按照坐标值递增的方向排序,如图5 - 2所示。体素是六面体的一种特殊情况,用于提高计算性能。

类似于像素,我们对体素单元的定义不同于术语体素的传统定义。通常,体素被称为常值“体积元素”。使用我们的定义,8个体积元素构成体素单元的8个角点。我们通常使用术语体素来描述体素单元,但该术语的含义将根据上下文而有所不同。

楔。楔形是一个主要的三维单元,由三个四边形面、两个三角形面、九个边和六个顶点组成。楔形由6个点组成的有序列表定义,如图5 - 2所示。面和边不能与任何其他面和边相交,楔必须是凸的。

金字塔。金字塔是一个基本的三维单元,由一个四边形面、四个三角形面、八个边和五个顶点组成。金字塔由5个点组成的有序列表定义,如图5 - 2所示。确定四边形基平面的四个点必须是凸的;第五顶点不能与基准点共面。

五角棱镜。五角形棱镜是由五个四边形面、两个五角形面、十五个边和十个顶点组成的初级三维单元。五角形棱镜由十个点组成的有序列表定义,如图5 - 2所示。面和边不能与任何其他面和边相交,五边形必须是凸的。

六角棱镜。六边形棱镜是由六个四边形面、两个六边形面、十八个边和十二个顶点组成的初级三维单元。六角形棱镜由12个点组成的有序列表定义,如图5 - 2所示。面和边不能与任何其他面和边相交,六边形必须是凸的

非线性类型

在数值分析中通常使用非线性单元格,即使用非线性基函数的单元格公式。这些基函数一般由多项式组合而成。非线性单元格提供了更精确的插值函数(参见269页的“插值函数”)和更好的近似曲面几何。然而,可能的非线性基函数的数量是无限的,这对任何可视化系统都提出了一个组合问题(即,不可能实现所有非线性单元类型)。为了解决这个问题,VTK采取了双重方法。首先,VTK直接支持带有二次插值函数的非线性单元类型

图5-4 VTK中的非线性单元格类型。

如图5 - 4所示。这样的单元格是通过添加中间边缘节点、中间面节点和内部节点来构造的,需要扩展连接列表来反映这些额外条目的添加。其次,VTK有一个复杂的单元适配器框架,允许用户将任何基函数接口到VTK,只要基函数可以在r-s-t参数坐标系中唯一地表征。(注意:我们将在第8章更详细地描述单元适配器框架。)线性单元格和非线性单元格之间的。

一个显著区别是它们被各种可视化算法渲染和操作的方式。线性单元格很容易转换为线性图形原语,然后由图形库处理。另一方面,非线性单元格在图形库中通常没有直接的支持。(一个例外是非均匀有理b样条族或NURBS。甚至这些通常被图形库镶嵌成线性原语。)因此,可视化系统必须对非线性单元进行特殊处理。一些可能性包括:

1;将非线性单元格细分为线性单元格,然后对线性单元格进行操作。

2. 开发自定义渲染和可视化算法,以直接操作非线性单元。

3.在图形库中编程自定义渲染操作。

这些问题是可视化研究中的活跃话题[Schroeder05]。在VTK中,目前采用镶嵌方法,因为一旦镶嵌,细胞就可以通过现有的线性算法进行处理。上述解决方案2)和3)的困难在于,创建新的渲染和可视化算法的工作非常重要,可能需要为每种非线性单元提供不同的解决方案。此外,在专用渲染硬件(例如,处理线性单元格)中发现的性能可能远远超过任何用于更高阶单元格的软件渲染解决方案。上面1)的困难是,镶嵌必须小心地执行,否则不可接受的错误会引入可视化。或者,如果单元格过度镶嵌,将导致过多的线性原语。未来的研究指向开发自适应方法,在选定的误差度量上细分(更多信息请参阅第8章)。

VTK采用固定细分对非线性二次元进行镶嵌,如图5 - 5所示。这通常适用于二次元单元,因为插值的阶数较低,并且定义单元的点数量较少。

二次边。二次元边是一个基本的一维单元。它由三点定义。前两点定义了边的端点;第三点位于边缘的中心,如图5 - 4所示。沿直线的方向是从第一点到第二点。

二次三角形。二次三角形是一个初等二维单元。它由6点定义。前三个点位于三角形的顶点上;下三个位于每条边的中间,如图5 - 4所示。

二次线性四边形。二次线性四边形是初等二维单元。它由6点定义。前四个点位于四边形的顶点上;下两个位于第一和第三条边的中间,如图5 - 4所示。

图5-5二次非线性单元格分解为线性单元格。将二次四面体镶嵌成六个线性四面体;二次六面体被镶嵌成八个线性六面体。

注意,一些镶嵌需要添加新的点。在VTK中,可以使用单元适配器框架对具有任意复杂度的基函数的单元进行镶嵌,有关更多信息,请参阅第8章。

二次四边形。二次四边形是一个初等二维单元。它由八个点定义。前四个点位于四边形的顶点上;接下来的四条位于每条边的中间,如图5 - 4

双二次四边形所示。双二次四边形是初等二维单元。它由9个点定义。前四个点位于四边形的顶点上;接下来的四个位于每条边的中间;最后一个点位于四边形的中心,如图5 - 4所示。

二次四面体。二次四面体是一个初生三维单元。它由10个点定义。前四个点位于四面体的顶点上;接下来的6个位于每条边的中间,如图5 - 4所示。

二次金字塔。二次金字塔是一个基本的三维单元。它由13个点定义。前五个点位于金字塔的顶点;下八个位于每八个边的中间,如图5 - 4所示。

二次线性楔形。二次线形楔形是一个初级的三维单元。它由12点定义。前六个点位于楔形的顶点;接下来的6条位于属于三角形面的6条边的每条边的中间,如图5 - 4所示。

二次楔。二次楔是一个原始的三维单元。它由15个点定义。前六个点位于楔形的顶点;接下来的9条位于9条边的中间,如图5 - 4所示

Bi-Quadratic楔。双二次楔形是一个初级的三维单元。它由18个点定义。前六个点位于楔形的顶点;接下来的9条位于9条边的中间;下三个位于每个四边形的中心,如图5 - 4所示。

二次六面体。二次六面体是一个初等三维单元。它由20个点定义。前八个点位于六面体的顶点上;下12条位于12条边的中间,如图5 - 4所示。

Bi-Quadratic六面体。双二次六面体是一个初等三维单元。它由24个点定义。前八个点位于六面体的顶点上;接下来的12条位于每条边的中间;后四个点位于前四个面中心,如图5 - 4所示。

Tri-Quadratic六面体。三二次六面体是一个初等三维单元。它由27点定义。前八个点位于六面体的顶点上;接下来的十二个位于每十二个边的中间;接下来的六个位于每个面的中心;最后一个位于六面体的中心,如图5 - 4所示。

5.5属性数据

属性数据是与数据集结构相关联的信息。该结构包括数据集几何结构和拓扑结构。通常,属性数据与数据集点相关联

或单元格,但有时属性数据可能分配给单元格组件,如边或面。属性数据也可以跨整个数据集分配,或者跨一组单元格或点分配。我们将此信息称为属性数据,因为它是数据集结构的属性。典型的例子包括某一点的温度或速度、单元的质量或进入和流出单元表面的热流。

属性数据通常分为特定类型的数据。这些类别是根据常见的数据表单创建的。可视化算法也根据它们所操作的数据类型进行分类。

单值函数(如温度或压力)是标量数据的示例,这是一种属性类型。一般来说,属性数据可以被视为n维数据数组。例如,单值函数温度可以被视为一个数组,而速度可以被视为x、y和z方向上的分量数组。这种抽象的数据属性模型可以在整个可视化系统中进行扩展。有些系统扩展了这个模型,以包括数据的结构。例如,一个3D图像数据集(即一个卷)可以表示为一个数据值的3D数组。非结构化数据可以表示为一个三维位置向量,加上一个连接数组。我们将这种通用方法称为可视化数据的超数据模型(参见第138页的“其他数据抽象”)。

在下面的章节中,我们将使用更简单的特定于类型的模型来描述数据属性(图5 - 6)。我们还将自己限制在三维结构,因为数据集结构和图形被假设是三维的。

标量

数据是数据集中每个位置的单个值。标量数据的例子有温度、压力、密度、海拔和股票价格。标量数据是最简单、最常见的可视化数据形式。

矢量

矢量数据是有大小和方向的数据。在三维空间中,这表示为值的三元组(u, v, w)。矢量数据的例子包括流速、粒子轨迹、风运动和梯度函数。

法线

法线是方向向量:也就是说,它们是大小为| n|=1的向量。图形系统经常使用法线来控制对象的阴影。一些算法也可以使用法线来控制单元格原语的方向或生成,例如从有方向的线创建条带。

纹理坐标

纹理坐标用于将点从笛卡尔空间映射到1维、2维或3维纹理空间。纹理空间通常被称为纹理映射。纹理映射是颜色、强度和/或透明度值的规则数组,为渲染对象提供额外的细节。

二维纹理的一个应用是将一张照片“粘贴”到一个或多个多边形上,从而产生一个不需要大量图形原语的详细图像。(纹理映射将在第7章中详细介绍。)

张量

张量是向量和矩阵的复杂数学推广。秩为k的张量可以被认为是k维表。秩为0的张量是一个标量,秩为1的张量是一个向量,秩为2的张量是一个矩阵,秩为3的张量是一个三维矩形数组。高阶张量是k维的矩形数组。

一般张量可视化是当前研究的一个领域。到目前为止,人们的努力都集中在二维的2秩张量上,也就是矩阵。这种张量最常见的形式是应力和应变张量,它们表示在负载下物体上某一点的应力和应变。VTK只处理实值对称张量。

5.6数据集类型

数据集由组织结构和相关属性数据组成。该结构具有拓扑和几何性质,由一个或多个点和单元组成。数据集的类型来源于组织结构,并指定单元格和点之间的关系。常见数据集类型如图5 - 7所示。

数据集的特征是根据其结构是规则的还是不规则的。如果组成点和单元之间存在单一的数学关系,则数据集是规则数据集。如果这些点是规则的,那么数据集的几何结构也是规则的。如果单元格的拓扑关系是规则的,则数据集的拓扑是规则的。常规(或结构化)数据可以隐式表示,这大大节省了内存和计算。不规则(或非结构化)数据必须显式地表示,因为没有可以紧凑描述的固有模式。非结构化数据往往更通用,但需要更大的内存和计算资源。

  • 多边形数据

我们已经看到图形库是如何被设计来渲染诸如直线和多边形这样的几何原语的。这些原语也经常由计算几何和可视化算法生成或使用。在可视化工具包中,我们称此图形原语集合为多边形数据。多边形数据集由顶点、多边形、线、折线、多边形和三角形条组成。多边形数据的拓扑和几何结构是非结构化的,组成该数据集的单元格在拓扑维度上有所不同。多边形数据集形成了数据、算法和高速计算机图形之间的桥梁。

顶点、直线和多边形构成了表示0维、1维和2维几何图形的最小基元集。为了方便、紧凑和性能,我们包含了多顶点、折线和三角形条形单元格。特别是三角形条带是高性能的原语。用三角形条表示n个三角形只需要n+2个点,而传统表示需要3n个点。此外,许多图形库可以以比三角形多边形更快的速度渲染三角形条带。

图5-7数据集类型非结构化网格由所有单元格类型组成。

我们的最小单元格选择是基于常见的应用程序和性能,代表一些图形库中可用的单元格的子集。其他类型包括四边形网格,Bezier曲线和曲面,以及其他样条类型,如NURBS(非均匀有理b样条)[Mortenson85]。样条曲面通常用于精确地建模和可视化几何。很少有可视化算法(除了几何可视化)开发需要样条曲面。

图像数据

图像数据集是一个点和单元格的集合,排列在一个规则的矩形点阵上。晶格的行、列和面平行于全局x-y-z坐标系。如果点和单元格排列在一个平面上(即二维),则数据集被称为像素图、位图或图像。如果点和单元格被排列成堆叠的平面(即,三维),则数据集被称为体积。请记住,术语图像数据是指图像、卷或一维点数组的集合。请注意,一些作者将图像数据称为统一网格和结构化点。(结构化点是VTK早期版本中使用的术语。)

图像数据由线元素(1D)、像素(2D)或体素(3D)组成。图像数据在几何和拓扑上都是规则的,可以隐式表示。表示方案只需要数据维度、原点和数据间距。数据的维度是一个3-向量,指定x、y和z方向上的点的数量。原点是最小x-y-z点在三维空间中的位置。图像数据集中的每个像素(2D)或体素(3D)在形状上是相同的,间距指定在x-y-z方向上的长度。

图像数据集的拓扑和几何结构的规则性质表明了一个自然的i-j-k坐标系统。数据集中的点的数量是,而单元格的数量是。可以通过指定三个索引i-j-k来选择特定的点或单元格。类似地,通过指定三个索引中的两个来定义线,通过指定单个索引来定义平面。

表示的简单和紧凑是图像数据的理想特征。它是一种有效的遍历和计算结构。因此,图像数据是唯一可与多边形数据相媲美的最常见的可视化数据集形式。图像数据的主要缺点是所谓的“维数诅咒”。为了获得更高的数据分辨率,我们必须增加数据集的维度。增加图像的维度会导致内存需求增加O(n2),而卷则需要增加O(n3)。因此,使用图像数据解析一个小特征可能需要比可用的更多的磁盘空间或计算机内存。

图像数据集经常用于成像和计算机图形学。大量数据经常由医疗成像技术生成,如计算机断层扫描(CT)和磁共振成像(MRI)。有时体积被用来取样数学函数或数值解。

  • 矩形网格

直线网格数据集是排列在规则网格上的点和单元格的集合。晶格的行、列和面平行于全局x-y-z坐标系。虽然nx ny nz (),, nx ny nz´´nx () - 1 ny´()- 1 nz´()- 1 5.6数据集类型137数据集的拓扑是规则的,但几何结构只是部分规则的。也就是说,点沿坐标轴对齐,但点之间的间距可能会变化。

像图像数据集一样,直线网格由像素(2D)或体素(3D)组成。拓扑通过指定网格尺寸隐式表示。几何图形通过维护一个单独的x、y和z坐标列表来表示。要获得特定点的坐标,必须适当地组合这三个列表中的每个值。

结构化网格

结构化网格是具有规则拓扑和不规则几何结构的数据集。网格可以扭曲成单元不重叠或自交的任何构型。

结构化网格的拓扑结构通过指定3维向量隐式表示。几何图形通过维护点坐标数组显式表示。结构化网格的组成单元是四边形(2D)或六面体(3D)。像图像数据一样,结构化网格有一个自然的坐标系统,允许我们使用拓扑i-j-k坐标引用特定的点或单元。

结构化网格常用于有限差分分析。有限差分是一种近似偏微分方程解的数值分析技术。典型的应用包括流体流动、传热和燃烧。

非结构化点

非结构化点是指空间中不规则分布的点。在非结构化点数据集中没有拓扑,并且几何结构是完全非结构化的。顶点和多顶点单元格用于表示非结构化点。

非结构化点是一种简单但重要的数据集类型。数据通常没有固有的结构,可视化任务的一部分就是发现或创建数据。例如,考虑一个装有温度表的汽车活塞。量规的数量和位置选择在有限的点集上,导致在活塞表面“不相关”(至少在可视化拓扑方面)位置上的温度值。为了可视化表面温度,我们必须创建一个插值表面和方案来填充中间值。

非结构化点用于表示这种非结构化数据。通常,为了可视化的目的,将此数据表单转换为另一种更结构化的表单。将非结构化点转换为其他形式的算法在第355页的“可视化非结构化点”中有描述。

非结构化网格数据集

最常见的形式是非结构化网格。拓扑和几何都是完全非结构化的。任何单元格类型都可以在非结构化网格中任意组合。因此,单元格的拓扑范围从0D(顶点,多顶点)到3D(四面体,六面体,体素)。在可视化工具包中,任何数据集类型都可以表示为非结构化网格。我们通常只在绝对必要时才使用非结构化网格来表示数据,因为这种数据集类型需要最多的内存和计算资源来表示和操作。nx nz nz(),,, 138基本数据表示

非结构化网格在有限元分析、计算几何和几何建模等领域中被发现。有限元分析是偏微分方程的数值求解技术。有限元分析的应用包括结构设计、振动、动力学和传热。(这与偏微分方程的有限差分分析相比。有限元分析的一个优点是消除了规则拓扑的约束。因此,复杂的域可以更容易地网格化。)

5.7其他数据抽象

除了这里介绍的数据集模型之外,还提出了其他数据模型。我们简要地考察了另外两个已经成功应用的模型。它们是AVS领域模型和Haber、Lucas和Collins的模型,商业IBM Data Explorer系统对它们进行了修改。本节最后对这两个模型和VTK的数据模型进行了简要的比较。

应用可视化系统

AVS(应用可视化系统)是第一个大规模的商业可视化系统[AVS89]。可视化技术的早期发展、可见性和成功应用,很大程度上是由于AVS的直接应用或AVS对其他研究人员的影响。AVS是一个数据流可视化系统,具有简洁的用户界面,可以创建、编辑和操作可视化网络。使用显式执行来控制网络的执行,AVS可以运行分布式和并行可视化应用程序。由于AVS架构是开放的,研究人员和开发人员可以捐赠过滤器供他人使用。

AVS数据模型由原始数据和聚合数据组成。基本数据是字节、整数、实数和字符串等数据的基本表示形式。聚合类型是基本类型的复杂组织,包括字段、颜色映射、几何图形和像素映射。字段可以被认为是AVS的基本数据类型,稍后将详细描述。颜色映射用于将函数值(即标量值)映射为颜色和透明度值。几何图形由点、线和多边形等图形原语组成,并由几何渲染器用于显示对象。像素映射是可视化的渲染图像或输出。

字段是AVS数据模型中最有趣的部分。一般来说,它是一个n维数组,每个点上都有标量或矢量数据。标量是单个值,而向量是两个或多个值(不一定是三个)。字段数组可以有任意数量的维度,维度可以是任意大小。字段没有隐式结构,而是定义了一个映射函数。也就是说,指定从数据元素到坐标点的隐式或显式关系。因此,字段是两种空间之间的映射:字段数据的计算空间和坐标空间,后者通常是全局坐标系。AVS支持三种类型的映射:统一映射(即结构化映射)、直线映射和不规则映射(即非结构化映射)。

数据浏览器

Haber, Lucas和Collins [Haber91]的数据模型是基于纤维束的数学。他们的工作目标是在5.7其他数据抽象139规则和不规则网格上为字段的分段表示创建一个通用模型。他们将自己的模型称为字段数据模型,但是他们对字段这个词的定义与AVS模型不同。字段是由基本数据和相关数据组成的对象。非正式地说,基是一个流形,其坐标是场的自变量,因变量的值与基的自变量相关联。可视化数据由描述局部区域基础变量和因变量的场元素组成。

可视化工具集

这些数据模型与VTK的数据集模型有相似之处,也有不同之处。最大的不同是,这些其他模型更抽象。它们能够表示更广泛的数据,并且更加灵活。特别是,AVS字段模型能够以简单而优雅的方式表示任意的数字流。Haber等人的现场数据模型也很强大:作者展示了如何使用该数据表示来利用数据中的规律性来获得紧凑表示。另一方面,所有这些模型(包括VTK)都共享结构与数据的概念。AVS场模型通过映射函数引入结构。Haber等人的现场数据。模型类似于VTK的数据集模型,其中基相当于VTK的单元,字段数据模型的依赖数据类似于VTK的属性数据。

抽象层次的差异在可视化系统的设计中提出了重要的问题。在下面的讨论中,我们将数据模型称为抽象模型或具体模型,其中具体模型的相对抽象级别较低。抽象类和具体类比较如下:

•抽象模型比具体模型更灵活,能够表示更广泛的数据形式。

•抽象模型适用于紧凑的计算机代码。

•具体模型比抽象模型更容易描述、接口和实现。

•抽象级别影响计算机代码和/或数据模型的数据库接口。抽象的模型导致抽象的代码和数据表示;具体的模型产生具体的代码和数据表示。

•可以通过创建更简单的、特定于应用程序的接口来隐藏抽象模型的复杂性。然而,这需要额外的努力。另一方面,具体模型不能通过修改接口而变得更加抽象。

计算机系统的设计要求仔细注意抽象系统和具体系统之间的平衡。特别是可视化系统,必须仔细设计,因为它们与其他系统和数据模型有接口。过于抽象的模型会导致计算机代码和界面混乱,并且可能因为用户的误解而被误用。另一方面,具体模型的灵活性和能力有限,但往往更容易学习和应用。

在可视化工具包的设计中,我们选择使用相对于AVS和现场数据模型的更具体的数据模型。我们的决定是基于这样一个前提,即系统既要提供信息,又要具有功能,我们希望清楚地演示基本概念。另一方面,VTK的数据模型足够通用,可以支持我们的可视化实践。我们对用户的经验也告诉我们,VTK的数据模型对于普通的可视化用户来说更容易

图5-8连续阵列实现。这个例子是类定义vtkFloatArray的一个片段。

要比抽象的模型更容易理解。如果您决定设计自己的系统,我们建议您检查其他数据模型。然而,我们认为可视化工具包中代码的清晰性是设计抽象和简单性之间平衡的一个例子。

5.8把一切放在一起

在本节中,我们将描述前面介绍的数据集类型的实现细节。我们还将通过各种c++示例向您展示如何创建这些数据集。

内存分配和数据数组

由于数据的大小和范围,必须仔细管理内存以创建有效的可视化系统。在可视化工具包中,我们使用连续的数据数组作为大多数数据结构的基础。连续数组的创建、删除和遍历速度比其他数据结构(如链表或指向结构的指针数组)更快。在VTK中,我们将这些称为数据数组,并使用类vtkDataArray表示它们。

连续数组也可以很容易地在网络上传输,特别是当数组中的信息与计算机内存地址无关时。内存独立性避免了将信息从一个内存位置映射到另一个内存位置的开销。因此,在VTK中,我们基于“id”访问信息,这是一个数组类对象的整数索引。数据数组是0偏移量,就像c++数组一样。也就是说,给定n个数据值,我们使用id依次访问这些值。

一个重要的设计决策是不使用对象数组表示数据(例如,单元格和/或点的单独类)。我们的经验表明,由于建造和删除的成本,这样的设计严重影响性能。相反,我们专注于在更高抽象级别上设计类。从性能的角度来看,面向对象方法在应用程序级别服务最好,而不是在实现级别。

类vtkFloatArray是一个连续数组的例子。我们将使用这个类来描述如何在VTK中实现连续数组。如图5 - 8所示,实例变量Array是一个指向float类型内存的指针。数组的分配长度由Size给出。该数组是动态的,因此尝试插入超出分配大小的数据会自动生成Resize()操作。当调整大小时,数组的大小每次大约增加一倍。浮点数组;int大小;int MaxId;int NumberOfComponents;char *名称;图5-8连续阵列实现。这个例子是类定义vtkFloatArray的一个片段。f0 f1 f2 fn-2 fn-1 Size (n) MaxId组件数量()012,,,,¼n1 - 5.8组合141 MaxId字段是一个整数偏移量,定义插入数据的结束。如果没有插入数据,则MaxId等于-1。否则,MaxId为整数值,其中。

元组抽象

许多可视化数据是由多个组件值定义的。x-y-z坐标三联体或RGBA颜色像素值就是这样的两个例子。为了在连续的数据数组中表示这些数据,引入了元组数据抽象。如图5 - 8所示,连续数组被分组为使用NumberOfComponents组件的更小的子数组。这些子数组称为元组,对于给定的数组,元组大小或NumberOfComponents对于所有元组都是常量,如图5 - 9所示。

用数据数组表示数据

属性数据和点,以及其他一些数据对象,在VTK中用数据数组表示。某些属性数据,如点、向量、法线和张量,需要具有与其定义一致的元组大小。例如,点、向量和法线要求一个元组大小为3的数据数组;张量是大小为9的元组(即一个矩阵)。标量对元组大小没有任何要求。处理此类标量数据的算法通常对每个元组的第一个组件进行操作。(VTK中存在过滤器,用于将多组件数据数组拆分为单独的数组,并将单独的数据数组合并为单个数组。参见vtkSplitField和vtkMergeFields。)

抽象/具体数据数组对象

可视化数据有多种形式——浮点数、整数、字节和双精度——仅举几个简单的类型。更复杂的类型(如字符串或多维标识符)也是可能的。既然有这么多种类型,我们如何使用数据数组表示和操作这些数据呢?答案是通过抽象数据对象提供运行时解决方案,使用模板化c++代码提供编译时解决方案。

抽象数据对象是使用动态绑定提供统一方法来创建、操作和删除数据的对象。在c++中,我们使用virtual关键字将方法声明为动态绑定。动态绑定允许我们通过操作具体对象的抽象超类来执行属于该对象的方法(参见图5 - 10)。

考虑抽象类vtkDataArray。我们可以通过执行方法double s = GetTuple1(129)来访问关联点id为129的数据值。由于虚拟GetTuple1()方法返回一个浮点数据值,因此vtkDataArray的每个子类也必须返回一个浮点值。尽管子类可以自由地以任何可能的形式表示数据,但它必须将其数据表示转换为浮点值。这个过程可能像从内置类型转换一样简单

图5-10数据阵列对象示意图。vtkDataArray是一个抽象基类。vtkDataArray的子类实现了类型特定的表示和操作。注意:并不是所有具体的数据数组子类都显示在这个图中。

类型转换为浮点值,或者可能是数据的复杂映射。例如,如果我们的数据由字符串组成,我们可以创建一个字母列表,并将字符串映射到列表中的位置,然后将位置转换为双精度值。

虽然这个面向运行时的接口便于编写不依赖于特定数据类型的通用算法,但将本机表示转换为双类型是有问题的。首先,转换操作会对性能产生不利影响,因为频繁调用数据访问方法,虚拟函数比内联或非虚拟调用慢,而且在许多情况下,强制转换操作符很慢。其次,像double这样的复杂类型在转换为double的过程中会失去精度。为了解决这些问题,可以以原生形式访问数据并相应地进行处理。在这种方法中使用c++模板。

要使用模板,必须获得原始的、类型化的数据指针,并了解数据的类型。vtkDataArray及其相关子类提供了此功能。有了这些信息,就可以将数据类型转换为基于该类型的模板函数。使用此功能的典型代码片段可以在大多数成像过滤器中找到,几乎所有的图像过滤器都是如下模板化的:

图5-11数据对象表示为字段数据。字段可以表示为数组的数组。每个数组都有指定的类型、长度、元组大小和名称。数据数组与点或单元格的关联,以及它作为特定属性类型的标记,形成了点和单元格属性数据。

在实践中,使用宏简化了这段代码,并且static_cast<>c++操作符用于执行强制转换。注意,函数func是一个模板函数。编译器将为适当的类型实例化函数。在大多数情况下,所有本机类型都在switch语句中表示,因此func进行了相应的扩展。

使用面向编译时的方法(如模板)可以避免将每个数据访问转换为特定类型(例如,double)。虽然它确实使代码有些复杂,并导致更大的目标代码,但它通常比运行时虚拟方法快。随着类型数量的增加,这种方法就会出现问题。例如,一些过滤器(如vtkImageShiftScale)使用双重嵌套模板来解决输入和输出类型的潜在差异。代码比通用的运行时方法更复杂、更大。

数据对象表示

数据对象在VTK中以vtkdataarray数组的形式实现,如图5 - 11所示。vtkDataObject是可视化数据的通用表示。它用于封装实例变量和可视化网络执行的方法(参见前一章),以及表示数据。在内部,数据用类vtkFieldData的实例表示。很少有算法直接操作数据对象;相反,大多数算法都需要一个组织结构的规范来处理数据。数据集将按照以下部分中的描述指定组织结构。

数据集表示

在VTK中实现了五个数据集:vtkPolyData、vtkImageData、vtkStructuredGrid、vtkrectanglineargrid和vtkUnstructuredGrid。非结构化点数据集没有实现,但可以使用vtkPolyData或vtkUnstructuredGrid表示。

我们为每种数据集类型使用不同的内部数据表示。通过使用不同的表示形式,我们可以最小化数据结构内存需求并实现高效的访问方法。可以使用vtkUnstructuredGrid来表示所有数据集类型,但是内存和计算开销对于大数据来说是不可接受的。下面几节描述如何表示数据集。字段数据:数组的数组。每个数组可以是不同的数据类型。图5-11数据对象作为字段数据的表示字段可以表示为数组的数组。每个数组都有指定的类型、长度、元组大小和名称。数据数组与点或单元格的关联,以及它作为特定属性类型的标记,形成了点和单元格属性数据。144基本数据表示。

最简单和最紧凑的表示是vtkImageData。数据集点和单元格都是通过指定维度、数据间距和原点隐式表示的。维度定义数据集的拓扑结构,而原点和间距指定几何形状。vtkImageData数据集类型可以表示1D直线样本、2D图像和3D卷。(注:在VTK的早期版本中,vtkImageData被称为vtkStructuredPoints。在代码库中仍然有这个术语的残余。)

组成vtkImageData的点和单元格都有一个隐式的顺序。单元格和点都按照递增x、y、z的方向进行编号。总的点数是其中nx、ny和nz是vtkImageData的维数。单元格总数为。

vtkRectilinearGrid。虽然vtkrectifier grid的拓扑结构是规则的,但其几何结构可以描述为“半规则”。通过沿着x、y和z坐标轴指定数据维度,可以隐式地表示拓扑。几何图形是使用沿着这些轴的三个坐标值数组定义的。这三个坐标数组可以组合在一起,以确定数据集中任何点的坐标。在VTK中,我们使用三个vtkDataArray实例来表示数组。点和单元格的编号是隐式的,与描述vtkImageData的方式完全相同。

vtkStructuredGrid。像vtkImageData一样,vtkStructuredGrid的拓扑结构是规则的,并通过在拓扑i-j-k坐标系统中指定维度来定义。然而,vtkStructuredGrid的几何结构是通过在全局x-y-z坐标系中指定点坐标来实现的。

抽象数据类vtkPoints用于表示点坐标。vtkPoints引用了vtkDataArray的底层实例,该实例实际上将点的表示形式保存为连续的三组件元组数组。通过指定特定的点id,可以检索或插入特定的点坐标。点和单元格的编号与vtkImageData的方式相同。必须注意确保数据数组中的点数量与网格维度所暗示的点数量相同。

vtkPolyData。与vtkImageData和vtkStructuredGrid不同,vtkPolyData的拓扑结构不是规则的,因此必须显式地表示数据集的拓扑和几何结构。vtkPolyData中的点数据使用类似于vtkStructuredGrid的vtkPoints类表示。可视化工具包使用类vtkCellArray显式地表示单元拓扑。该类是每个单元格的连通性列表。列表的结构是一个整数序列(图5 - 12)。列表中的第一个数字是一个计数(单元格连通性中的点数),接下来的一系列数字是单元格连通性。(每个数字在连接

图5-12 vtkCellArray结构表示cell拓扑

List是指向点坐标列表实例的索引。)count序列后面跟着连通性列表,直到枚举每个单元格。其他信息,如列表中的单元格数量和列表中的当前位置(用于遍历)也由vtkCellArray维护。

注意,类型信息在这个结构中没有直接表示。相反,vtkPolyData维护顶点、直线、多边形和三角形条的四个独立列表。顶点列表表示类型为vtkVertex和vtkPolyVertex的单元格。行列表表示类型为vtkLine和vtkPolyLine的单元格。多边形列表表示类型为vtkTriangle、vtkQuad和vtkPolygon的单元格。三角形条带列表表示单一类型vtkTriangleStrip的单元格。因此,通过定义单元格的特定列表,加上定义单元格的点数,就可以知道单元格类型。

我们对vtkPolyData类的设计基于两个重要的需求。首先,我们想要一个有效的外部图形库接口。其次,我们希望根据拓扑结构聚合单元格。这四个独立的列表提供了高效的界面,因为图形库有独立的顶点、直线、多边形和三角形条带原语。因此,在VTK中不需要运行时检查来匹配不同的单元格类型与适当的“加载原语”函数,因为类型是从原语所在的列表中已知的。这四个列表还将单元格分为0维、1维和2维类型。这很有用,因为可视化算法通常以不同的方式处理不同拓扑顺序的数据。

vtkUnstructuredGrid。就其表示拓扑和几何结构的能力而言,数据集类型vtkUnstructuredGrid是最通用的。点和单元格都使用vtkPoints和vtkCellArray的派生类显式表示。类vtkUnstructuredGrid类似于vtkPolyData,除了vtkUnstructuredGrid必须能够表示所有单元格类型,而不仅仅是vtkPolyData的有限图形类型(即顶点、线、多边形和三角形条)。

vtkUnstructuredGrid的另一个显著特征是我们以不同的方式表示类型信息。在vtkPolyData中,我们将单元格分为四个单独的列表,从而间接表示单元格类型。在vtkUnstructuredGrid中,我们添加了额外的类vtkCellTypes来显式地表示单元格类型。

vtkCellTypes是一个补充信息数组。对于每个单元格,一个整数标志定义单元格类型。另一个变量用于记录单元格定义在相应的vtkCellArray中的位置(图5 - 13)。

除了表示单元类型外,这种设计还允许随机访问单元。由于单元格连接列表的长度不同,如果不从原点遍历特定单元格的数据结构,vtkCellArray类就无法定位特定单元格。然而,通过添加类vtkCellTypes,可以通过单个解引用(即使用偏移值)直接访问单元格。

vtkCellTypes也可以添加到vtkPolyData数据表示中——事实上已经添加了。然而,我们添加这一项的原因并不是显式地表示类型,而是提供对单元格的随机访问并支持许多拓扑操作。我们将在第8章进一步阐述这个观点。

对象模型。5个数据集实现如图5 - 14所示。正如这个对象图所示,这些具体数据集是抽象类vtkDataSet的子类。还引入了另外两个类。类vtkStructuredData为结构化数据提供实例变量和方法。类的structureddata没有继承关系

图5-13 vtkUnstructuredGrid类的数据结构。(这是整个结构的子集。

详情见第八章。)

图5-14数据集对象图。五个数据集(阴影部分)在VTK中实现。

数据集;相反,所示的结构化数据集委托给它以实现它们的一些方法。(这样做是为了避免多重继承。)类vtkPointSet的子类显式地表示它们的点,即通过vtkPoints的实例或它的子类。vtkPointSet提供了操作点数据的方法和实例变量,以及查找点和单元格的通用搜索功能。(更多信息见297页的“搜索”。)

图5-15 VTK中20种具体单元类型的对象图。vtkEmptyCell表示NULL单元格。vtkGenericCell可以表示任何类型的单元格。三维单元格是vtkCell3D的子类。高阶单元格是vtk非线性单元格的子类。

  • 单元表达法

在可视化工具包中,每个单元格类型都是通过创建特定的类来实现的。每个单元格都是抽象类型vtkCell的子类。单元格拓扑由一组有序点id表示,单元格几何由一组点坐标表示。vtkCell及其子类的对象图如图5 - 15所示。

抽象类vtkCell指定每个单元必须实现的方法。这些方法为单元的几何和拓扑提供了一个已定义的接口。其他方法在单元格上执行计算。这些方法将在第8章中详细讨论。

数据属性

数据属性与数据集的结构相关联。数据集模型是建立在点和单元格上的,因此将数据属性与点和单元格相关联是很自然的。中间结构特征,如单元格边缘或面,没有显式表示,因此我们不能轻易地将数据属性与它们关联起来。

在VTK中,数据属性与数据集的点和单元格相关联。数据属性与中间拓扑特征(如三角形边或六面体面)没有关联。(这里我们将与点关联的数据属性称为点属性,将与单元格关联的数据属性称为单元格属性。)我们的设计选择基于以下基本原理。vtkPolygon vtkHexahedron vtkPolyLine vtkLine vtkQuad vtkTriangleStrip vtkTetra vtkTriangle vtkCell vtkVoxel vtkVertex vtkPolyVertex vtkPixel vtkEmptyCell图5-15 VTK中20种具体单元格类型的对象图vtkEmptyCell表示NULL单元格。vtkGenericCell可以表示任何类型的单元格。三维单元格是vtkCell3D的子类。高阶单元格是vtk非线性单元格的子类。148基本数据表示

•数据采集和数值模拟系统通常在点位置或单元的中心测量和/或计算结果。

•边界属性信息(例如,在面和边上)可以维护为根据单元的拓扑结构排序的单元数据。

•VTK数据模型是基于点和单元的原因紧凑和效率。在单元边界上表示属性数据需要扩展这种表示,以支持少量需要在单元边界上直接支持属性数据的情况。如果将来需要更复杂的数据结构来表示边界属性数据,最好将其封装到单个类中,而不是强制在整个系统中进行抽象。

维护单元格数据和点数据表示的一个困难是数据中可能出现不一致。例如,如果单元格的标量值是0.5,而它的点的标量值不是0.5,那么哪个是正确的值?虽然用户必须认识到可能存在这种不一致的情况,但可以设计优先次序方案来解决这种情况。

为了表示数据集属性,我们使用组织类vtkPointData和vtkCellData,它们都是类vtkFieldData的子类,如图5 - 16所示。类vtkDataSetAttributes用于协调数据从一个进程对象到下一个进程对象的移动。它提供了在输入和输出之间复制、内插和移动数据的方法。vtkDataSetAttributes的另一个重要特性是,它提供了为表示特定数据属性分配数据数组的能力。例如,SetScalars()方法用于指定将哪个数据数组作为字段中的标量。

每个数据集点与其属性数据之间存在一一对应关系。点属性是通过点id访问的。例如,要访问数据集实例aDataSet中点id 129的标量值,我们使用

该语句假定标量数据已为此数据集定义,且为非NULL。

  • 示例

在接下来的例子中,我们将展示手动创建和操作数据集。通常,这些操作不是由VTK的用户直接执行的。相反,源对象用于读取数据文件或生成数据。这比这里显示的手动技术更方便,应该尽可能使用。

数据集的创建是一个两步过程。首先必须定义数据集的几何结构和拓扑结构。根据数据集的类型,几何和拓扑定义将以不同的方式进行。然后创建点和/或单元格属性数据并与数据集关联。请记住,属性数据与数据集中的点和单元格之间是一对一的关系。

图5-17多边形立方体的创建(立方体。cxx)。

创建多边形数据集。在第一个例子中,我们创建了一个立方体的多边形表示。立方体由8个点和6个四边形面组成。我们还创建了与立方体的八个顶点相关联的八个标量值。图5 - 17显示了用于创建数据的关键c++代码片段以及生成的图像。

多维数据集的几何形状是使用类vtkPoints的实例定义的。默认情况下,vtkPoints的底层类型是vtkFloatArray。多维数据集(即多边形)的拓扑是用类vtkCellArray的实例定义的。它们分别定义立方体的点和多边形。标量数据由类vtkIntArray的实例表示。

如本例所示,多边形数据是通过构造片段(例如,点、单元格和点属性数据)来创建的,然后将这些片段组装起来以形成完整的数据集。如果vtkPolyData实例的名称是cube,那么我们可以将这三个步骤总结为:

1.执行以下命令。创建vtkPoints子类的实例来定义几何(即点坐标)。使用操作符立方体->SetPoints()将点与数据集关联起来。vtkPolyData图5-17多边形立方体创建(cube . data)cxx)。vtkPolyDataMapper vtkPolyData *cube = vtkPolyData::New();vtkPoints *points = vtkPoints::New();vtkCellArray *polys = vtkCellArray::New();vtkFloatArray *scalars = vtkFloatArray::New();(我= 0;i< 8;我+ +)点→InsertPoint(我x[我]);(我= 0;i< 6;我+ +)多边形→InsertNextCell(4分(我));(我= 0;i< 8;我+ +)标量→InsertTuple1(我);立方体→定位点(点);点→删除();立方体→SetPolys(多边形);多边形→删除();立方体→GetPointData()→SetScalars(标量);标量→删除();150基本数据表示法

2.创建vtkCellArray实例来定义顶点、直线、多边形和三角形带的拓扑结构。使用运算符cube-> setvert()、cube->SetLines()、cube->SetPolys()和cube-> setstripes()将单元格与数据集关联起来。

3.创建点和/或属性数据。每个数据集都有两个字段,分别表示vtkPointData和vtkCellData。使用操作符pd=cube->GetPointData()检索指向点属性数据的指针。使用操作符pd=cube->GetCellData()检索到单元格属性数据的指针。使用操作符pd-> SetScalars(), pd->SetVectors(), pd->SetNormals(), pd->SetTensors()和pd->SetTCoords()将属性数据与数据集关联起来(对于单元格数据也类似)。

多边形数据支持以下单元格类型:顶点、多顶点、直线、折线、三角形、四边形、多边形和三角形条。不需要定义点和单元格属性数据——可以不创建点和单元格属性,也可以创建部分或全部的点和单元格属性。

本例中最令人困惑的地方是Delete()方法。为了防止内存泄漏,我们必须在每个New()方法之后使用Delete()方法(VTK的析构函数)。从示例中可以明显看出,实例的点、多边形和标量由另一个对象(例如立方体)引用。那么,调用Delete()方法不会产生问题吗?

答案是否定的。VTK中的某些数据对象被引用计数以保存内存资源(即,vtkObjectBase的子类)。这意味着它们可以在对象之间共享。对于大多数对象,Delete()将调用析构函数。引用计数对象的行为略有不同。Delete()方法只是减少引用计数。这可能会破坏对象,也可能不会,这取决于它是否正在被另一个对象使用。在本例中,点、多边形和标量由多边形数据集多维数据集使用,因此在调用Delete()时不会删除它们。一旦我们释放数据集多维数据集,也就是说,当它们的引用计数降为零时,它们就会被释放。(有关内存管理的更多信息,请参阅VTK用户指南。)

创建一个图像数据集。在本例中,我们创建了一个图像数据集(即vtkImageData的一个实例)。数据集的拓扑是通过指定数据维来定义的。几何形状由数据间距和原点定义。间距指定每个体素的长、宽和高。原点指定数据的“左下角”在3D空间中的位置。

在我们的例子中,我们设置了数据集的原点和间距,使其中心位于原点,数据集的边界为(-0.5,0.5,-0.5,0.5,-0.5,0.5)。在本例中,我们在创建图像数据集的同时创建标量数据。标量值是从球面的隐式函数计算出来的

用半径。标量数据存储在vtkFloatArray的一个实例中,并分配给数据集的点属性数据。

为了完成这个示例,使用轮廓过滤器来生成标量值的曲面。请注意,这个功能(以更通用的形式)可以从源对象vtkSampleFunction与vtkSphere结合使用。图5 - 18显示了用于创建数据和标量字段轮廓的关键c++代码片段,以及生成的图像。

由于图像数据集的几何和拓扑都是隐式定义的,因此易于构造。如果vtkImageData实例的名称是vol,我们可以将创建数据集的步骤总结如下:

1.Fxyz (),, x 2 y 2 z2 () + + r2 = - R0.4= Fxyz(),, = 0 5.8将它全部放在一起151 1。使用vol->SetDimensions()操作符定义数据集的拓扑结构。

2. 使用操作符vol->SetOrigin()和vol->SetSpacing()定义数据集的几何形状。

3.创建点和/或属性数据,并将其与数据集关联。

您不需要指定原点和数据间距。默认情况下,在x-yz方向上的数据间距为(1,1,1),原点为(0,0,0)。因此,如果数据集的维度为,则数据集的默认长度、宽度和高度将为。

数据集的拓扑维度可以从它的实例变量中隐式地知道。例如,如果任何一个维度等于1(而其他两个维度大于1),则数据集的拓扑维度为2。

创建一个结构化网格数据集。在下一个示例中,我们创建一个vtkStructuredGrid数据集。拓扑是从数据集的维度隐式定义的。通过提供一个对象来表示点坐标,显式地定义了几何图形。在本例中,我们使用了vtkPoints的一个实例,并假设结构化网格根据圆柱体的方程进行了扭曲

我们任意选择切向方向上的点数为13,径向方向上的点数为11,轴方向上的点数为11(即维度为)。

矢量是在圆柱体的切线方向上生成的,其大小与半径成正比。为了显示数据,我们在每个点上画小的,有方向的线,如图5 - 19所示。(这种技术被称为刺猬。更多信息请参见第173页的“刺猬和定向字形”。)

结构化网格数据集的创建部分显式,部分隐式。几何图形是通过创建vtkPoints实例显式创建的,而拓扑是通过指定数据集维度隐式创建的。如果vtkStructuredGrid实例的名称是sgrid,则使用以下三个步骤来创建它。

1. 通过创建一个vtkPoints实例来指定数据集的几何形状。使用操作符sgrid- >SetPoints()将这些点与数据集关联起来。

2. 使用操作符sgrid->SetDimensions()指定数据集拓扑。确保在上面第1项中创建的点数等于隐含的点数。

3.创建点和/或单元格属性数据,并将其与数据集关联。

数据集的拓扑维数由指定的维数表示。例如,如果任何维度(nx, ny, nz)等于1,则数据集的拓扑维度为2。如果三个维度中的两个(nx, ny, nz)等于1,则数据集的拓扑维度为1。

图5-18创建镜像数据集标量数据是由一个球的方程生成的。

体积尺寸为26 3

(Vol.cxx)

图5-19创建半圆柱体的结构化网格数据集矢量被创建,其大小与半径成正比,并以切向为导向(SGrid。cxx)。

创建一个直线网格数据集。直线网格在拓扑上是规则的,在几何上是半规则的。与结构化网格或图像数据集类似,拓扑通过指定网格尺寸隐式表示。由于网格是轴对齐的,但每个轴上的点坐标可能不同,因此我们需要三个数据数组来表示数据集的几何形状,x-y-z轴每个数组对应一个。注意,直线数据集的单元格类型是像素和体素。

为了在创建直线网格时获得最大的灵活性,在VTK中我们使用三个vtkDataArray对象来定义轴数组。这意味着每个轴可以使用不同的本机数据类型(例如,unsigned char、int、float等)。

为了总结创建vtk直线型网格实例的过程,我们遵循四个步骤。在这个例子中(如图5 - 20所示),我们假设vtkrectifier实例的名称是rgrid。

1. 通过创建三个vtkDataArray实例来创建数据集几何结构,每个实例对应xy-z坐标轴。我们假设每个标量中的值的数量是nx、ny和nz。

2. 分别使用rgrid-> SetXCoordinates()、rgrid->SetYCoordinates()和rgrid->SetZCoordinates()方法将这三个实例分配到x、y和z轴。

3.使用操作符rgrid->SetDimensions()指定数据集拓扑。确保在上面第1项中创建的点数等于隐含的点数。

4. 创建点和/或单元格属性数据,并将其与数据集关联。

数据集的拓扑维数由指定的维数表示。例如,如果任何维度(nx, ny, nz)等于1,则数据集的拓扑维度为2。如果三个维度中的两个(nx, ny, nz)等于1,则数据集的拓扑维度为1。创建一个非结构化网格数据集。非结构化网格数据集是拓扑和几何中最常用的数据集类型。

在这个例子中,我们使用vtkUnstructuredGrid实例“人为地”创建了一个非结构化网格(图5 - 21)。网格包含除像素和体素外的每种单元格类型的示例。(像素和体素通常用于内部处理图像数据集。只要观察到所需的点几何关系,就可以显式地创建和操作它们。)创建数据集结构需要创建点来定义几何结构,并创建各种单元来定义拓扑。(请注意,在有限元世界中,我们将它们称为节点和元素。)

为了总结创建vtkUnstructuredGrid实例的过程,我们遵循五个步骤。我们假设vtkUnstructuredGrid实例的名称为ugrid。

1. 为数据集分配内存。使用操作符ugrid->Allocate()。该操作符接受两个与数据大小相关的可选参数。第一个是连接列表的大小,第二个是扩展存储的数量(如果需要的话)。根据经验,使用单元格数量乘以为两个参数定义每个单元格的平均点数。这些参数的确切值并不重要,尽管选择这些参数可能会影响性能。如果在插入数据前未执行此操作,将导致软件崩溃。

2. 创建vtkPoints的一个子类的实例来定义数据集几何结构。使用操作符ugrid->SetPoints()将这些点与数据集关联起来。

3.使用单元格插入操作符ugrid- >InsertNextCell()逐个单元格创建数据集拓扑。这个操作符有很多种,请使用合适的操作符。

4. 创建点和/或单元格属性数据,并将其与数据集关联。

5. 通过执行ugrid->Squeeze()操作符完成创建过程。该操作符回收数据结构所消耗的任何额外内存。虽然这个步骤不是必需的,但是它会将内存资源返回给计算机系统。非结构化网格数据集的创建与其他数据集类型的创建略有不同。这是因为数据的非结构化性质,以及内部数据结构的复杂性质。

5.9章小结

数据集表示可视化数据。数据集具有组织结构,具有拓扑和几何组件,以及相关的属性数据。数据集的结构由单元格(拓扑)和点(几何)组成。结构的一个重要特征是它的几何和拓扑是规则的还是不规则的(或等价地,结构化的还是非结构化的)。规则数据比不规则数据更紧凑,通常计算效率更高。然而,不规则数据在表示能力上比规则数据更灵活。

重要的数据集类型包括多边形数据、直线网格、图像数据、结构化网格和非结构化网格。多边形数据集类型用于表示图形数据以及多种可视化数据。非结构化网格是最普遍的类型,由所有可能的单元格类型的任意组合组成。

属性数据由标量、向量、张量、纹理坐标和法线组成。其他数组也可以作为属性数据的一部分,因为它是一种字段数据类型。在可视化工具包中,属性数据与数据集点和单元格相关联。

5.10书目注释

对于这里描述的每种数据集类型,都提出了各种表示方案。这些方案取决于设计目标。例如,即使是简单的体积表示也可以用其他更复杂的方案实现,如运行长度编码和八叉树[Bloomenthal88]。在[Haber91]、AVS场模型[AVS89]和紧凑单元结构[Schroeder94]中有更通用的表示方案的描述。数据集类型的概述可以在[Gelberg90]中找到。一些面向数学的结构可以在[Brisson90]和[Poluzzi93]中找到。Haimes [VISUAL3]描述了一种用于非结构化网格可视化的高效数据结构。

如果您对有限元方法的更多细节感兴趣,请参阅经典的Zienkiewicz [Zienkiewicz87]或[Gallagher75]。关于有限差分法和有限元法的信息可在[Lapidus82]中找到。

5.11参考资料

[AVS89]安普生,小T.福克伯,D.卡明斯等。应用可视化系统:科学可视化的计算环境计算机图形学与应用,9(4):30-42,1989。

[杜晓东,王晓东,等。隐式曲面的多边形化计算机辅助几何设计。5(4): 341-355, 1988年11月。vtkPoints *points = vtkPoints::New();(我= 0;i< 27个;我+ +)点→InsertPoint(我x[我]);vtkunstructuregrid *ugrid = vtkUnstructuredGrid::New();ugrid→分配(100);InsertNextCell(VTK_HEXAHEDRON, 8, pts[0]);InsertNextCell(VTK_HEXAHEDRON, 8, pts[1]);InsertNextCell(VTK_TETRA, 4, pts[2]);InsertNextCell(VTK_TETRA, 4, pts[3]);InsertNextCell(VTK_POLYGON, 6, pts[4]);InsertNextCell(VTK_TRIANGLE_STRIP, 6, pts[5]);InsertNextCell(VTK_QUAD, 4, pts[6]);InsertNextCell(VTK_TRIANGLE, 3, pts[7]);InsertNextCell(VTK_TRIANGLE, 3, pts[8]);InsertNextCell(VTK_LINE, 2, pts[9]);InsertNextCell(VTK_LINE, 2, pts[10]);InsertNextCell(VTK_VERTEX, 1, pts[11]);ugrid→定位点(点);点→删除();图5-21创建非结构化网格(UGrid. xml)cxx)。vtkDataSetMapper vtkUnstructuredGrid 158基本数据表示

[Brisson90]。d维几何结构的表示:拓扑和顺序计算机学会计算几何研讨会。ACM出版社,纽约,1989年。

[加拉格尔75]李志强。有限元分析:基础。Prentice Hall, Upper Saddle River, NJ, 1975。

[李文杰,李志强,李志强,等。结构化和非结构化科学数据的可视化技术SIGGRAPH ' 90课程笔记的国家的艺术数据可视化。1990年8月。

[刘国强,刘国强。“为科学可视化提供规则和不规则网格的数据模型。”在《可视化学报》91年。第298-395页,IEEE计算机协会出版社,Los Alamitos, CA, 1991。

[刘国强,李国强。]科学与工程中偏微分方程的数值解法。约翰·威利父子,纽约,1987年。

[摩顿森85]莫顿森。几何建模。约翰·威利父子,纽约,1985年。

[Poluzzi93]李国强,李国强。简单复合体与维数无关的建模ACM图形学汇刊。12(1): 56 - 102, 1993。

[施隆德,李志强,等。“科学可视化的紧凑单元结构”科学可视化高级技术的SIGGRAPH ' 93和' 94课程笔记。

[施洛德05]李文华,王志强,王志强,Pébay。高阶基函数可视化框架在IEEE可视化论文集2005,pp. 43-50,明尼阿波利斯,明尼苏达州,IEEE计算机社会出版社,2005年10月。

[视觉3]海姆斯,贾尔斯。交互式非定常非结构化3D可视化AIAA报告编号张仁- 91 - 0794。1991年1月。

[刘文杰,李文杰,李文杰,等。几何建模的拓扑结构。博士论文,伦斯勒理工学院,特洛伊,纽约,1986年5月。

[齐恩凯维奇,刘志伟,刘志伟,等。有限元法,第1卷。麦格劳-希尔图书公司,纽约,1987年第4版。

5.12运动

5.1考虑尺寸为1002的像素图。比较内存需求来表示这些数据,使用:

a)图像数据集,

b)结构化网格数据集,5.12 Exercises 159

c)四边形多边形网格,

d)四边形单元的非结构化网格,

e)和三角形条形网格,每个条形网格有100条,每个条形网格有200个三角形。

5.2考虑尺寸为100的体积。比较使用以下方法表示此数据的内存需求:

a)图像数据集,

b)结构化网格数据集,

c)和非结构化六面体网格单元。5.3建立直线网格的表示方案。这与结构化网格(内存需求)相比如何?

5.4考虑尺寸为100的体积。计算以下点属性类型的内存需求:

a)无符号字符标量(每个标量1个字节),

b)浮点标量(每个标量4个字节),

c)浮点向量,

d)和双精度张量(3x3张量)。

5.5列出三个标量数据的例子。

5.6列举三个矢量数据的例子。

5.7列出三个张量数据的例子。

5.8数据集中是否可以有多个标量字段?如果是,该如何表示该信息?

5.9表示单元格连通性的一种常用方法是列出最后一个id为负数的点id。例如,三角形(8,7,3)将被表示为(8,7,-3)。负索引表示单元格定义的结束。与VTK单元阵列结构相比,该方案的优点和缺点是什么?

5.10一个六面体细胞有多少种分解成四面体的方法?相邻六面体之间是否存在兼容性问题?

5.11编写程序创建并显示空心圆柱体(即有孔的圆柱体)形式的结构化网格。

5.12编写程序创建并显示空心圆柱体形式的非结构化网格。

5.13编写程序创建并显示一个多边形八面体

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 若您想要下载 VTK(Visualization Toolkit,可视化工具包)的教程 PDF 文件,您可以按照以下步骤进行操作: 1. 打开您的浏览器,并搜索“vtk教程 pdf”来查找相关的网页。 2. 浏览搜索结果,找到一个可靠的网站或资源,它可能是一个论坛、博客、学术机构的网站、文档分享平台等。 3. 点击搜索结果中提供的链接,进入该网站。 4. 在网站上寻找关于 VTK 教程的文档或资源。其中一种可能的方式是在网站上使用搜索功能,并输入“VTK教程”等相关关键词。 5. 找到合适的 PDF 文件并点击下载链接。有些网站可能会要求您注册、登录或进行一些其他操作才能开始下载。 6. 按照网站的指示完成下载。 需要注意的是,确保您选择的网站是可信赖的,以便下载到内容真实、无病毒的 VTK 教程 PDF 文件。另外,您还可以考虑到 VTK 官方网站或相关技术论坛上寻找相关资料和教程,这些来源通常提供高质量的资源。 ### 回答2: vtk(Visualization Toolkit)是一个开源的可视化工具库,用于处理和呈现三维数据。关于vtk教程的pdf下载,你可以通过以下步骤获得。 首先,打开互联网浏览器,例如谷歌浏览器、火狐浏览器等。 然后,在搜索引擎中输入“vtk教程pdf下载”。点击搜索按钮,搜索引擎会为你提供与vtk教程相关的pdf下载链接。 接下来,浏览搜索结果列表,找到你所需的vtk教程pdf下载链接。通常,这些链接会指向包含vtk教程pdf文件的网站。 点击合适的链接,你会被重定向到相关网站的页面。在页面上,你可能需要注册或登录才能进行下载。 根据网站的提示,完成所需的注册或登录操作。一旦注册或登录成功,你将能够下载vtk教程的pdf文件。 点击下载链接,开始下载vtk教程的pdf文件。请注意,下载时间取决于文件大小和你的网络连接速度。 下载完成后,你可以打开下载文件夹,找到vtk教程的pdf文件。双击文件名,使用默认的pdf阅读器或你喜欢的阅读器打开。 现在,你可以使用该pdf文件来学习vtk教程。根据自己的需求,你可以打印出来或在电脑上阅读。 总结起来,通过搜索并访问相关网站,进行注册或登录,然后下载vtk教程的pdf文件,您就可以获得所需的教程资料了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值