Visualization Toolkit官方开发文档翻译(7)–第六章基本算法

我们已经了解了如何表示基本类型的可视化数据,例如图像数据、结构化网格、非结构化网格和多边形数据。本章探讨了将这些数据与这些不同的表示进行转换的方法,最终生成我们可以渲染的图形基元。这些方法被称为算法,并且对于那些在可视化领域工作的人来说特别感兴趣。算法是允许我们以视觉形式表达数据的动词。通过适当地组合这些动词,我们可以将复杂的数据简化为简单易懂的句子,这是数据可视化的力量。

6.1 简介

转换数据的算法是数据可视化的核心。为了描述可用的各种转换,我们需要根据转换的结构类型对算法进行分类。我们所说的结构是指转换对数据集的拓扑和几何形状的影响。类型是指算法操作的数据集类型。

结构转换可以分为四种方式,具体取决于它们如何影响数据集的几何、拓扑和属性。

  • 几何变换会改变输入几何,但不会改变数据集的拓扑。例如,如果我们平移、旋转和/或缩放多边形数据集的点,拓扑不会改变,但点坐标和几何形状会改变。

  • 拓扑变换改变输入拓扑但不改变几何和属性数据。将数据集类型从多边形数据转换为非结构化网格数据,或从图像数据转换为非结构化网格,会更改拓扑但不会更改几何。然而,更常见的是,只要拓扑结构发生变化,几何形状就会发生变化,因此拓扑变换并不常见。

  • 属性转换将数据属性从一种形式转换为另一种形式,或从输入数据创建新属性。数据集的结构不受影响。计算矢量幅度或基于高程创建标量是数据属性转换。

  • 组合转换同时改变数据集结构和属性数据。例如,计算等高线或曲面是一种组合变换。

我们还可以根据算法操作的数据类型或生成的数据类型对算法进行分类。对于类型,我们通常指的是属性数据的类型,例如标量或向量。典型类别包括:

  • 标量算法对标量数据进行操作。例如,在天气图上生成温度等高线。

  • 矢量算法对矢量数据进行操作。显示气流的定向箭头(方向和幅度)是矢量可视化的一个示例。

  • 张量算法在张量矩阵上运行。张量算法的一个示例是使用定向图标显示材料中的应力或应变分量。

  • 建模算法生成数据集拓扑或几何,或表面法线或纹理数据。建模算法往往是许多算法的包罗万象的类别,因为有些算法并不完全适合上述任何单一类别。例如,根据矢量方向生成字形,然后根据标量值进行缩放,是一种组合的标量/矢量算法。为方便起见,我们将这种算法归类为建模算法,因为它不适合任何其他类别。

算法也可以根据它们处理的数据类型进行分类。这是可视化文献中最常见的方案。然而,该方案并非没有问题。通常类别重叠,导致混淆。例如,一个类别(上面没有提到)是体可视化,它指的是体数据(或者我们的术语,图像数据)的可视化。该类别最初是为了描述排列在卷上的标量数据的可视化而创建的,但最近,矢量(甚至张量)数据已经在卷上进行了可视化。因此,我们必须将我们的技术限定为体积矢量可视化或其他可能令人困惑的组合。

在接下来的文本中,我们将使用属性类型分类方案:标量、向量、张量和建模。如果算法在特定数据集类型上运行,我们会根据我们的最佳判断将它们归入适当的类别。但请注意,确实存在替代分类方案,并且可能更适合描述算法的真实性质。

图6-1

图 6-1通过查找表将标量映射到颜色。

 

普遍性与效率

大多数算法可以专门为特定的数据集类型编写,或者更一般地说,可以处理任何数据集类型。特定算法的优势在于它通常比可比较的通用算法更快。(参见第 5 章中的“其他数据抽象”,我们讨论了抽象形式和具体形式之间的权衡。)特定算法的实现也可能更节省内存,并且它的实现可能更好地反映算法与其数据集类型之间的关系上运行。

这方面的一个例子是轮廓表面的创建。提取轮廓表面的算法最初是为体数据开发的,主要用于医疗应用。卷的规律性有助于高效算法。然而,基于体积的算法的专业化使其无法用于更一般的数据集,例如结构化或非结构化网格。尽管轮廓算法可以适应这些其他数据集类型,但它们的效率低于体积数据集。

我们对算法的介绍倾向于更通用的实现。在某些特殊情况下,我们将描述特定数据集类型的性能改进技术。有关专用算法的详细描述,请参阅每章末尾的参考书目。

6.2 标量算法

标量是与数据集的每个点和/或单元相关联的单个数据值。(回想一下,在可视化工具包中,我们将数据与点相关联。)因为标量数据在现实世界的应用程序中很常见,而且因为标量数据很容易使用,所以有许多不同的算法可以将其可视化。

颜色映射

颜色映射是一种常见的标量可视化技术,将标量数据映射到颜色,并在计算机系统上显示颜色。标量映射是通过索引颜色查找表来实现的。标量值用作查找表的索引。

映射如下进行。查找表保存一组颜色(例如,红色、绿色、蓝色分量或其他可比较的表示)。与该表相关的是标量值映射到的最小和最大标量范围(min,max) 。大于最大范围的标量值被限制为最大颜色,小于最小范围的标量值被限制为最小颜色值。然后,对于每个标量值xi, 索引i进入具有 n 个条目(和 0 偏移)的颜色表由下式给出图 6-1.

