原创 《vtk9 book》 官方web版 第四章 - 可视化管线(2 / 2)

        请注意AddInputConnection()方法的使用。该方法向连接列表中添加连接,而SetInputConnection()方法则清除列表并指定连接到端口的单个连接。

        另一个重要的过滤器类是vtkProbeFilter。该过滤器需要两个输入。第一个输入是我们希望探测的数据。第二个输入提供一组用作探测点的点。一些处理对象需要输入数据的列表。另一个有趣的过滤器是vtkBooleanStructuredPoints类,它在体数据集上执行集合操作。列表中的第一个数据项用于初始化集合操作。列表中的每个后续项都使用用户指定的布尔运算符与前面操作的结果组合。

        有关过滤器和数据对象的对象设计的更多详细信息,请参阅第5章 - 数据表示和第6章 - 基本算法。

  

     管道执行和信息对象

        直到现在,我们一直比较随意地使用元数据和信息对象这两个术语。如前所述,在VTK的上下文中,这些术语指的是描述数据集的数据。在本节中,我们将展示这些对象,它们是vtkInformation的子类,如何用于促进VTK管道的执行。

        信息对象。信息对象是整个VTK管道中用于保存各种元数据的基本容器。它们是异构的键值映射,其中键的类型决定了值的类型。以下是信息对象使用的列举。

        管道信息对象保存管道执行的信息。它们存储在vtkExecutive或其子类的实例中,并且可以通过方法vtkExecutive::GetOutputInformation()访问。每个输出端口对应一个管道信息对象。它包含一个条目,指向在相应端口上已创建的输出vtkDataObject(如果已创建)。vtkDataObject包含一个指针,指向其相应的管道信息对象,可通过vtkDataObject::GetPipelineInformation()方法访问。管道信息对象还保存有关在过滤器执行并生成输出时将填充数据对象的信息。所包含的实际信息由输出数据类型和使用的执行模型确定。输入连接的管道信息对象可以通过方法vtkExecutive::GetInputInformation()访问,它们是与输入端口连接的输出端口上的管道信息对象。

        端口信息对象保存有关输出端口生成的数据类型和输入端口消耗的数据类型的信息。它们由vtkAlgorithm的实例存储。每个输入端口对应一个输入端口信息对象,每个输出端口对应一个输出端口信息对象。可以通过方法vtkAlgorithm::GetInputPortInformation()和vtkAlgorithm::GetOutputPortInformation()访问它们。端口信息对象通常由vtkAlgorithm的子类创建和填充,以指定过滤器的接口。

        请求信息对象保存有关发送给执行器或算法的特定请求的信息。有一个条目指示发送的请求是什么,可能还有其他条目提供有关特定请求的其他详细信息。这些信息对象不能通过任何公共方法访问,而是传递给实现请求的ProcessRequest()方法。

        数据信息对象保存有关vtkDataObject中当前存储的内容的信息。每个数据对象中都有一个数据信息对象,可以通过vtkDataObject::GetInformation()方法访问。所包含的实际信息由数据对象类型确定。

        算法信息对象保存有关vtkAlgorithm实例的信息。每个算法对象对应一个算法信息对象,可以通过vtkAlgorithm::GetInformation()方法访问。所包含的实际信息由算法对象类型确定。

        信息对象在VTK中的重要性在于它们是灵活的(例如,可以轻松添加新的键值对)和可扩展的。也就是说,读取器、过滤器和映射器可以向容器中添加新的信息,而不需要改变与管道相关的类的API。

        管道执行模型。在VTK中,基本的管道更新机制基于请求。请求是一种基本的管道操作(或“管道传递”),通常要求通过管道传播特定的信息片段。执行模型是由特定执行器定义的一组请求。有关执行过程的描述,请参阅以下执行过程描述中的图4-18。

        图4-18. 请求通过管道发送的路径。例如,假设消费者(在最右边)只需要这些数据的一个片段(例如,4个中的第1个片段);同时假设生产者(在最左边)是一个可以将其数据分成片段的读取器。消费者将此请求向上传递,它会继续向上(通过执行者),直到到达能够满足请求的生产者。当读取器算法被要求提供数据的一个片段时,它会提供,并将新数据(带有它是4个片段中的第1个的信息)沿着管道传递回去。当它到达发出请求的消费者时,它停止。

        请求被执行为信息对象。有一个vtkInformationRequestKey类型的键,指定请求本身。该键通常由执行者的类定义。有关请求的其他信息也可以存储在请求信息对象中。

        请求通过每个过滤器的执行者传播管道。对于给定的请求信息对象,会在执行者上调用vtkExecutive::ProcessRequest()方法。这个方法由每个执行者实现,负责根据自己认为合适的方式满足请求。对于某些请求,只有在满足了提供其输入的过滤器的请求之后,才能为过滤器满足请求。对于这些请求,执行者将将请求传递给这些上游过滤器的执行者,然后处理请求本身。

        执行者通常会请求其算法对象的帮助来满足请求。它通过调用vtkAlgorithm::ProcessRequest()方法将请求发送到算法对象。所有算法都实现了这个方法,并负责处理请求。输入和输出管道信息对象作为参数提供给方法。算法必须仅使用自己的过滤器参数设置和给定的管道信息对象来处理请求。算法不允许向其执行者请求任何其他信息。这确保了算法独立于执行者。图4-18显示了请求在通过管道发送时通常采取的路径。通常,请求起源于管道末端的消费者。它通过执行者再次传递回管道。每个执行者都会请求其算法来帮助处理请求。

        灵活的计算/内存权衡


        默认情况下,使用可视化工具包构建的网络存储中间计算结果(即,更青睐计算)。但是,可以设置一个类变量,以在不再需要中间数据时丢弃它们(即,更青睐内存)。此外,可以在每个处理对象中设置本地参数,以控制对象级别的此权衡。

设置全局变量如下。给定数据对象O(或使用O=filter->GetOutput()获得的过滤器的输出),调用O->SetGlobalReleaseDataFlagOn()以启用数据释放。要为特定对象启用数据释放,请使用O->SetReleaseDataFlagOn()。还存在适当的方法来禁用内存释放。

高级对象设计


        在本文的这一点上,描述构成可视化管道的各种对象的设计细节尚为过早。但是,有两个重要的类影响了文本中许多对象。这些是类vtkObject和vtkObjectBase。

                vtkObjectBase是VTK中几乎所有继承层次结构的基本对象。vtkObjectBase实现了数据对象引用计数(见“引用计数和垃圾回收”)。vtkObjectBase的子类可能会被其他对象共享,而无需重复内存。它还为对象定义了打印关于自身信息的API。

vtkObject是vtkObjectBase的子类。它提供了控制运行时调试的方法和实例变量,并维护内部对象修改时间。特别是,方法Modified()用于更新修改时间,方法GetMTime()用于检索它。vtkObject还为我们在上一章中看到的事件回调提供了一个框架(见第3章中的“事件和观察者”)。

        请注意,我们并不总是在对象图中包括vtkObject和vtkObjectBase,以节省空间。有关确定语句,请参考源代码。

示例

        我们将展示四个示例,演示可视化管道的一些特性。在这里使用的一些对象对您可能不太熟悉。在我们后面涵盖这些信息之前,请忽略缺少的细节。这里的目标是提供对软件架构及其使用的一些了解和熟悉感。

        简单的球体。第一个示例演示了一个简单的可视化管道。使用源对象(vtkSphereSource)创建了一个球体的多边形表示。球体通过一个过滤器(vtkElevationFilter)传递,该过滤器计算了球体上每个点相对于一个平面的高度。该平面垂直于z轴,并通过点(0,0,-1)。最后,数据通过查找表映射(vtkDataSetMapper),映射过程将高度值转换为颜色,并将球体几何图形接口化到渲染库中。将映射器分配给一个角色,然后显示该角色。可视化网络、部分代码和输出图像如图4-19所示。

        图4-19。一个简单的球体示例。参见ColoredSphere.cxx和ColoredSphere.py。 当我们渲染actor时,管道的执行是隐式发生的。每个actor都会要求其映射器更新自身。映射器反过来会要求其输入更新自身。这个过程会一直持续,直到遇到一个源对象。然后,如果源对象自上次渲染以来发生了修改,它就会执行。

        然后系统会遍历网络,并执行每个对象,如果它的输入或实例变量已过期。完成后,actor的映射器就是最新的,并且生成了一个图像。

        现在让我们通过跟踪方法调用来重新审视管道执行的同样过程。该过程始于actor从渲染器接收到一个Render()消息。actor然后向其映射器发送一个Render()消息。映射器通过向其输入发送一个Update()操作来开始网络执行。这会导致Update()方法的级联调用,因为每个过滤器依次要求其输入更新自身。如果管道中存在分支,则更新方法也会分支。最后,当遇到一个源对象时,级联终止。如果源对象已过期,它会发送一个RequestData()命令给自己。每个过滤器会根据需要向自己发送一个RequestData()以使自己更新到最新。最后,映射器将执行操作,将其输入转换为渲染基元。

        在可视化工具包中,Update()方法是公开的,而RequestData()方法是受保护的。因此,您可以通过调用Update()操作手动触发网络执行。当您想要根据上游执行的结果设置网络中的实例变量,但又不想整个网络更新时,这可能很有用。RequestData()方法是受保护的,因为它需要某种对象状态存在。Update()方法确保了这种状态的存在。

        最后要注意的一点。代码的缩进用来指示对象实例化和修改的位置。第一行(即New()运算符)是创建对象的地方。随后的缩进行表示正在对对象执行各种操作。我们鼓励您在自己的工作中使用类似的缩进方案。

        扭曲的球体。这个示例扩展了前一个示例的管道,并展示了类型检查对处理对象的连接性产生的影响。我们添加了一个变换过滤器(vtkTransformFilter)来非均匀地缩放球体在x-y-z方向上。

        变换滤波器仅对具有显式点坐标表示的对象操作(即 vtkPointSet 的子类)。然而,高程滤波器生成更一般形式的 vtkDataSet 作为输出。因此,我们无法将变换滤波器连接到高程滤波器。但是,我们可以将变换滤波器连接到球体源,然后将高程滤波器连接到变换滤波器。结果如图 4-20 所示。(注意:另一种方法是使用 vtkCastToConcrete 执行运行时转换。)