查找表的更一般形式称为传递函数。传递函数是图 6-2映射任何将标量值映射到颜色规范的表达式。例如,将标量值转换为红色、绿色和蓝色分量的单独强度值。我们还可以使用传递函数将标量数据映射到其他信息,例如局部透明度。(传递函数在第 7 章的“透明度和 Alpha 值”中有更详细的讨论。图 6-2映射任何将标量值映射到颜色规范的表达式。例如,将标量值转换为红色、绿色和蓝色分量的单独强度值。我们还可以使用传递函数将标量数据映射到其他信息,例如局部透明度。(传递函数在第 7 章的“透明度和 Alpha 值”和7 章“体积渲染”中有更详细的讨论。)查找表是传递函数的离散采样。我们可以通过在一组离散点对传递函数进行采样,从任何传递函数创建一个查找表。

颜色映射是一种一维可视化技术。它将一条信息(即标量值)映射到颜色规范中。然而,颜色信息的显示不限于一维显示。我们经常使用映射到 1D、2D 或 3D 对象的颜色信息。这是增加可视化信息内容的简单方法。

标量可视化颜色映射的关键是仔细选择查找表条目。图 6-3显示了四个不同的查找表,用于在流体流过燃烧室时可视化气体密度。第一个查找表是灰度的。灰度表通常为眼睛提供更好的结构细节。其他三张图片在图 6-3使用不同的颜色查找表。第二个使用从蓝色到红色的彩虹色调。第三种使用从红色到蓝色排列的彩虹色调。最后一张表使用了旨在增强对比度的表。谨慎使用颜色通常可以增强数据集的重要特征。然而,任何类型的查找表都可能夸大不重要的细节或创建视觉伪影,因为数据、颜色选择和人体生理学之间的不可预见的相互作用。

设计查找表既是一门艺术,也是一门科学。从实用的角度来看,表格应该突出重要的特征,同时尽量减少不太重要或无关的细节。还希望使用固有地包含缩放信息的调色板。例如,通常使用从蓝色到红色的彩虹色标度来表示温度标度,因为许多人将“蓝色”与冷温度联系起来,而将“红色”与热温度联系起来。然而,即使是这个尺度也是有问题的:物理学家会说蓝色比红色更热,因为更热的物体比红色发出更多的蓝光(即更短的波长)。此外,没有必要将自己限制在“线性”查找表中。即使标量到颜色的映射已被呈现为线性运算(图 6-1),表格本身不必是线性的。也就是说,可以设计表格以使用对数或其他方案来增强标量值的微小变化,提高舒适度并让人类观察者更深入地参与数据的呈现,从而提高通信的有效性。

图6-2

图 6-2。作为标量值函数的颜色分量红色、绿色和蓝色的传递函数。

 

图 6-3

图 6-3。流密度用不同的查找表着色。左上:灰度;右上角彩虹(蓝色到红色);左下彩虹(红到蓝);右下大反差。请参阅 Rainbow.cxx和 Rainbow.py

 

图6-4

图 6-4。轮廓线值 = 5 的 2D 结构化网格轮廓。

 

轮廓

颜色映射的自然扩展是轮廓。当我们看到一个用数​​据值着色的表面时,眼睛通常会将相似颜色的区域分成不同的区域。当我们绘制数据轮廓时,我们正在有效地构建这些区域之间的边界。这些边界对应于恒定标量值的等高线 (2D) 或曲面 (3D)。

2D 等高线显示的示例包括用恒温线(等温线)注释的天气图,或用等高线绘制的拓扑图。三维轮廓称为等值面,可以用许多多边形图元来近似。等值面的示例包括与身体组织(例如皮肤、骨骼或其他器官)相对应的恒定医学图像强度。也可以创建其他抽象等值面,例如流体流动中的恒定压力或温度表面。

考虑如图所示的 2D 结构化网格图 6-4. 标量值显示在定义网格的点旁边。轮廓总是从选择与生成的轮廓线或表面相对应的标量值或轮廓值开始。要生成轮廓,必须使用某种形式的插值。这是因为我们在数据集中的一组有限点处具有标量值,而我们的轮廓值可能位于点值之间。由于最常见的插值技术是线性的,我们通过沿边缘的线性插值在轮廓面上生成点。如果一条边在其两个端点处具有标量值 10 和 0,并且如果我们试图生成值为 5 的等高线,则边插值计算出等高线通过边的中点。

一旦生成了单元边缘上的点,我们可以使用几种不同的方法将这些点连接到轮廓中。一种方法检测边缘交叉点(即,轮廓穿过边缘),然后在它移动穿过单元边界时“跟踪”该轮廓。我们知道,如果轮廓边缘进入一个单元格,它也必须退出一个单元格。跟踪轮廓,直到它自行关闭或退出数据集边界。如果已知仅存在单个轮廓,则该过程停止。否则,必须检查数据集中的每条边以查看是否存在其他等高线。另一种方法使用分而治之的技术,独立处理细胞。这是2D中的行进方块算法和行进立方体 [Lorensen87]在 3D 中。这些技术的基本假设是一个轮廓只能以有限的方式通过一个单元。在给定单元点处的标量值组合的情况下,构建一个案例表,枚举单元的所有可能拓扑状态。拓扑状态的数量取决于单元顶点的数量,以及顶点相对于轮廓值可以具有的内部/外部关系的数量。如果顶点的标量值大于轮廓线的标量值,则认为顶点在轮廓内。标量值小于等高线值的顶点称为等高线外。例如,如果一个单元格有四个顶点,并且每个顶点可以在等高线内部或外部,则有16轮廓通过单元格的可能方式。在案例表中,我们不关心轮廓在哪里穿过单元格(例如几何交点),只关心它如何穿过单元格(即单元格中轮廓的拓扑结构)。

图 6-5显示正方形单元格的十六种组合。可以通过将每个顶点的状态编码为二进制数字来计算案例表的索引。对于矩形网格上表示的 2D 数据,我们可以用 4 位索引表示 16 个案例。一旦选择了适当的情况,就可以使用插值计算轮廓线/单元边缘交叉点的位置。该算法处理一个单元格,然后移动或前进到下一个单元格。访问完所有单元格后,轮廓将完成。总之,行进算法如下:

  1. 选择一个单元格。

  2. 计算单元格每个顶点的内部/外部状态。

  3. 通过将每个顶点的二进制状态存储在单独的位中来创建索引。

  4. 使用索引在案例表中查找单元的拓扑状态。

  5. 计算案例表中每个边缘的轮廓位置(通过插值)。

此过程将在每个单元格中构造独立的几何图元。在单元边界处,可能会创建重复的顶点和边。这些重复可以通过使用特殊的重合点合并操作来消除。请注意,沿每条边的插值应在同一方向上进行。否则,数值舍入可能会导致生成的点不完全重合,并且无法正确合并。

边缘跟踪和行进立方体方法都有优点和缺点。行进广场算法很容易实现。当我们将技术扩展到三个维度时,这一点尤其重要,因为等值面跟踪变得更加困难。另一方面,该算法会创建断开的线段和点,并且所需的合并操作需要额外的计算资源。跟踪算法可以实现为每条轮廓线生成一条折线,避免了合并重合点的需要。

图6-5

图 6-5。十六个不同的行进广场案例。深色顶点表示标量值高于轮廓值。案例 5 和 10 是模棱两可的。

 

图 6-6

图 6-6。用于 3D 等值面生成的 Marching Cubes 案例。使用对称性将 256 种可能的情况减少到 15 种。红色顶点大于选定的等值面值。见 MarchingCasesA.cxx见 MarchingCasesA.py

 

图6-7
图 6-7。使用行进三角形或行进四面体来解决矩形晶格上的不明确情况(仅显示立方体的面)。选择对角线方向可能会导致轮廓表面出现“凸起”。在 2D 中,对角线方向可以任意选择,但在 3D 中,对角线受邻居约束。

如前所述,行进广场的 3D 类比是行进立方体。这里有 256 种不同的标量值组合,假设一个立方体单元中有 8 个点(即,28组合)。图 6-6显示通过使用对称参数将这些组合减少到 15 种情况。我们使用旋转和镜像的组合来产生拓扑等效的情况。

图片[8]-Visualization Toolkit官方开发文档翻译(7)–第六章基本算法-卡核

图 6-10 Marching Cubes 补充案例。请参阅 MarchingCasesB.cxx 和 MarchingCasesB.py

 

一个重要的问题是轮廓模糊。仔细观察编号为 5 和 10 的行进方块案例和编号为 3、6、7、10、12 和 13 的行进立方体案例表明,存在可以以不止一种方式描绘单元轮廓的配置。(当使用边缘跟踪方法进行轮廓绘制时,这种模糊性也存在。)当相邻边缘点处于不同状态但对角顶点处于相同状态时,轮廓模糊会出现在 2D 正方形或 3D 立方体的面上。

在二维中,轮廓模糊很容易处理:对于每个模糊的情况,我们实现两种可能的情况之一。特定情况的选择独立于所有其他选择。根据选择,轮廓可以延伸或破坏当前轮廓,如图所示图 6-8. 任何一种选择都是可接受的,因为生成的等高线将是连续的且闭合的(或将在数据集边界处结束)。

在三个维度上,问题更加复杂。我们不能简单地选择一个独立于所有其他模棱两可的情况的模棱两可的情况。例如图 6-9展示了如果我们不小心执行两个彼此独立的案例会发生什么。在此图中,我们使用了通常的案例 3,但将案例 6 替换为补充案例。通过将“暗”顶点与“亮”顶点交换来形成互补案例。(这相当于将顶点标量值从等值面值上方交换到等值面值下方,反之亦然。)这两种情况配对的结果是在等值面上留下了一个洞。

已经采取了几种不同的方法来解决这个问题。一种方法是用四面体镶嵌立方体,并使用行进四面体技术这是有效的,因为行进的四面体没有表现出模棱两可的情况。不幸的是,行进四面体算法会生成由更多三角形组成的等值面,并且用四面体细分立方体需要对四面体的方向做出选择。由于沿面对角线的插值,此选择可能会导致等值面中出现人为的“凹凸”,如图所示图 6-7. 另一种方法评估曲面的渐近行为,然后选择要加入或破坏轮廓的情况。Nielson 和 Hamann [Nielson91]基于这种方法开发了一种技术,他们称之为渐近决策器。它基于对模糊面上标量变量变化的分析。该分析确定了等值面多边形的边应如何连接。

图6-8

图 6-8。选择特定的轮廓情况将破坏(a)或加入(b)当前轮廓。所示案例为行进广场案例 10。

 

图6-9

图 6-9。任意选择行进立方体案例会导致等值面出现孔洞。

 

一个简单而有效的解决方案通过添加额外的补充案例来扩展原来的 15 个行进立方体案例。这些案例旨在与相邻案例兼容,并防止在等值面上产生孔洞。需要六个互补的案例,对应于行进立方体案例 3、6、7、10、12 和 13。互补的行进立方体案例显示在图 6-10.

我们可以将行进正方形和行进立方体的一般方法扩展到其他拓扑类型。在 VTK 中,我们使用行进线、三角形和四面体来勾勒这些类型的细胞(或由这些类型组成的复合细胞)。此外,虽然我们说的是正方形和立方体等常规类型,但行进立方体可以应用于拓扑上与立方体等效的任何单元类型(例如,六面体或非立方体体素)。

图 6-11显示轮廓的四种应用。在图 6-11a(a) 我们看到不同组织类型对应的 CT 密度值的二维等高线。这些线条是使用行进方块生成的。图 6-11b(b) 通过图 6-11d(d) 是由行进立方体创建的等值面。图 6-11b(b) 是来自计算机断层扫描 (CT) X 射线成像系统的恒定图像强度的表面。(图 6-11a(a) 是该数据的 2D 子集。)强度级别对应于人体骨骼。图 6-11c(c) 是恒定流动密度的等值面。图 6-11d(d) 是铁蛋白分子的电子势等值面。如图所示图 6-11b(b) 由于我们熟悉人体解剖学,因此可以立即识别。然而,对于计算流体动力学和分子生物学领域的从业者来说,图 6-11c(c) 和图 6-11d(d) 同样熟悉。正如这些示例所示,轮廓绘制方法是用于可视化来自各个领域的数据的强大而通用的技术。

图 6-11a

(a) 用于生成等高线的行进广场。

 

图 6-11b

(b) 人体骨骼的 Marching Cubes 表面

 

图 6-11c

(c) 流动密度的行进立方体表面。

 

图 6-11d

(d) 铁蛋白的 Marching Cubes 表面

 

图 6-11。轮廓示例。(a) 用于生成等高线的行进方块参见 HeadSlice.cxxHeadSlice.py;(b) 人体骨骼的行进立方体表面。参见 HeadBone.cxxHeadBone.py;(c) Marching Cubes 流密度表面见 CombustorIsosurface.cxxCombustorIsosurface.py;(d) 铁蛋白的行进立方体表面。请参阅 IronIsoSurface.cxxIronIsoSurface.py

标量生成

迄今为止提出的两种可视化技术,颜色映射和轮廓,是显示标量信息的简单有效的方法。在可视化数据时,首先求助于这些技术是很自然的。然而,我们的数据通常不适合这些技术。数据可能不是单值(即标量),也可能是数学或其他复杂关系。这是可视化的乐趣和创造性挑战的一部分:我们必须利用我们的创造性资源将数据转换为我们可以可视化的形式。

例如,考虑地形数据。我们假设数据是xyz坐标,其中xy代表平面内的坐标,z代表海拔高度。我们想要的可视化是根据海拔对地形进行着色。这需要创建一个彩色地图——可能使用白色表示高海拔,蓝色表示海平面及以下,以及对应于海平面和高海拔之间的高度的各种绿色和棕色阴影。我们还需要标量来索引颜色映射。这里明显的选择是提取z坐标。也就是说,标量只是z坐标值。

这个例子可以通过概括这个问题变得更有趣。尽管我们可以轻松地创建一个过滤器来提取z坐标,但我们可以创建一个过滤器来生成高程标量值,其中高程是沿任何轴测量的。给定一条从(低)点开始的定向线pl(例如,海平面)并在(高)点结束(例如,山顶),我们计算海拔标量si在点pi=(xi,yi,zi)使用点积,如图所示图 6-12. 使用定向线的大小对标量进行归一化,并且可以将其限制在最小和最大标量值之间(如果需要)。该图的下半部分显示了将该技术应用于夏威夷檀香山地形模型的结果。使用从深蓝色(水)到黄白色(山顶)的 256 个查找表来对该图进行彩色映射。

 

图6-12a
图 6-12

图 6-12。使用归一化点积计算标量。图的下半部分说明了应用于夏威夷檀香山地形数据的技术。请参阅 Hawaii.cxxHawaii.py

 

可视化创造性实践的一部分是从可用技术的调色板中为给定数据选择最佳技术。这通常需要可视化系统的用户进行创造性的映射。特别是,要使用标量可视化技术,我们只需要创建一个关系即可生成唯一的标量值。标量映射的其他示例包括数据列表中的索引值、计算矢量幅度或矩阵确定、评估表面曲率或确定点之间的距离。标量生成与颜色映射或轮廓相结合时,是一种用于可视化多种类型数据的简单而有效的技术。

6.3 向量算法

矢量数据是方向和大小的三维表示。矢量数据通常来自对流体流动的研究,或在检查某个量的导数(即变化率)时。

刺猬和定向字形

一种自然的向量可视化技术是为每个向量绘制一条有方向的缩放线 (图 6-13(一个))。线从与向量相关联的点开始,并朝向向量分量的方向(vx,vy,vz). 通常,生成的线必须按比例放大或缩小以控制其视觉表示的大小。这种技术通常被称为刺猬,因为它的结果是毛茸茸的。

这种技术有很多变体(图 6-13(b))。可以添加箭头来指示线的方向。这些线可以根据矢量幅度或一些其他标量(例如,压力或温度)着色。此外,可以使用定向的“字形”而不是使用线条。字形是指任何 2D 或 3D 几何表示,例如定向三角形或圆锥。

 

图 6-13a

图 6-13

(c) 复杂的展示。

 

图 6-13。矢量可视化技术:(a) 定向线;(b) 使用定向字形;(c) 复杂向量可视化。请参阅 ComplexV.cxxComplexV.py

 

在应用这些技术时应小心谨慎。在 3D 中,通常很难理解矢量的位置和方向,因为它会投影到 2D 图像中。此外,使用大量矢量会使显示变得混乱,以至于可视化变得毫无意义。图 6-13(c) 显示了人类颈动脉区域中的 167,000 个 3D 矢量(使用定向和缩放线)。较大的矢量位于动脉内,较小的矢量位于动脉外,方向随机(测量误差),但幅度较小。显然,从该图像中无法辨别矢量场的细节。

缩放字形也会带来有趣的问题。在 Tufte 所说的“可视化谎言”中,[Tufte83]缩放 2D 或 3D 字形会导致外观上的非线性差异。物体的表面积随着其比例因子的平方而增加,因此两个大小相差两倍的向量可能会根据表面积出现高达四倍的差异。这种缩放问题在数据可视化中很常见,必须非常小心地避免误导观众。

翘曲

矢量数据通常与“运动”相关联。运动是速度或位移的形式。显示此类矢量数据的一种有效技术是根据矢量场“扭曲”或变形几何图形。例如,想象一下通过结构变形来表示结构在负载下的位移。或者,如果我们正在可视化流体的流动,我们可以通过扭曲垂直于流动插入的直线来创建流动剖面。

 

图 6-14a

(a) 梁的振动。

 

图 6-14b

(b) 动量剖面。

 

图 6-14。扭曲几何以显示矢量场。(a) 光束位移参见 PlateVibration.cxxPlateVibration.py。);(b)参见 VelocityProfile.cxxVelocityProfile.py

 