Listing (4.1) Warped Sphere.
vtkNew <vtkSphereSource > sphere;
sphere -> SetThetaResolution (12);
sphere -> SetPhiResolution (12);
vtkNew <vtkTransform > aTransform ;
aTransform ->Scale (1, 1.5, 2);
vtkNew < vtkTransformFilter >
transFilter ;
transFilter -> SetInputConnection (sphere -> GetOutputPort ());
transFilter -> SetTransform ( aTransform );
vtkNew < vtkElevationFilter > colorIt;
colorIt -> SetInputConnection (transFilter -> GetOutputPort ());
colorIt -> SetLowPoint (0, 0, -1);
colorIt -> SetHighPoint (0, 0, 1);
vtkNew <vtkLookupTable > lut;
lut -> SetHueRange (0.667 , 0.0);
lut -> SetSaturationRange (1, 1);
lut -> SetValueRange (1, 1);
vtkNew <vtkDataSetMapper > mapper;
mapper -> SetLookupTable (lut );
mapper -> SetInputConnection (colorIt -> GetOutputPort ());
vtkNew <vtkActor > actor;
actor -> SetMapper (mapper );

        图4-20。在前面示例的基础上添加了一个变换滤波器。请参阅TransformSphere.cxx和TransformSphere.py。

        C++编译器强制执行源、滤波器和映射器的正确连接。为了决定哪些对象是兼容的,我们检查SetInput()方法的类型规范。如果输入对象返回输出对象或该类型的子类,则这两个对象是兼容的,可以连接起来。

        生成定向标志。该示例演示了使用具有多个输入的对象的用法。vtkGlyph3D在每个输入点处放置3D图标或标志(即任何多边形几何体)。图标几何形状由实例变量Source指定,输入点来自实例变量Input。每个标志可以根据输入和实例变量以多种方式定向和缩放。在我们的示例中,我们将圆锥放置在点法线方向上(图4-21)。