图 6-14显示了向量变形的两个示例。在第一个示例中,显示了振动梁的运动。原始未变形的轮廓线框显示。第二个示例显示结构化网格数据集中的扭曲平面。平面根据流动动量而翘曲。在平面的变形中可以清楚地看到相对的前后流动。

通常,我们必须缩放矢量场以控制几何失真。太小的扭曲可能不可见,而太大的扭曲会导致结构翻转或自相交。在这种情况下,可视化的查看者可能会丢失上下文,并且可视化将变得无效。

位移图

物体表面上的矢量位移可以通过位移图进行可视化。位移图显示对象在垂直于其表面的方向上的运动。物体运动是由施加的矢量场引起的。在典型应用中,矢量场是位移或应变场。

矢量位移图借鉴了“标量生成”中的思想。通过计算每个点的表面法线和向量之间的点积,向量被转换为标量 (图 6-15(一个))。如果结果为正值,则该点的运动沿表面法线方向(即正位移)。负值表示运动与表面法线相反(即负位移)。

该技术的一个有用应用是研究振动。在振动分析中,我们对结构的特征值(即自然共振频率)和特征向量(即振型)感兴趣。要了解模式形状,我们可以使用位移图来指示运动区域。结构中存在正位移变为负位移的特殊区域。这些是零位移区域。当绘制在结构的表面上时,这些区域显示为所谓的振动模态线。长期以来,模态线的研究一直是理解模态振型的重要可视化工具。

 

图 6-15a

图 6-15。(a) 标量计算。

图 6-15b

图 6-15。矢量位移图。(a) 向量通过点积计算转换为标量;(b) 振动板的表面图。深色区域显示节点线。明亮区域显示最大运动。请参阅 DisplacementPlot.cxxDisplacementPlot.py

 

图 6-15(b) 显示了振动矩形梁的模态线。该图中的振动模式是第二种扭转模式,由交叉的模态线清楚地表示。(图中的锯齿是因为分析网格的粗糙度。)为了创建图形,我们结合了以下过程图 6-15(a) 带有一个特殊的查找表。查找表的中心是暗区(即,对应于零点积)和表的开头和结尾处的亮区(对应于 1 或 -1 点积)。结果,大法向位移的区域是明亮的,而靠近模态线的区域是黑暗的。

时间动画

到目前为止描述的一些技术可以被认为是在一个小的时间步长上移动一个点或对象。刺猬线是一个点在一段时间内运动的近似值,其持续时间由比例因子给出。换句话说,如果速度V=dx/dt,则点的位移为

屏幕截图 2022-11-06 163817

这暗示了对我们之前技术的扩展:在多个时间步长上重复替换点。图 6-16显示了这种方法。从以某个点C为中心的球体S开始,我们反复移动S以生成所示的气泡。眼睛倾向于通过连接气泡来追踪路径,让观察者对该区域的流体流动有一个定性的了解。气泡可以随着时间的推移显示为动画(给出运动的错觉)或多次曝光序列(给出路径的外观)。

图6-16

图 6-16。点C的时间动画。尽管点之间的间距不同,但每个点之间的时间增量是恒定的。

 

这种方法可能会被滥用。一方面,某一点的速度是瞬时的。

一旦我们离开该点,速度可能会发生变化。使用上面的公式6-1 假设速度在整个步骤中是恒定的。通过采取大步骤,我们可能会跳过速度的变化。使用更小的步骤,我们将在不同的位置结束。因此,步长的选择是构建矢量场中粒子路径的精确可视化的关键参数。

为了评估Equation6-1,我们可以将其表示为一个积分:

屏幕截图 2022-11-06 163907尽管对于大多数现实世界的数据,这种形式无法解析求解,但可以使用数值积分技术来近似求解。精确的数值积分超出了本书的范围,但众所周知,积分的准确度是步长dt的函数. 由于路径是整个数据集的积分,因此单元插值函数的准确性以及原始矢量数据的准确性对于实现精确解具有重要作用。目前还没有明确的研究将像元大小或插值函数特征与可视化误差相关联。但教训很清楚:必须仔细检查数值积分的结果,尤其是在矢量场梯度较大的区域。然而,与许多其他可视化算法一样,通过使用矢量积分技术获得的洞察力在质量上是有益的,尽管存在不可避免的数值误差。

最简单的数值积分形式是欧拉方法,

其中时间的位置是xi+前一位置的矢量和加上瞬时速度乘以增量时间步长Δt.

欧拉方法的误差为O(Δt2),这对于某些应用程序来说不够准确。一个这样的例子显示在图 6-17. 速度场描述了围绕中心点的完美旋转。使用欧拉的方法,我们发现我们总是会发散,而不是生成圆,而是生成螺旋。

图6-17

图 6-17。Euler 积分 (b) 和 RungeKutta 2 阶积分 (c) 应用于均匀旋转矢量场 (a)。欧拉的方法总是发散的。

 

在本文中,我们将使用 2 阶[Conte72]的 RungeKutta 技术。这是由表达式给出的

屏幕截图 2022-11-06 164112

其中速度Vi+1是使用欧拉方法计算的。这种方法的错误是O(Δt3). 与 Euler 方法相比,RungeKutta 技术允许我们采取更大的集成步骤,但代价是额外的函数评估。通常,这种权衡是有益的,但与任何数值技术一样,使用的最佳方法取决于数据的特定性质。高阶技术也可用,但通常不是必需的,因为更高的精度会被插值函数中的误差或数据值固有的误差所抵消。如果您对其他积分公式感兴趣,请查看本章末尾的参考资料。

关于准确性问题的最后一点说明。可视化的感知或计算所涉及的错误是一个开放的研究领域。上一段中的讨论就是一个很好的例子。在那里,我们使用传统的数值积分参数来描述流线积分中的误差。但是这个论点有一个问题。在可视化应用程序中,我们正在跨函数值连续但导数不连续的单元进行集成。当流线穿过单元边界时,可能会出现标准数值分析未处理的细微影响。因此,需要为可视化应用程序扩展标准参数。

积分公式需要从全局坐标到局部坐标的重复转换。考虑在矢量场的影响下通过数据集移动一个点。第一步是识别包含该点的单元格。这个操作是一个搜索(参见第 8 章中的“搜索”),加上一个本地坐标的转换。找到单元后,下一步是通过对单元点的速度进行插值来计算该点的速度。然后逐渐重新定位该点(使用积分公式Equation6-4)。然后重复该过程,直到该点退出数据集或遍历的距离或时间超过某个指定值。

这个过程在计算上可能要求很高。我们可以采取两个重要步骤来提高性能。

  1. 改进搜索程序。有两种不同类型的搜索。最初,粒子的起始位置必须由全局搜索程序确定。一旦在数据集中确定了点的初始位置,就可以使用增量搜索过程。增量搜索是有效的,因为点的运动被限制在单个单元格内,或者最多跨越一个单元格边界。因此,搜索空间受到很大限制,增量搜索相对于全局搜索更快。

  2. 坐标变换。如果满足以下任一条件,则可以降低从全局坐标到局部坐标的坐标转换成本:局部坐标系和全局坐标系彼此相同(或因xyz而异平移),或者如果向量场从全局空间变换到局部坐标空间。图像数据坐标系是与全局坐标平行的局部坐标的示例,因此可以大大加快全局到局部坐标的转换。如果将矢量场转换为局部坐标(作为预处理步骤或在逐个单元的基础上),则积分可以在局部空间中完全进行。一旦计算出集成路径,为了可视化,可以将沿路径的选定点转换为全局空间。

流线型

先前时间动画技术的自然扩展是在许多时间步上连接点位置。结果是表示为一条线的粒子轨迹的数值近似。

借用流体流动研究中的术语,我们可以定义三种相关的矢量场线表示方案。

  • 粒子轨迹是流体粒子随时间追踪的轨迹。

  • 条纹是特定时间的一组粒子轨迹ti通过指定点xi.

  • 流线是沿曲线的积分曲线s满足方程

屏幕截图 2022-11-06 164221在特定时间t.

如果流动是稳定的,则流线、条纹和粒子轨迹彼此等效。在时变流中,给定的流线仅存在于某一时刻。可视化系统通常提供计算粒子轨迹的工具。但是,如果时间是固定的,则可以使用相同的工具来计算流线。通常,我们将使用术语流线来指代在矢量场中追踪轨迹的方法。如果流量随时间变化,请记住这些表示中的差异。

图 6-18在一个小厨房里展示了四十条流线。房间有两扇窗户,一扇门(漏气)和一个带热炉的烹饪区。空气泄漏和温度变化相结合,在整个厨房中产生空气对流。流线的起始位置是通过创建一个rake或曲线(及其相关点)来定义的。这里的耙子是一条直线。这些流线清楚地显示了流场的特征。通过同时释放许多流线,我们可以获得更多信息,因为眼睛倾向于将附近的流线组合成对流场特征的“全局”理解。

图 6-18

图 6-18。为小厨房计算的流速(俯视图和侧视图)。四十条流线沿着位于窗户下方的耙子开始。有些最终经过热炉并向上对流。请参阅 Kitchen.cxxKitchen.py

 