Listing (4.2) Mace.
vtkNew <vtkSphereSource > sphere;
sphere -> SetThetaResolution (8);
sphere -> SetPhiResolution (8);
vtkNew <vtkPolyDataMapper > sphereMapper ;
sphereMapper -> SetInputConnection (sphere -> GetOutputPort ());
vtkNew <vtkActor > sphereActor ;
sphereActor -> SetMapper ( sphereMapper );
vtkNew <vtkConeSource > cone;
cone -> SetResolution (6);
vtkNew <vtkGlyph3D > glyph;
glyph -> SetInputConnection (sphere -> GetOutputPort ());
glyph -> SetSourceConnection (cone -> GetOutputPort ());
glyph -> SetVectorModeToUseNormal ();
glyph -> SetScaleModeToScaleByVector ();
glyph -> SetScaleFactor (0.25);
vtkNew <vtkPolyDataMapper > spikeMapper ;
spikeMapper -> SetInputConnection (glyph -> GetOutputPort ());
vtkNew <vtkActor > spikeActor ;
spikeActor -> SetMapper ( spikeMapper );

        图4-21. 多输入和输出的示例。请参阅Mace.cxx和Mace.py。 可视化网络在vtkGlyph3D处分支。如果任一分支被修改,则此滤波器将重新执行。网络更新必须在两个方向上分支,并且在vtkGlyph3D执行时,两个分支都必须是最新的。这些要求由Update()方法强制执行,并且对隐式执行方法没有问题。

        消失的球。在我们的最后一个示例中,我们构建了一个带有反馈循环的可视化网络,并展示了如何使用过程化编程来改变网络的拓扑结构。该网络由四个对象组成:vtkSphereSource用于创建初始多边形几何体,vtkShrinkFilter用于收缩多边形并在邻居之间创建间隙或空间,vtkElevationFilter用于根据高度对几何体进行着色超过x-y平面,以及vtkDataSetMapper用于通过查找表映射数据并与渲染库进行交互。网络拓扑结构、部分C++代码和输出如图4-22所示。

Listing (4.3) Warped Sphere.
vtkNew <vtkSphereSource > sphere;
sphere -> SetThetaResolution (12);
sphere -> SetPhiResolution (12);
vtkNew <vtkShrinkFilter > shrink;
shrink -> SetInputConnection (sphere -> GetOutputPort ());
shrink -> SetShrinkFactor (0.9);
vtkNew < vtkElevationFilter > colorIt;
colorIt -> SetInputConnection (shrink -> GetOutputPort ());
colorIt -> SetLowPoint (0, 0, -0.5);
colorIt -> SetHighPoint (0, 0, 0.5);
vtkNew < vtkDataSetMapper > mapper;
mapper -> SetInputConnection (colorIt -> GetOutputPort ());
vtkNew <vtkActor > actor;
actor -> SetMapper (mapper );
renWin ->Render (); // execute first time
// create loop
shrink -> SetInputConnection (colorIt -> GetOutputPort ());
renWin ->Render (); // begin looping

        图4-22。带有循环的网络(LoopShrk.cxx)。VTK 5.0不允许执行循环可视化网络;这在先前的VTK版本中是可能的。请参阅LoopShrink.cxx和LoopShrink.py。

        在vtkSphereSource生成初始几何体(响应渲染请求)后,vtkShrinkFilter的输入被更改为vtkElevationFilter的输出。由于存在反馈循环,vtkShrinkFilter将始终重新执行。因此,网络的行为是每次执行渲染时重新执行。由于收缩过滤器被重新应用于相同的数据,多边形会变得越来越小,最终消失。

4.10 章节总结

        可视化过程自然地使用功能模型和对象模型的组合进行建模。功能模型可以简化并用于描述可视化网络。对象模型指定了可视化网络的组件。可视化网络由过程对象和数据对象组成。数据对象表示信息;过程对象将数据从一种形式转换为另一种形式。有三种类型的过程对象:源对象没有输入,至少有一个输出;过滤器至少有一个输入和输出;终端,或映射器,终止可视化网络。可以隐式或显式地控制网络的执行。隐式控制意味着每个对象必须确保其输入是最新的,从而分发控制机制。显式控制意味着存在一个集中的执行者来协调每个对象的执行。有许多技术可用于编程可视化网络。直接的视觉编程在商业系统中最常见。在更高的级别,应用程序提供了定制但更严格的界面来可视化信息。在最低级别,子程序或对象库提供了最大的灵活性。可视化工具包包含了一个用C++实现的对象库,用于构建可视化网络。

4.11 参考文献说明

        学习可视化过程的实际方法是研究商业可用系统。这些系统可以分为直接的视觉编程环境或应用程序。常见的视觉编程系统包括AVS [AVS89],Iris Explorer [IrisExplorer],IBM Data Explorer [DataExplorer],aPE [aPE90]和Khoros [Rasure91]。应用程序系统通常提供的灵活性较少,但更适合于特定的问题域。PLOT3D [PLOT3D]是CFD可视化工具的早期示例。这已被FAST [FAST90]所取代。FieldView是另一个流行的CFD可视化器[FieldView91]。VISUAL3 [VISUAL3]是一个用于非结构化或结构化网格可视化的通用工具。PV-WAVE [Charal90]可以被认为是一个混合系统,因为它既有简单的视觉编程技术来接口数据文件,也比视觉编程环境具有更结构化的用户界面。Wavefront的DataVisualizer [DataVisualizer]是一个通用的可视化工具。它独特之处在于它是一个强大的渲染和动画软件包的一部分。用于可视化3D网格数据(如数值天气模型生成的数据)的一种良好系统是VIS5D。在VIS5D网站上了解更多信息。

尽管许多可视化系统声称是面向对象的,但这通常更多是表象而不是实现。关于可视化的面向对象设计问题的文献很少。VISAGE [VISAGE92]提出了一个与本章描述的类似的体系结构。Favre [Favre94]描述了一个更常规的面向对象方法。他的数据集类基于拓扑维度,并且数据和方法被合并到类中。

4.12 参考文献

[aPE90] D. S. Dyer。“用于可视化的数据流工具包”。IEEE计算机图形与应用。10(4):60-69,1990年7月。

[AVS89] C. Upson,T. Faulhaber Jr.,D. Kamins等。“应用可视化系统:用于科学可视化的计算环境”。IEEE计算机图形与应用。9(4):30-42,1989年7月。

[Bavoil2005] L. Bavoil,S.P. Callahan,P.J. Crossno,J. Freire,C.E. Scheidegger,C.T. Silva和H.T. Vo。“VisTrails:支持交互式多视图可视化”。在IEEE可视化2005年会议论文集中。IEEE计算机学会出版社,2005年。

[Berger84] M. Berger和J. Oliger。适应性网格细化用于双曲型偏微分方程。计算物理学杂志,53:484-512,1984年3月。

[Charal90] S. Charalamides。“新波技术图形是受欢迎的”。DEC USER,1990年8月。

[CruzNeira93] C. CruzNeira,D.J. Sandin和T. DeFanti。“基于投影的CAVE环绕屏幕虚拟现实的设计和实现”。在SIGGRAPH 93会议论文集中,第135-142页,1993年8月。

[DataExplorer] 数据探索器参考手册。IBM公司,纽约阿蒙克,1991年。