存在许多流线可视化的增强功能。线条可以根据速度大小着色以指示流动速度。其他标量如温度或压力也可用于给线条着色。我们也可以创建恒定时间虚线。每个破折号代表一个恒定的时间增量。因此,在高速区域,短划线的长度将相对于低速区域更大。这些技术在图 6-19用于钝翅片周围的气流。此示例由一个壁组成,该壁具有突出到流体流中的半圆形翅片。(使用对称参数,只有一半的域被建模。)在鳍的上游释放了 25 条流线。翅片与壁面交界处的边界层效应从流线中清晰可见。在这个区域,流动再循环是明显的,以及降低的流速。

6.4 张量算法

正如我们之前提到的,张量可视化是一个活跃的研究领域。然而,我们可以使用一些简单的技术来可视化真实的×3对称张量。这种张量用于描述 3D 材料中的位移或应力状态。弹性材料的应力和应变张量显示在图 6-20.

在这些张量中,对角线系数是所谓的法向应力和应变,非对角线项是剪切应力和应变。法向应力和应变作用于垂直于指定表面,而剪切应力和应变作用于表面相切。正应力是压缩或拉伸,取决于系数的符号。

图 6-19

图 6-19。矢量可视化技术。请参阅 BluntStreamlines.cxxBluntStreamlines.py

 

一个实对称矩阵可以用三个称为特征向量的 3D 向量和称为矩阵特征值的三个数字来表征。特征向量形成一个轴相互垂直的 3D 坐标系。在某些应用中,特别是在材料研究中,这些轴也被称为张量的主轴,并且在物理上很重要。例如,如果张量是应力张量,则主轴是正应力方向,无剪应力方向。与每个特征向量相关的是一个特征值。特征值通常在物理上也很重要。在振动研究中,特征值对应于结构的共振频率,特征向量是相关的振型。

在数学上,我们可以如下表示特征值和特征向量。给定一个矩阵,特征向量和特征值必须满足关系

屏幕截图 2022-11-06 164459要使公式 6-6成立,矩阵确定必须满足
屏幕截图 2022-11-06 164527展开这个方程产生一个nth多项式在λ其根是特征值。于是,总有n特征值,尽管它们可能不是不同的。通常,由于计算性能差,方程 6-7不能使用多项式根搜索来求解。(对于 3 阶矩阵求根是可以接受的,因为我们可以解析地求解特征值。)一旦我们确定了特征值,我们可以将每个特征值代入公式 6-7以求解相关的特征向量。

图 6-20

图 6-20。应力和应变张量。xyz 坐标方向上的法向应力表示为 *sigma*,剪切应力表示为 *tau*。由 (u, v, w) 分量表示的材料位移。

 

我们可以表达特征向量系统作为

屏幕截图 2022-11-06 164640ei特征值方向上的单位向量,以及λi系统的特征值。如果我们对特征值进行排序,使得
屏幕截图 2022-11-06 164714然后我们参考对应的特征向量v1、v2在v1作为主要中等次要特征向量。

张量椭球

这将我们引向用于可视化真实对称矩阵的张量椭球技术。第一步是提取特征值和特征向量,如上一节所述。由于已知特征向量是正交的,因此特征向量形成局部坐标系。这些轴可以作为椭球的短轴中轴长轴。因此,椭球的形状和方向代表了特征值的相对大小和特征向量的方向。

为了形成椭圆体,我们首先在张量位置放置一个球体。然后使用特征向量围绕其原点旋转球体,其在公式6-8 的形式中是方向余弦。特征值用于缩放球体。使用变换矩阵并参考方程 3-6方程 3-9方程 3-13,我们通过使用矩阵变换以原点为中心的球体来形成椭球T

屏幕截图 2022-11-06 164923(记得从右到左阅读)。特征向量可以直接插入来创建旋转矩阵,而点坐标xyz和特征值λ1λ2λ3被插入到平移和缩放矩阵中。这些矩阵的串联形成最终的变换矩阵T.

图6-21

图 6-21。张量椭球。(a) 沿张量特征值(即主轴)取向的椭球体;(b) Boussinesq 问题的图形描述;(c) 根据 Saada 的分析结果。

 

图 6-21(a) 描述了张量椭球技术。在图 6-21(b) 我们展示了这种技术来可视化半无限域表面上的点载荷附近的材料应力。(这就是所谓的 Boussinesq 问题。)从 Saada [Saada74]我们得到了笛卡尔坐标中应力分量的解析表达式,如图图 6-21(C)。请注意,z 方向定义为起始于力 ρ 施加点的轴. 变量ρ是从负载应用点到点的距离xyz. x 和 y 轴的方向在垂直于 z 轴的平面内。(这些轴的平面内的旋转并不重要,因为解是围绕 z 轴对称的。)(参数n是泊松比,它是材料的属性。泊松比将材料的横向收缩与单轴应力条件下的轴向伸长率联系起来。有关详细信息,请参阅[Saada74][Timoshenko70]。)

 

图 6-22a

(a) 张量轴

 

图 6-22b

(b) 张量椭球

 

图 6-22。张量可视化技术;(a) 张量轴。请参阅 TensorAxes.cxxTensorAxes.py (b) 张量椭球。请参阅 TensorEllipsoids.cxxTensorEllipsoids.py

 

图 6-22我们将来自 Saada 的 Boussinesq 问题的分析结果可视化。该图的顶部通过显示应力张量的缩放和定向主轴来显示结果。(这些称为张量轴。)在底部,我们使用张量椭球来显示相同​​的结果。张量椭圆体和张量轴是一种专门用于张量可视化的字形(参见“字形” )。

由于负载接触点处存在应力奇异性,因此必须非常小心地将该结果可视化。在实际应用中,负载施加在一个小区域上,而不是在一个点上。此外,塑性行为可防止应力水平超过某一点。与任何计算机过程一样,可视化的结果仅与底层模型一样好。

6.5 建模算法

建模算法是我们可视化技术分类的包罗万象的类别。建模算法有一个共同点:它们创建或更改数据集几何或拓扑。

源对象

正如我们在前面的示例中所见,源对象开始可视化管道。源对象用于创建几何体,例如球体、圆锥体或立方体,以支持可视化上下文或用于读取数据文件。源对象也可用于创建数据集属性。源对象及其使用的一些示例如下。

建模简单几何。

球体、圆锥体、立方体和其他简单的几何对象可以单独使用或组合使用来建模几何。我们经常可视化现实世界的应用程序,例如房间中的气流,并且需要显示现实世界的对象,例如家具、窗户或门。

现实世界的对象通常可以使用这些简单的几何表示来表示。这些源对象按程序生成它们的数据。或者,我们可以使用阅读器对象来访问数据文件中定义的几何数据。这些数据文件可能包含更复杂的几何图形,例如由 3D CAD(计算机辅助设计)系统生成的几何图形。

支持几何。

在可视化过程中,我们可以使用源对象来创建支持几何体。这可能像三条线一样简单来表示坐标轴,也可能像管子缠绕在线段以加厚和增强其外观一样复杂。另一个常见用途是作为流线或探针过滤器等对象的补充输入。这些过滤器采用定义一组点的第二个输入。对于流线,这些点确定了生成流线的初始位置。探针过滤器使用点作为位置来计算属性值,例如标量、向量或张量。

数据属性创建。

源对象可用作创建数据属性的过程。例如,我们可以程序化地创建纹理和纹理坐标。另一个用途是在统一网格上创建标量值。如果标量值是从数学函数生成的,那么我们可以使用此处描述的可视化技术来可视化该函数。事实上,这将我们引向一类非常重要的源对象:隐式函数。

隐式函数

隐函数是形式的函数

F(x,y,z)=c(6-11)

其中 c 是任意常数。隐式函数具有三个重要属性。

  • 简单的几何描述。隐式函数是描述常见几何形状的便捷工具。这包括平面、球体、圆柱体、圆锥体、椭圆体和二次曲面。

  • 区域分离。隐式函数将 3D 欧几里得空间分成三个不同的区域。这些区域在隐式函数的内部、之上和外部。这些区域定义为F(x,y,z)<0, 分别。

  • 标量生成。隐式函数将空间中的位置转换为标量值。也就是说,给定一个隐式函数,我们可以在某个点对其进行采样(xi,yi,zi)生成一个标量值ci.

隐式函数的一个例子是半径球体的方程.

屏幕截图 2022-11-06 165637这个简单的关系定义了三个区域(在F(x,y,z=0)球体),F(x,y,z)<0(在球体内),和F(x,y,z)(球外)。任何点都可以简单地通过计算公式6-12 被分类在球内、球上或球外。

 

图 6-23a

图 6-23a。(a) 球体取样

 

图 6-23b

(b) 球体的等值面

 

图 6-23c

(c) 布尔组合

 