[DataVisualizer] 数据可视化器用户手册。Wavefront Technologies,加利福尼亚州圣巴巴拉,1990年。

[FAST90] G. V. Bancroft,F. J. Merritt,T. C. Plessell,P. G. Kelaita,R. K. McCabe和A.Globus。“FAST:用于可视化的多进程环境”。在可视化‘90年会议论文集中。第14-27页,IEEE计算机学会出版社,加利福尼亚州洛杉矶,1990年。

[Favre94] J. M. Favre和J. Hahn。“用于多变量数据对象可视化的面向对象设计”。在可视化‘94年会议论文集中。第319-325页,IEEE计算机学会出版社,加利福尼亚州洛杉矶,1994年。

[FieldView91] S. M. Legensky。“桌面工作站上的高级可视化”。在可视化‘91年会议论文集中。第372-378页,IEEE计算机学会出版社,加利福尼亚州洛杉矶,1991年。

[Haeberli88] P. E. Haeberli。“ConMan:交互式图形的可视化编程语言”。计算机图形学(SIGGRAPH ‘88)。22(4):103-11,1988年。

[Humphreys99] G. Humphreys和P. Hanrahan。“用于大型瓷砖显示器的分布式图形系统”。在IEEE可视化‘99会议论文集中,第215-224页,IEEE计算机学会出版社,1999年10月。

[IrisExplorer] Iris Explorer用户指南。硅图公司,加利福尼亚州山景城,1991年。

[King03] B. King和W. Schroeder。“复杂C++代码的自动封装”。C/C++用户杂志,2003年1月。

[Law99] C. Charles Law,K. M. Martin,W. J. Schroeder,J. E. Temkin。“用于大型结构化数据集的多线程流水线架构”。在可视化‘99年会议论文集中。IEEE计算机学会出版社,1999年。

[Levoy94] M. Levoy。“图像的电子表格”。在SIGGRAPH‘94会议论文集中。第139-146页,1994年。

[Martin2001] K.M. Martin,B. Geveci,J. Ahrens,C. Law。“使用并行数据流进行大规模数据可视化”。IEEE计算机图形与应用,21(4):34-41,2001年7月。

[PLOT3D] P. P. Walatka和P. G. Buning。PLOT3D用户手册。NASA流体动力学部,1988年。

[Rasure91] J. Rasure,D. Argiro,T. Sauer和C. Williams。“用于图像处理的可视化语言和软件开发环境”。国际图像系统和技术杂志。1991年。

[VISAGE92] W. J. Schroeder,W. E. Lorensen,G. D. Montanaro和C. R. Volpe。“VISAGE:面向对象的可视化系统”。在可视化‘92年会议论文集中。第219-226页,IEEE计算机学会出版社,加利福尼亚州洛杉矶,1992年。

最近更新

  1. TCP协议是安全的吗?

    2024-03-17 13:06:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-17 13:06:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-17 13:06:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-17 13:06:01       20 阅读

热门阅读

  1. 外观模式实战运用

    2024-03-17 13:06:01       19 阅读
  2. Android中的设计模式---单例模式

    2024-03-17 13:06:01       19 阅读
  3. 大型语言模型与Scikit-learn:Scikit-LLM全面指南

    2024-03-17 13:06:01       19 阅读
  4. Rust的所有权和生命周期机制的本质

    2024-03-17 13:06:01       22 阅读
  5. redis spring cache

    2024-03-17 13:06:01       17 阅读
  6. HTTP 状态码

    2024-03-17 13:06:01       19 阅读
  7. 设计模式详解(十二)——外观模式

    2024-03-17 13:06:01       18 阅读
  8. c++ 设计模式模版方法

    2024-03-17 13:06:01       19 阅读
  9. c++ 设计模式 策略模式

    2024-03-17 13:06:01       22 阅读
  10. 大数据平台测试-我是怎么面试高级测试的

    2024-03-17 13:06:01       22 阅读