图 6-23。采样功能。(b) 采样球体的等值面;参见 ImplicitSphere.cxxImplicitSphere.py;(c) 两个球体、一个圆锥体和两个平面的布尔组合。(一个球体与另一个球体相交,平面夹住圆锥体。参见 IceCream.cxxIceCream.py

建模对象。

隐式函数可以单独使用或组合使用来对几何对象进行建模。例如,为了对由隐式函数描述的曲面建模,我们采样在数据集上并在等高线值处生成等值面ci. 结果是函数的多边形表示。*图 6-23b显示了在体积上采样的半径 = 1 球体的等值面。请注意,我们可以选择非零轮廓值来生成一系列偏移曲面。这对于创建混合功能和其他特殊效果很有用。

可以使用布尔运算符 union、intersection 和 difference 组合隐式函数来创建复杂对象。之间的联合运算FG两个函数之间F(x,y,z)G(x,y,z)是最小值

屏幕截图 2022-11-06 165944两个隐函数之间的交集由下式给出
屏幕截图 2022-11-06 170020两个隐函数的差异由下式给出
屏幕截图 2022-11-06 170029图 6-23c显示了一个简单的隐式函数的组合来创建一个冰淇淋蛋筒。圆锥是通过用两个平面剪裁(无限)圆锥函数来创建的。冰淇淋是通过对较大的球体和较小的偏移球体执行差分操作来构建的,以创建“咬”。使用等值面值为 0.0 的表面轮廓提取所得表面。

(a) 使用隐式函数选择数据 (b) 使用布尔组合选择数据

图 6-24

图 6-24。用于选择数据的隐式函数: (a) 选择椭圆中的二维单元格;(b) 使用联合操作组合两个椭球,用于从体积中选择体素。体素缩小了 50%。请参阅 ExtractData.cxxExtractData.py

 

选择数据。

我们可以利用隐函数的特性来选择和切割数据。特别是我们将使用区域分离属性来选择数据。(我们将关于切割的讨论推迟到“切割”。)

使用隐式函数选择或提取数据意味着选择位于函数特定区域内的单元格和点(以及相关的属性数据)。要确定点xyz是否位于区域内,我们只需评估该点并检查结果的符号。如果一个单元格的所有点都位于该区域内,则该单元格位于该区域内。

图 6-24(a) 显示了一个二维隐函数,这里是一个椭圆,用于选择其中包含的数据(即点、单元格和数据属性)。布尔组合也可用于创建复杂的选择区域,如图所示图 6-24(b)。在这里,结合使用两个椭圆来选择体积数据集中的体素。请注意,提取数据通常会更改数据集的结构。在图 6-24输入类型是图像数据数据集,而输出类型是非结构化网格数据集。

可视化数学描述。

一些函数,通常在本质上是离散的或概率的,不能转换为Equation6-11的形式。但是,通过应用一些创造性思维,我们通常可以生成可以可视化的标量值。一个有趣的例子是所谓的奇异吸引子

奇怪的吸引子出现在非线性动力学和混沌系统的研究中。在这些系统中,不存在通常类型的动态运动——平衡、周期性运动或准周期性运动。相反,系统表现出混沌运动。由于初始条件中的小扰动,系统的最终行为可能会发生根本性变化。

图 6-25
图 6-25。通过将 Lorenz 方程集成到一个体积中来可视化 Lorenz 奇异吸引子。每个体素中的访问次数被记录为一个标量函数。表面是通过使用访问值 50 的行进立方体提取的。集成步骤数为 1000 万,维度为 200^3。表面粗糙度是由评估函数的离散性质引起的。请参阅 Lorenz.cxxLorenz.py

Lorenz 在 1963 年开发了一个经典的奇异吸引子[Lorenz63]。Lorenz 为大气中的热致流体对流开发了一个简单的模型。对流引起旋转流体的环,并且可以从流体流动的一般 NavierStokes 偏微分方程发展而来。Lorenz 方程可以用无量纲形式表示为

(6-16)dXd=p()dd=rXXdd=Xb

在哪里X与流体环中的流体速度成正比,z 测量环平面内的流体温度,参数pr分别与普朗特数和罗利数有关,并且b是几何因子。

当然,这些方程不是方程 6-11 的隐式形式那么我们如何可视化它们呢?我们的解决方案是将变量x、y、z视为一个三维空间的坐标,将方程6-16积分生成系统“轨迹”,即系统在时间上的状态。积分在一个体积内进行,并且通过计算每个体素被访问的次数来创建标量。通过足够长的积分,我们可以创建一个表示奇怪吸引子“表面”的体积,图 6-25. 奇异吸引子的表面是通过使用行进立方体和指定体素中访问次数的标量值来提取的。

图6-26

图 6-26。到点、线和三角形的距离函数。

 

隐式建模

在上一节中,我们看到了如何使用隐式函数或隐式函数的布尔组合来对几何对象进行建模。基本方法是在规则的点数组或体积上评估这些函数,然后在体积中的每个点生成标量值。然后使用体积渲染(“体积渲染”)或等值面生成与表面渲染相结合来显示模型。

这种方法的扩展称为隐式建模,类似于使用隐式函数进行建模。不同之处在于标量是使用距离函数而不是通常的隐式函数生成的。距离函数计算为到一组生成图元(如点、线或多边形)的欧几里得距离。例如,图 6-26显示到点、线和三角形的距离函数。因为距离函数是表现良好的单调函数,我们可以通过指定不同的等值面值来定义一系列偏移曲面,其中值是到生成图元的距离。等值面形成了真实偏移表面的近似值,但使用高体积分辨率我们可以获得令人满意的结果。

单独使用生成图元在模拟复杂几何的能力方面受到限制。然而,通过使用基元的布尔组合,可以很容易地对复杂的几何图形进行建模。布尔运算并集、交集和差集(分别为Equation6-13Equation6-14Equation6-15)如图所示图 6-27图 6-28显示了应用隐式建模来“加厚”文本符号“HELLO”中的线段。等值面是在体积上生成的在 0.25 个单位的距离偏移处。使用布尔联合运算符组合生成原语。尽管欧几里得距离始终是非负值,但可以对具有外部和内部的对象使用有符号距离函数。负距离是对象内部的点到对象表面的负距离。使用有符号距离函数允许我们创建包含在实际表面中的偏移表面。隐式建模的另一个有趣特征是,当生成等值面时,可能会产生多个连接的曲面。当生成的图元形成凹特征时,就会出现这些情况。图 6-29说明了这种情况。如果需要,可以使用第 9 章“连通性”中描述的连通性算法来分离多个表面。

图6-27

图 6-27。使用点和线作为生成图元的布尔运算。

 

图 6-28

图 6-28。用于加粗描边字体的隐式建模。在半透明的隐式表面内可以看到原始线条。请参阅 Hello.cxxHello.py

 

图6-29

图 6-29。凹面特征可能导致多个等高线/曲面。

 

字形

字形,有时也称为图标,是一种可视化每种类型数据的通用技术。字形是受其输入数据影响的“对象”。该对象可以是几何图形、数据集或图形图像。字形可以响应数据来定向、缩放、平移、变形或以某种方式改变对象的外观。我们已经看到了一种简单形式的字形:刺猬是根据点的位置和矢量值定向、平移和缩放的线。一种变体是使用定向锥体或箭头。(有关详细信息,请参阅本章中的“刺猬和定向字形” 。)

更精细的字形是可能的。在一项创造性的可视化技术中,Chernoff [Chernoff73]将数据值与人脸的标志性表示联系起来。眉毛、鼻子、嘴巴和其他特征根据财务数据值进行了修改。这种有趣的技术建立在人类识别面部表情的能力之上。通过将适当的数据值与面部特征联系起来,可以快速识别重要的数据点。

图 6-30

图 6-30字形表示人脸模型上的表面法线。字形位置是随机选择的。请参阅 SpikeFran.cxxSpikeFran.py

 

从某种意义上说,字形代表了可视化过程的基本结果。此外,我们展示的所有可视化技术都可以视为抽象字形类的具体表示。例如,虽然刺猬是矢量字形的明显表现,但等值面可以被认为是标量数据的拓扑二维字形。Delmarcelle 和 Hesselink [Delmarcelle95]开发了一个基于字形类型的流可视化统一框架。他们根据三个类别之一对字形进行分类。

  • 基本图标代表其空间域范围内的数据。例如,定向箭头可用于表示表面法线。

  • 局部图标代表基本信息以及空间域周围值的局部分布。由局部曲率着色的表面法线向量是局部图标的一个示例,因为超出基本信息的局部数据被编码。

  • 全局图标显示完整数据集的结构。等值面是全局图标的一个示例。

这种分类方案可以扩展到其他可视化技术,例如矢量和张量数据,甚至可以扩展到非视觉形式,例如声音或触觉反馈。我们发现这种分类方案在设计可视化或创建可视化技术时很有帮助。通常,它可以深入了解表示可能被忽略的数据的方式。

图 6-30是字形的一个例子。小的 3D 圆锥在表面上定向以指示表面法线的方向。类似的方法可用于显示其他表面属性,例如曲率或解剖关键点。

切割

通常我们希望通过一个表面切割数据集,然后在表面上显示插值的数据值。我们将这种技术称为数据切割或简称切割。数据切割操作需要两条信息:表面的定义和要切割的数据集。我们将假设切割表面由隐式函数定义。切割的典型应用是用平面对数据集进行切片,并根据矢量值对标量数据进行彩色映射和/或扭曲平面。

图 6-31
图 6-31。用平面切割结构化网格。剖切面显示为实心阴影。一个恒定值的计算平面显示在线框中以进行比较。颜色对应于流动密度。切割面不一定是平面:也可以使用隐式函数,例如球体、圆柱体和二次曲面。请参阅 CutStructuredGrid.cxxCutStructuredGrid.py

隐式函数的一个属性是将位置转换为标量值(参见本章中的“隐式函数” )。我们可以将此属性与轮廓算法(例如,行进立方体)结合使用来生成切割表面。基本思想是为数据集的每个单元格的每个点生成标量(使用隐式割函数),然后对表面值进行轮廓化F(x,y,z)=0.

切割算法如下进行。对于每个单元格,通过评估生成函数值F(x,y,z)对于每个单元格点。如果所有点都评估为正或负,则表面不会切割单元格。但是,如果这些点评估为正值和负值,则表面会穿过单元格。我们可以使用细胞轮廓操作来生成等值面F(x,y,z)=0. 然后可以通过沿切割边缘插值来计算数据属性值。

图 6-31说明了穿过结构化网格数据集的平面。平面以法线 (–0.287, 0, 0.9579) 穿过数据集的中心。为了比较的目的,还显示了网格几何形状的一部分。网格几何是网格表面k = 9(以线框显示)。切割表面的一个好处是我们可以查看(几乎)任意表面上的数据。因此,数据集的结构不会限制我们查看数据的方式。

通过为切割算法指定多个等值,我们可以轻松地通过结构化网格数据集进行多个平面切割。图 6-32显示了 100 个垂直于相机视图平面法线的剖切面。以 0.05 的不透明度从后到前渲染平面会产生体积渲染的模拟(参见第 7 章中的“体积渲染”)。

图 6-32

图 6-32。100 个不透明度为 0.05 的切割平面。从后到前渲染以模拟体积渲染。请参阅 PseudoVolumeRendering.cxxPseudoVolumeRendering.py

 

此示例说明在结构化网格数据集中切割体积数据会产生多边形单元格。同样,切割多边形数据会产生线条。使用单平面方程,我们可以从用多边形定义的表面模型中提取“轮廓线”。图 6-33显示从皮肤表面模型中提取的轮廓。在曲面模型中的每个顶点,我们评估平面方程和F(x.y.z)=c并存储值函数作为标量值。从 1.5 到 136.5 用 46 个等值切割数据会产生相隔 3 个单位的等高线。

图 6-33

图 6-33。用一系列平面切割皮肤的表面模型会产生轮廓线。为了清晰起见,线条用管子包裹。请参阅 CutWithScalars.cxxCutWithScalars.py

 

6.6 放在一起

过程对象设计

算法在可视化工具包中实现为过程对象。这些对象可以是源、过滤器或映射器(参见第 4 章的“可视化管道”)。在本节中,我们将描述这些对象是如何实现的。

源设计。

 

图6-34a

(a) 功能模型

 

图6-34b

(b) 对象模型

 

图 6-34。源对象设计。所示示例是创建球体多边形表示的源对象。

 

源对象没有用于输入和一个或多个输出的可视化数据,图 6-34. 要创建源对象,继承用于指定流程对象为输出创建的数据集类型。vtkSphereSource。此类继承自vtkPolyDataAlgorithm,表明它在输出上创建多边形数据。

过滤器设计

过滤器对象有一个或多个输入和一个或多个输出,如图所示图 6-35. (您也可以参考第 4 章中的“流水线设计与实现”。)图 6-35一个过滤器对象,继承用于指定输入输出数据对象的类型。说明了具体源对象vtkContourFilter(实现行进立方体和其他轮廓技术)的这一点。值得详细研究此对象图,因为它是可视化管道架构的基础。

 

图6-35a

(a) 功能模型

 

图6-35b

(b) 对象模型

 

图 6-35。过滤器对象设计。所示示例适用于接收通用数据集作为输入并在输出上创建多边形数据的对象。

 

vtkContourFilter的超类是vtkAlgorithmvtkPolyData算法。vtkPolyData Algorithm类指定vtkContourFilter在输出时产生的数据类型(即vtkPolyData)。因为这个过滤器应该把 vtkDataSet 的任何子类作为输入,它必须覆盖它的超类实现 FillInputPortInformation() 方法来指定它。请注意,从vtkPolyData算法继承是可选的——这个功能可以直接在vtkContourFilter中实现。这个可选的超类只是一个方便的对象,使类派生更容易一些。

留给vtkContourFilter实现的是它的 RequestData() 方法(以及构造函数、打印方法和该类特殊的任何其他方法)。因此,具有等效继承层次结构的类之间的主要区别在于 RequestData() 方法的实现。

vtkAlgorithm的子类通过使用 FillInputPortInformation() 和 FillOutputPortInformation() 方法来强制过滤输入和输出类型。默认情况下,其子类[vtkDataSet](https://www.vtk.org/doc/nightly/html/classvtkDataSet.html#details)Algorithm接受输入类型vtkDataSet(或子类)并在输出时生成vtkDataSet。(输出的类型由输入的类型决定。)由于vtkDataSet是所有数据类型的基类,因此 [vtkDataSet] 的子类(https://www.vtk.org/doc/nightly/html/classvtkDataSet .html#details)算法将接受任何类型作为输入。专用过滤器派生自其他类。例如,接受多边形数据的过滤器可能来自vtkPolyDataAlgorithm,接受非结构化网格数据集的过滤器可能来自vtkUnstructuredGridAlgorithm

我们鼓励您仔细检查一些过滤器和源对象的源代码。

该架构非常简单,您可以快速掌握它。

映射器设计

 

图6-36a

(a) 功能模型

 

图6-36b

(b) 对象模型

 

图 6-36。映射器对象设计。显示的图形映射器(例如,vtkPolyDataMapper)通过图形库图元映射多边形数据。所示的写入器(例如,vtkSTLWriter)将多边形数据写入立体光刻格式。

 

映射器对象有一个或多个输入,没有可视化数据输出,图 6-36Visualization Toolkit中提供了两种不同类型的映射器:图形映射器和编写器。图形映射器将几何结构和数据属性连接到图形库;writer 将数据集写入磁盘或其他 I/O 设备。

由于映射器将数据集作为输入,因此需要类型强制。每个映射器都直接实现此功能。例如,vtkPolyData Mapper 和vtkSTLWriter类都实现了 SetInput() 方法来强制输入为vtkPolyData类型。其他映射器和编写器根据需要强制执行输入类型。

虽然 writer 和 mapper 不创建可视化数据,但它们都有类似于源和过滤器的 RequestData() 方法的方法。vtkMapper的每个子类都必须实现 Render() 方法。此方法在渲染过程中由图形系统参与者及其关联的映射器交换。该方法的效果是将其输入数据集映射到适当的渲染库/系统。vtkWriter类的子类必须实现 WriteData() 方法。此方法使写入器将其输入数据集写入磁盘(或其他 I/O 设备)。

彩色地图

使用vtkLookupTable类的实例在Visualization Toolkit中创建颜色图。此类允许您使用 HSVA(例如,色调、饱和度、值和 alpha 不透明度值)规范创建查找表。尽管我们在第 3 章 – 计算机图形学入门中讨论了 HSV 颜色系统,但我们还没有定义 alpha 不透明度。我们将在第 7 章 – 高级计算机图形学中这样做,但在那之前,我们将 alpha 值视为对象的不透明度。Alpha 值 1 表示对象是不透明的,而 Alpha 值为零表示对象是透明的。

生成查找表条目的过程是为 HSVA 定义值对。这些对定义了色调、饱和度、值和不透明度的线性渐变。当调用 Build() 方法时,这些线性斜坡用于生成具有请求的表条目数的表。或者,vtkLookupTable还允许您将颜色直接加载到表中。因此,您构建的自定义表格不能简单地表示为 HSVA 值的线性斜坡。为了演示这个过程,我们为 HSVA 的每个组件指定一个开始和结束值,然后我们将使用以下 C++ 代码创建一个从蓝色到红色的彩虹查找表。

vtkLookupTable *lut = vtkLookupTable::New();
  lut->SetHueRange(0.6667, 0.0);
  lut->SetSaturationRange(1.0, 1.0);
  lut->SetValueRange(1.0, 1.0);
  lut->SetAlphaRange(1.0, 1.0);
  lut->SetNumberOfColors(256);
  lut->Build();

由于 SaturationRange、ValueRange、AlphaRange 和查找表颜色数的默认值分别为 (1,1)、(1,1)、(1,1) 和 256,我们可以将此过程简化为以下

vtkLookupTable *lut = vtkLookupTable::New();
  lut->SetHueRange(0.6667, 0.0);
  lut->Build();

(HueRange 的默认值为 (0.0, 0.6667) — 红到蓝的颜色表。)

为了构建一个包含 256 个条目的黑白查找表,我们使用

vtkLookupTable *lut = vtkLookupTable::New();
  lut->SetHueRange(0.0, 0.0);
  lut->SetSaturationRange(0.0, 0.0);
  lut->SetValueRange(0.0, 1.0)

在某些情况下,您可能希望直接指定颜色。您可以通过指定颜色数量、构建表格然后插入新颜色来完成此操作。插入颜色时,将使用 RGBA 颜色描述系统。例如,要创建红色、绿色和蓝色三种颜色的查找表,请使用以下 C++ 代码。

vtkLookupTable *lut = vtkLookupTable::New();
  lut->SetNumberOfColors(3);
  lut->Build();
  lut->SetTableValue(0, 1.0, 0.0, 0.0, 1.0);
  lut->SetTableValue(0, 0.0, 1.0, 0.0, 1.0);
  lut->SetTableValue(0, 0.0, 0.0, 1.0, 1.0);

Visualization Toolkit中的查找表与图形映射器相关联。如果未指定表,Mappers 将自动创建一个从红到蓝的查找表,但如果您想创建自己的,请使用 mapper->SetLookupTable(lut) 操作,其中 mapper 是vtkMapper或其子类的实例。

关于使用查找表的最后几点说明。

  • 映射器使用他们的查找表将标量值映射到颜色。如果不存在标量,则映射器及其查找表不会控制对象的颜色。而是与vtkActor类关联的vtkProperty对象。使用vtkProperty的方法,其中 r、g 和 b 是指定颜色的浮点值。actor->GetProperty()->SetColor(r,g,b)

  • 如果要防止标量为对象着色,请使用vtkMapper的方法 mapper->ScalarVisibilityOff() 关闭颜色映射。然后演员的颜色将控制对象的颜色。

  • 标量范围(即颜色映射到的范围)由映射器指定。使用方法mapper->SetScalarRange(min, max)

您还可以派生自己的查找表类型。以vtkLogLookupTable为例。这个特定的查找表继承自vtkLookupTable。它执行标量值到表条目的对数映射,当标量值跨越多个数量级时,这是一种有用的功能。

隐式函数

图6-37

图 6-37。vtkImplicitFunction 和子类的继承层次结构。

 

正如我们所见,隐式函数可用于可视化函数、创建几何图形以及剪切或选择数据集。VTK 包括几个隐式函数,包括单个平面 ( vtkPlane )、多个凸平面 ( vtkPlane )、球体 ( vtkSphere )、圆锥体 ( vtkCone )、圆柱体 ( vtkCylinder ) 和一般二次曲面 ( vtkQuadric )。vtkImplicitBoolean类允许您创建这些隐式函数原语的布尔组合。通过从抽象基类vtkImplicitFunction派生,可以将其他隐式函数添加到 VTK 。

隐式函数的现有继承层次结构显示在图 6-37vtkImplicitFunction的子类必须实现两个方法 Evaluate() 和 Gradient(x)。Evaluate() 方法返回函数在点 (x,y,z) 处的值,而 Gradient() 方法将梯度向量返回给函数在点 (x,y,z) 处的值。

轮廓

标量轮廓在Visualization Toolkit中使用vtkContourFilter 实现。此过滤器对象接受任何数据集类型作为输入。因此,vtkContourFilter会处理每种细胞类型,并且每种细胞类型都必须提供一种对自身进行轮廓化的方法。

VTK 中的轮廓是使用前面介绍的行进立方体算法的变体实现的。也就是说,轮廓案例表与每个单元格类型相关联,因此每个单元格将适当地生成轮廓图元。例如,四面体单元类型实现“行进四面体”并创建三角形基元,而三角形单元类型实现“行进三角形”并生成线段。

这种安排的含义是vtkContourFilter将根据输入单元类型的组合生成点、线和表面轮廓图元。因此vtkContourFilter是完全通用的。我们创建了另一个轮廓过滤器vtkMarchingCubes,它特定于数据集类型的图像数据(特别是 3D 体积)。这两个过滤器允许我们比较(至少对于这个算法)一般性的成本。

回想一下“通用性与效率”中有关通用算法和特定算法之间权衡的问题。图 6-38显示卷数据集的 CPU 时间比较,64×64×93, 和分辨率128×128×93. 该卷是人头的 CT 数据集。运行了三个案例。在第一种情况下,使用了vtkMarchingCubes对象。这个过滤器的输出是三角形加点法线。在第二种情况下,运行了vtkContourFilter。这个过滤器的输出只是三角形。在最后一种情况下,vtkContourFiltervtkPolyDataNormals结合(生成点法线)。组合过滤器的输出也是三角形加点法线。

使用vtkMarchingCubes对象将执行时间标准化为最小的数据集。结果很明确:特定对象的性能优于一般对象 1.4 到 7 倍,具体取决于数据大小和是否计算法线。较大的差异发生在较小的数据集上。这是因为对于较小的数据集,包含等值面的体素单元与体素总数的比率较大。(通常,体素的总数随着分辨率的立方而增加,而包含等值面的体素随着分辨率的平方而增加。)因此,相对于体素总数,在较小的数据集中处理的体素比在较大的数据集中处理的多。 . 当数据集变得更大时,更多的体素是“空的”并且不被处理。

尽管这些结果并不代表所有实现或其他算法的行为,但它们确实表明了一般性的代价。当然,专业化也是有成本的。这种成本通常是程序员的时间,因为程序员必须重写代码以适应新的环境和数据。与所有权衡一样,解决此问题需要了解应用程序。

图6-38
图 6-38。普遍性的成本。比较了三个不同大小的体积的等值面生成。结果显示了行进立方体等值面算法的两种不同实现的标准化执行时间。专门的过滤器是 vtkMarchingCubes。一般算法是先vtkContourFilter,然后结合vtkPolyDataNormals。

vtkContourFilter的使用示例显示在图 6-39. 这个例子取自图 4-1,它是一个二次函数的可视化。vtkSampleFunction 类使用 vtkQuadric隐式二次函数进行采样。虽然vtkQuadric在数据流方面不参与管道,但它用于定义和评估二次函数。可以使用vtkContourFilter同时生成一个或多个等值线/等值面。作为图 6-39如图所示,我们使用 GenerateValues() 方法指定一个标量范围,以及此范围内的轮廓数(包括初始和最终标量值)。vtkContourFilter 会生成重复的顶点,所以我们可以使用vtkCleanPolyData来移除它们。为了改善等值面的渲染外观,我们使用vtkPolyDataNormals来创建表面法线。(我们在第 9 章 – 高级算法中描述了正常生成。)

// Define implicit function
vtkQuadric *quadric = vtkQuadric::New();
  quadric->SetCoefficients(.5,1,.2,0,.1,0,0,.2,0,0);
vtkSampleFunction *sample = vtkSampleFunction::New();
  sample->SetSampleDimensions(50,50,50);
  sample->SetImplicitFunction(quadric);
vtkContourFilter *contour = vtkContourFilter::New();
  contour->SetInputConnection(sample->GetOutputPort());
  contour->GenerateValues(5,0,1.2);
vtkPolyDataMapper *contourMapper = vtkPolyDataMapper::New();
  contourMapper->SetInputConnection( contour->GetOutputPort());
  contourMapper->SetScalarRange(0,1.2);
vtkActor *contourActor = vtkActor::New();
  contourActor->SetMapper(contourMapper);
// Create outline
vtkOutlineFilter *outline = vtkOutlineFilter::New();
  outline->SetInputConnection(sample->GetOutputPort());
vtkPolyDataMapper *outlineMapper = vtkPolyDataMapper::New();
  outlineMapper->SetInputConnection(outline->GetOutputPort());
vtkActor *outlineActor = vtkActor::New();
  outlineActor->SetMapper(outlineMapper);
  outlineActor->GetProperty()->SetColor(0,0,0);

图 6-39

图 6-39。轮廓二次函数。显示了管道拓扑、C++ 代码和生成的图像。请参阅 ContourQuadric.cxxContourQuadric.py

 

图6-40

图 6-40。数据流入和流出 vtkGlyph3D 类。

 

切割

vtkCutter执行所有 VTK 单元类型的切割。SetValue() 和 GenerateValues() 方法允许用户指定用于切割的多个标量值。vtkCutter需要一个隐式函数,该函数将在数据集中的每个点进行评估。然后使用单元格的轮廓方法切割每个单元格。任何点属性都被插值到生成的切割顶点。可以使用 SortBy 方法控制生成的多边形数据的排序顺序。默认排序顺序 SortByValue() 会在内部循环中处理每个轮廓值的单元格。SortByCell() 处理内部循环中的切割值并生成适合从后到前渲染的多边形数据(参见图 6-32)。(在第 7 章 – 高级计算机图形学中讨论的不透明度渲染时,排序顺序很有用。)注意这个过滤器与vtkContourFilter的相似之处。这两个对象都勾勒出具有多个等值的数据集。vtkCutter使用隐式函数来计算标量值,而vtkContourFilter使用与数据集的点数据关联的标量数据。

字形

vtkGlyph3D类在Visualization Toolkit提供了一个简单但功能强大的字形功能。vtkGlyph3D是一个接受多个输入的对象示例 (图 6-40)。使用 SetInputConnection() 方法指定的一个输入定义了一组点和这些点处可能的属性数据。使用 SetSourceConnection() 方法指定的第二个输入定义了要复制到输入数据集中每个点的几何图形。源是vtkPolyData类型。因此,可以使用任何过滤器、创建多边形数据的过滤器序列或多边形数据集来描述字形的几何形状。

vtkGlyph3D实例的行为取决于输入数据的性质及其实例变量的值。通常,输入源几何图形将被复制到输入数据集的每个点。几何图形将沿输入矢量数据对齐,并根据矢量的大小或标量值进行缩放。在某些情况下,使用点法线而不是矢量。此外,可以打开或关闭缩放。

我们在图4–20给出的示例中看到了如何使用vtkGlyph3D。锥体被用作字形并位于球体上的每个点上,沿球体的表面法线定向。

图6-41

图 6-41。vtkStreamer 和子类的继承层次结构。

 

流线型

流线和粒子运动需要数值积分来引导一个点通过矢量场。我们将在后面章节中看到的矢量可视化算法也需要数值积分。因此,我们设计了一个对象层次结构,将数值积分过程隔离到一个单一的基类中。基类是 vtkStreamer,它负责通过指定长度(表示为经过时间)的向量场生成粒子路径。vtkStreamer 的每个派生类都利用这种能力在矢量场中移动,但实现了自己特定的表示技术来描述粒子运动。流线 (vtkStreamLine) 绘制连接线,同时通过将 vtkStreamPoints 的输出与 vtkGlyph3D 相结合来显示粒子运动目的。使用vtkGlyph3D,我们可以在 vtkStreamPoints 创建的粒子路径上的点上放置球体或定向对象,例如圆锥体或箭头。vtkStreamer 和子类的继承层次结构显示在图 6-41.

vtkStreamer 中的集成方法是作为虚函数实现的。因此,它可以根据需要进行重载。重载的可能原因包括实现更高或更低精度的集成技术,或创建专门用于特定数据集类型的技术。例如,卷中的搜索过程比其他数据集类型快得多,因此可以构建高效的向量集成技术。

VTK 中的载体整合技术将适应任何细胞类型。因此,通过任何拓扑维度的单元进行集成是可能的。如果单元的拓扑维度为 2 或更小,则积分过程将粒子运动限制在表面 (2D) 或线 (1D) 上。粒子只能通过穿过单元边界、移动到相邻单元或离开数据集来离开单元。

抽象过滤器

属性转换创建或修改数据属性而不更改数据集的拓扑或几何。因此,实现属性转换的过滤器(例如,vtkElevationFilter)可以接受任何数据集类型作为输入,并且可以在输出上生成任何数据集类型。不幸的是,由于过滤器必须专门化它们输出的特定类型的数据,乍一看,在输出上创建通用数据集类型的过滤器似乎是不可行的。这是因为类型vtkDataSet是一种抽象类型,必须专门化以允许实例化。

幸运的是,有一个解决这个困境的方法。解决方案是使用“虚拟构造函数”NewInstance()。尽管 C++ 不允许使用虚构造函数,但我们可以通过创建一个特殊的虚函数来模拟它,该虚函数构造调用它的对象的副本。例如,如果将此函数应用于vtkPolyData类型的数据集实例,则结果将是该实例的副本(图 6-42)。(请注意,我们使用引用计数来制作副本并避免重复内存。)虚拟构造函数 NewInstance() 在许多 VTK 类中实现,包括数据集和单元格。

图6-42

图 6-42。抽象过滤器输出的数据流描述。输出对象类型与输入类型相同。

 

使用虚拟构造函数,我们可以构建输出抽象数据类型的过滤器,例如vtkDataSet。我们只需将 NewInstance() 应用于过滤器的输入。然后,这将返回一个指向作为过滤器输出的具体对象的指针。结果是一个通用过滤器对象,它可以接受任何数据集类型作为输入,并创建通用vtkDataSet类型作为输出。在 VTK 中,此功能已在抽象类[vtkDataSet](https://www.vtk.org/doc/nightly/html/classvtkDataSet.html#details)Algorithm中实现。

还有其他过滤器可以实现这种委托技术的变体。类[vtkPointSet](https://www.vtk.org/doc/nightly/html/classvtkPointSet.html#details)Algorithm类似于vtkDataSetAlgorithm。此类将其几何通过vtkPoints(或子类)的实例明确定义的任何数据集作为输入,并在输出时生成相同类型的对象(即vtkPointSet)。vtkMergeFilter类结合了来自一个或多个输入数据集的数据集结构和点属性。例如,您可以读取多个文件并将一个文件中的几何/拓扑与其他文件中的不同标量、向量和法线组合起来。

使用抽象过滤器类型的一个困难是输出类型可能与下游过滤器的输入类型不匹配。例如,即使输入可能是 vtkPolyData 类型vtkElevationFilter的输出也被指定为vtkDataSet,并且我们从前面的讨论中知道实际的输出类型将是vtkPolyData。使用过滤器vtkCastToConcrete消除了这个困难,它允许您在运行时强制转换为适当的输出类型。在这种情况下,我们将使用 vtkCastToConcrete 中的 GetPolyDataOutput( )。在检查强制转换的有效性后,此方法返回一个数据集强制转换到vtkPolyData. 当然,这个过程需要在请求输出之前设置vtkCastToConcrete的输入。

可视化血流

在这个例子中,我们将结合几种不同的技术来可视化人类颈动脉中的血流。我们的数据包含表示血液速度的向量和与速度(即速度)的大小成比例的标量。

我们可以通过创建速度等值面来为可视化提供上下文。该等值面显示了血流速度最快的区域,与动脉的实际表面相似但不相同。然而,它为我们提供了动脉结构的视觉提示。我们将使用的第一个矢量可视化技术是生成矢量字形(不幸的是,由于点的数量(超过 167,000 个点),我们不能只在每个点上创建字形。这样做会导致混乱,并且交互速度会很差。相反,我们将使用两个过滤器来选择可用点的子集。这些过滤器是vtkThresholdPointsvtkMaskPoints

vtkThresholdPoints允许我们提取满足某个阈值标准的点。在我们的示例中,我们选择速度大于指定值的点。这消除了大量的点,因为大多数点位于动脉之外并且具有较小的速度值。

过滤器vtkMaskPoints允许我们选择可用点的子集。我们使用 OnRatio 实例变量指定子集。此实例变量指示要选择每个 OnRatio 点。因此,如果 OnRatio 等于 1,则将选择所有点,如果 OnRatio 等于 10,则将选择每 10 个点。这种选择可以是统一的,也可以是随机的。使用 RandomModeOn() 和 RandomModeOff() 方法设置随机点选择。

选择原始点的子集后,我们可以按照通常的方式使用vtkGlyph3D过滤器。锥体的方向表示血流方向,其大小和颜色对应于速度大小。图 6-43显示了管道、示例代码和来自此可视化的结果图像。请注意,我们已经使用解释型语言 Tcl 实现了该示例。如果您想了解有关 Tcl的更多信息,请参阅第 11 章 – Web 上的可视化。

在本示例的下一部分中,我们将生成血流速度流管。我们再次使用速度等值面来为我们提供上下文。流管的起始位置是通过试验数据确定的。由于测量数据的方式和速度场的分辨率,许多拖缆在动脉外传播。这是因为由于数据分辨率的限制,没有捕获血流的边界层。因此,当血液绕曲线流动时,速度场中有一个分量将流管引导到动脉外。因此,很难找到产生有趣结果的流管的起始位置。我们将源对象vtkPointSourcevtkThresholdPoints结合使用解决这个问题。vtkPointSource生成以指定半径的球体为中心的随机点。我们只需要找到流管起点的大致位置,然后生成随机种子点云。vtkThresholdPoints用于剔除可能在高流速区域之外生成的点。

图 6-44显示了管道、示例 Tcl 代码和可视化的结果图像。请注意,等值面以线框形式显示。这提供了上下文,但允许我们看到等值面内的流管。

vtkStructuredPointsReader reader
 reader SetFileName "$env(VTK_TEXTBOOK_DATA)/carotid.vtk"
vtkThresholdPoints threshold
  threshold SetInputConnection [reader GetOutputPort]
  threshold ThresholdByUpper 200
vtkMaskPoints mask
  mask SetInputConnection [Threshold GetOutputPort]
  mask SetOnRatio 10
vtkConeSource cone
  cone SetResolution 3
  cone SetHeight 1
  cone SetRadius 0.25
vtkGlyph3D cones
  cones SetInputConnection [mask GetOutputPort]
  cones SetSourceConnection [cone GetOutputPort]
  cones SetScaleFactor 0.5
  cones SetScaleModeToScaleByVector
vtkLookupTable lut
  lut SetHueRange.667 0.0
  lut Build
vtkPolyDataMapper vecMapper
  vecMapper SetInputConnection [cones GetOutputPort]
  vecMapper SetScalarRange 2 10
  vecMapaper SetLookupTable lut

图 6-43

图 6-43。可视化人颈动脉中的血流。锥形字形指示流动方向和大小。请参阅 CarotidFlowGlyphs.cxxCarotidFlowGlyphs.py

 

图 6-44

图 6-44。可视化人颈动脉中的血流。流向量的流管 (streamV.tcl)。参见 CarotidFlow.cxxCarotidFlow.py

 

6.7 章节总结

可视化算法将数据从一种形式转换为另一种形式。这些转换可以更改或创建数据集的新结构和/或属性。结构转换会改变数据集的拓扑或几何。属性转换会更改数据集属性,例如标量、向量、法线或纹理坐标。

算法根据它们操作的数据类型进行分类。标量、向量和张量算法分别对标量、向量和张量数据进行操作。建模算法对数据集几何或拓扑、纹理坐标或法线进行操作。建模算法还可能包括可以表示不同数据类型组合的复杂技术。

算法可以针对一般类型的数据设计和实现,也可以专门针对特定类型。通用算法的效率通常低于其专用算法。相反,通用算法更灵活,不需要重写,因为引入了新的数据集类型。

重要的标量算法包括颜色映射和轮廓。颜色映射用于将标量值映射到颜色值。等高线算法创建等值面或等值线来指示恒定标量值的区域。

像刺猬这样的字形对于可视化矢量数据很有用。这些技术受到一次可以显示的字形数量的限制。粒子轨迹或流线是矢量场可视化的另一个重要算法。粒子轨迹的集合可以传达向量场的某些结构。

实对称张量3×3可以通过它们的特征值和特征向量来表征。

张量可以使用张量椭圆体或定向轴来可视化。

隐式函数和采样技术可用于制作几何图形、切割数据和可视化复杂的数学描述。字形是其外观与特定数据值相关联的对象。字形很灵活,可以创建以可视化各种数据。

6.8 书目注释

颜色映射是成像、计算机图形学、可视化和人为因素中广泛研究的主题。参考文献[Durrett87] [Ware88 ] [Rheingans92 ]提供了可用文献的样本。您可能还想了解颜色对感知的生理和心理影响。Wyszecki 和 Stiles [Wyszecki82]的文本作为介绍性参考。

由于其重要性和受欢迎程度,轮廓是一种在可视化中被广泛研究的技术。早期技术是针对 2D 数据开发的[Watson92]。三维技术最初是作为轮廓连接方法[Fuchs77]开发的——即,在均匀间隔的平面上给定一系列 2D 轮廓,连接轮廓以创建闭合曲面。自从引入行进立方体[Lorensen87]以来,已经实现了许多其他技术。(其中一些包括[Nielson91] [Montani94][Durst88])。Livnat 等人给出了一个特别有趣的参考资料。[Livnat96]. 他们展示了一种添加了预处理步骤的轮廓方法,该步骤可以在接近最佳的时间生成等高线。

尽管我们几乎没有触及这个话题,但对混沌和混沌振动的研究是一个非常有趣的话题。除了 Lorenz [Lorenz63]的原始论文,Moon [Moon87]的书是一个很好的起点。

二维和三维矢量图已被计算机分析师使用多年[Fuller80]。流线和流带也已应用于复杂流的可视化[Volpe89][Helman90][Richter90]中给出了有关矢量可视化技术的良好通用参考资料。

张量可视化技术的数量相对较少。大多数技术都是面向字形的[Haber90] [deLeeuw93]我们将在第 9 章 – 高级算法中看到更多技术。

Blinn [Blinn82]、Bloomental [Bloomenthal88] [Bloomenthal97]和 Wyvill [Wyvill86]是隐式建模的重要贡献者。隐式建模目前在计算机图形学中很流行,用于对“软”或“斑点”对象进行建模。这些技术简单、强大,并且正被广泛用于高级计算机图形建模。

6.9 参考文献

[Abraham85] RH 亚伯拉罕和克里斯托弗 D. 肖。动力学行为的几何学。空中印刷机,加利福尼亚州圣克鲁斯,1985 年。

[Blinn82] JF 布林。“代数曲面绘图的推广。” ACM 图形事务。1(3):235–256,1982 年 7 月。

[Bloomenthal88] J. 布鲁门塔尔。“隐式曲面的多边形化”。计算机辅助几何设计 5(4):341–355,1982 年 11 月。

[Bloomenthal97] J. Bloomenthal,编辑。隐式曲面简介。Morgan Kaufmann Publishers, Inc.,加利福尼亚州旧金山,1997 年。

[切尔诺夫73] H.切尔诺夫。“使用面以图形方式表示K维空间中的点。” J. 美国 统计协会。68:361–368, 1973。

[Cline93] H. Cline、W. Lorensen 和 W. Schroeder。“脑血流和表面解剖学的 3D 相位对比 MRI。” 计算机辅助断层扫描杂志。17(2):173–177,1993 年 3 月/4 月。

[Conte72] SD Conte 和 C. de Boor。初等数值分析。麦格劳希尔图书公司,1972 年。

[deLeeuw93]。WC de Leeuw 和 JJ van Wijk。“局部流场可视化的探针”。在可视化 ’93论文集 。第 39–45 页,IEEE 计算机学会出版社,加利福尼亚州洛斯阿拉米托斯,1993 年。

[Delmarcelle95] T. Delmarcelle 和 L. Hesselink。“流可视化的统一框架。” 在用于科学和工程分析的计算机可视化图形技术中*。RS加拉格尔,编辑。CRC 出版社,佛罗里达州博卡拉顿,1995 年。

[Durrett87] HJ Durrett 编辑。颜色和计算机。学术出版社,马萨诸塞州波士顿,1987 年。

[Durst88] MJ 德斯特。“对行进立方体的附加参考。” 计算机图形学。22(2):72–73, 1988。

[Fuchs77] H. Fuchs、ZM Kedem 和 SP Uselton。“平面轮廓的最佳表面重建”。ACM 的通信。20(10):693–702, 1977。

[富勒80] cA。J. 富勒和 MLX 多斯桑托斯。“计算机生成的 3D 矢量场显示。” 计算机辅助 设计。12(2):61–66, 1980。

[Haber90] RB Haber 和 DA 麦克纳布。“可视化习语:科学可视化系统的概念模型。” 科学计算中的可视化, GM Nielson、B. Shriver、LJ Rosenblum 编辑。IEEE 计算机协会出版社,第 61–73 页,1990 年。

[Helman90] J. Helman 和 L. Hesselink。“流体流动数据集中矢量场拓扑的表示和显示”。科学计算中的可视化。GM Nielson、B. Shriver、LJ Rosenblum 编辑。IEEE 计算机协会出版社,第 61–73 页,1990 年。

[Livnat96] Y. Livnat,HW Shen,CR 约翰逊。“结构化和非结构化网格的近乎最优等值面提取算法。” IEEE 可视化和计算机图形学汇刊。卷。2,第 1 号,1996 年 3 月。

[Lorensen87]我们洛伦森和他克莱恩。“行进立方体:高分辨率 3D 表面构造算法。” 计算机图形学。21(3):163–169,1987 年 7 月。

[洛伦兹63] EN 洛伦兹。“确定性非周期性流。” 大气科学杂志。20:130–141, 1963。

[Montani94] 抄送。蒙塔尼、R. Scateni 和 R. 斯科皮尼奥。“用于行进立方体隐式消歧的改进查找表。” 视觉计算机 (10):353–355, 1994。

[Moon87] FC 月亮。混沌震动 WileyInterscience,纽约,纽约,1987 年。

[Nielson91]通用汽车尼尔森和 B.哈曼。“渐近决策者:解决行进立方体中的歧义。” 在可视化 ’91 论文集。第 83–91 页,IEEE 计算机协会出版社,加利福尼亚州洛斯阿拉米托斯,1991 年。

[Rheingans92] P. Rheingans。“定量数据显示的颜色、变化和控制”。在可视化论文集 ’92中。第 252–259 页,IEEE 计算机协会出版社,加利福尼亚州洛斯阿拉米托斯,1992 年。

[Richter90] R. Richter、JB Vos、A. Bottaro 和 S. Gavrilakis。“流动模拟的可视化”。科学 可视化和图形模拟。D. Thalmann 编辑,第 161–171 页,John Wiley and Sons,1990。

[Saada74]作为萨达。弹性理论与应用。佩加蒙出版社,纽约,纽约,1974 年。

[Timoshenko70] SP Timoshenko 和 JN Goodier。弹性理论,3d 版。麦格劳希尔图书公司,纽约,纽约,1970 年。

[Tufte83] ER 塔夫特。定量信息的视觉展示。图形出版社,康涅狄格州柴郡,1990 年。

[Volpe89] G.沃尔普。“空气动力学中的流线和流带。” 技术报告 AIAA-89-0140,第 27 届航空航天科学会议,1989 年。

[Ware88] C. 洁具。“单变量地图的颜色序列:理论、实验和原理。” IEEE 计算机图形学和应用程序。8(5):41–49, 1988。

[Watson92] DF 沃森。轮廓:空间数据分析和显示指南。佩加蒙出版社,1992 年。

[Wyszecki82] G. Wyszecki 和 W. Stiles。色彩科学:概念和方法、定量数据和公式。约翰威利父子,1982 年。

[Wyvill86] G. Wyvill、C. McPheeters、B. Wyvill。“软对象的数据结构”。视觉计算机。2(4):227–234, 1986。

© 版权声明
THE END
喜欢就支持一下吧
点赞2.3W+ 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容