vtk用户指南 第十三章 交互,小部件和选择类

        可视化系统最强大的功能不在于它处理数据或创建图像的能力,而在于它允许用户与场景交互的机制,以便将可视化引导到新的方向。在VTK中,这种交互以各种形式出现,从基本的鼠标和键盘交互,允许您旋转,翻译和缩放,到场景中的交互式小部件元素,可以操纵以控制可视化的各种参数,到用于识别数据部分的选择机制。本章将介绍交互的基础知识,并向您介绍可用于为应用程序开发自定义交互模型的工具。

13.1交互器

        一旦您可视化了数据,您通常希望与它进行交互。可视化工具包提供了几种方法来实现这一点。第一种方法是使用内置类vtkRenderWindowInteractor。第二种方法是通过指定事件绑定来创建您自己的交互器。不要忘记,如果您使用的是解释性语言,您可以在运行时键入命令。您可能还希望参阅第59页的“选择”,了解如何从屏幕中选择数据。(注意:开发人员也可以选择一个窗口系统。参见第421页的“与窗口系统集成”。)

vtkRenderWindowInteractor

        vtkRenderWindowInteractor为鼠标/按键/时间事件提供了独立于平台的交互机制。特定于平台的子类拦截来自窗口系统的消息,这些消息发生在呈现窗口内,并将它们转换为与平台无关的事件。特定的类可以观察这些用户事件的交互器并响应它们。其中一个类是vtkInteractorObserver。(请记住,多个渲染器可以绘制到一个渲染窗口中,并且渲染器绘制到渲染窗口中的viewport中。交互器在一个渲染窗口中支持多个渲染器)。我们之前已经看到了如何使用vtkRenderWindowInteractor,这里是一个重述。

vtkRenderWindowInteractor iren
iren SetRenderWindow renWin
iren AddObserver UserEvent {wm deiconify .vtkInteract}

        除了提供独立于平台的交互,vtkRenderWindowInteractor还提供帧率控制功能。该类维护两种请求帧率的概念:“DesiredUpdateRate”和“StillUpdateRate”。这样做的基本原理是,在交互过程中,人们愿意牺牲一些渲染质量来获得更好的交互性。因此,交互器(更确切地说是交互器样式,您将在下一节中看到)在交互期间将目标帧速率设置为DesiredUpdateRate。交互之后,目标帧率被设置回StillUpdateRate。通常,desireduupdaterate比StillUpdateRate大得多。如果场景中存在vtkLODActor(第55页的“level - of - detail Actors”),那么它将切换到足够低的细节级别以满足目标速率。体积映射器(参见第139页的“体积渲染”)可以投射更少的光线,或者跳过纹理平面以满足所需的帧速率。用户可以使用交互器上的SetDesiredUpdateRate()和SetStillUpdateRate()方法设置这些速率。

交互器样式

        每个人都有自己喜欢的与数据交互的方式。在VTK中有两种截然不同的方式来控制交互风格。第一种(也是推荐的方法)是使用vtkInteractorStyle的子类,可以是系统提供的,也可以是您自己编写的。第二种方法是添加观察者来观察vtkRenderWindowInteractor上的事件,并定义你自己的一组回调(或命令)来实现这种风格。(注意:3D小部件是另一种更复杂的与场景中的数据交互的方式。)

vtkInteractorStyle

        类vtkRenderWindowInteractor可以支持不同的交互样式。当你在交互器中输入“t”或“j”时(参见前一节),你正在轨迹球和操纵杆之间切换交互风格。它的工作方式是vtkRenderWindowInteractor将它接收到的特定于窗口系统的事件(例如,鼠标按钮按下,鼠标移动,键盘事件)转换为VTK事件,如MouseMoveEvent, StartEvent等。(参见第29页的“用户方法、观察者和命令”。)然后,不同的风格观察特定的事件,并执行适合事件的动作,通常是某种形式的相机操作。要设置样式,使用vtkRenderWindowInteractor的SetInteractorStyle()方法。例如:

vtkInteractorStyleFlight flightStyle
vtkRenderWindowInteractor iren
iren SetInteractorStyle flightStyle

该工具包提供了各种交互器样式。

•vtkInteractorStyleTrackballActor -允许用户以基于轨迹球的风格与场景中的角色相互独立地进行交互(旋转,平移等)。轨迹球风格是运动敏感的。鼠标移动的幅度与与特定鼠标绑定相关联的摄像机运动成正比。

•vtkInteractorStyleTrackballCamera -允许用户交互操作(旋转,平移等)摄像机,场景的视点基于轨迹球的风格。

•vtkInteractorStyleJoystickActor -允许用户与操纵杆风格的演员互动。操纵杆风格是位置敏感的;ie。鼠标相对于物体中心的位置,而不是鼠标运动的速度,决定了物体的运动速度。

•vtkInteractorStyleJoystickCamera -以操纵杆风格操纵相机。

•vtkInteractorStyleFlight -提供飞行运动例程。它适用于飞越交互(例如通过虚拟结肠镜检查中的结肠)或飞越(例如在地形或高度场上方)。

•vtkInteractorStyleImage -该风格是专门设计的工作与图像正在与vtkImageActor渲染。

•vtkInteractorStyleRubberbandZoom -这个交互器风格允许用户在渲染窗口中绘制一个矩形(橡皮筋),并将相机适当地缩放到选定的区域。

•vtkGeoInteractorStyle -为与地理视图(例如地球仪)的交互量身定制。它的交互功能包括轨道、缩放和倾斜。它还提供了一个用于更改视图参数的指南针小部件。

•vtkInteractorStyleTreeMapHover -与树状图一起工作(参见第163页的“信息可视化”)。

•vtkInteractorStyleAreaSelectHover -类似于vtkInteractorStyleTreeMapHover,除了它与一个区域布局(见“区域布局”在第175页)

•vtkInteractorStyleUnicam -单个鼠标按钮,上下文敏感的交互。

添加vtkRenderWindowInteractor观察者

        虽然在VTK中有各种各样的交互器样式,但您可能更喜欢创建自己的自定义样式来满足特定应用程序的需要。在c++中,自然的方法是创建vtkInteractorStyle的子类。(参见第255页的“vtkRenderWindowInteractor”。)然而,在解释性语言(如Tcl、Python或Java)中,这很难做到。对于解释型语言,最简单的方法是使用观察者来定义特定的交互绑定。(参见第29页的“用户方法、观察者和命令”。)这些绑定可以用VTK支持的任何语言进行管理,包括c++、Tcl、Python和Java。这样的一个例子可以在Tcl代码VTK/Examples/GUI/Tcl/ CustomInteraction中找到。它为一个简单的tcl应用程序定义绑定。这里有一段节选,让你了解发生了什么。

vtkRenderWindowInteractor iren
iren SetInteractorStyle ""
iren SetRenderWindow renWin
# Add the observers to watch for particular events
# These invoke Tcl procedures
set Rotating 0
set Panning 0
set Zooming 0
iren AddObserver LeftButtonPressEvent {global Rotating; set Rotating 1}
iren AddObserver LeftButtonReleaseEvent \
{global Rotating; set Rotating 0}
iren AddObserver MiddleButtonPressEvent {global Panning; set Panning 1}
iren AddObserver MiddleButtonReleaseEvent \
{global Panning; set Panning 0}
iren AddObserver RightButtonPressEvent {global Zooming; set Zooming 1}
iren AddObserver RightButtonReleaseEvent {global Zooming; set Zooming 0}
iren AddObserver MouseMoveEvent MouseMove
iren AddObserver KeyPressEvent Keypress
proc MouseMove {} {
...
 set xypos [iren GetEventPosition]
 set x [lindex $xypos 0]
 set y [lindex $xypos 1]
...
 }
proc Keypress {} {
set key [iren GetKeySym]
if { $key == "e" } {
 vtkCommand DeleteAllObjects
 exit
 }
...
}

        注意,这个例子中的关键步骤是通过调用SetInteractionStyle("")来禁用默认的交互样式。然后添加观察器来监视与适当Tcl过程绑定的特定事件。这个示例是一种从Tcl脚本添加绑定的简单方法。如果你想使用Tcl/Tk创建一个完整的GUI,那么使用vtkTkRenderWidget,并参考433页的“Tcl/Tk”了解更多细节。

13.2小部件

        交互器样式通常用于控制摄像机,并提供简单的按键和面向鼠标的交互技术。交互器样式在场景中没有表示;也就是说,它们不能被“看到”或与之交互,用户必须知道鼠标和键绑定是什么才能使用它们。然而,由于能够直接对场景中的对象进行操作,某些操作将大大简化。例如,如果可以交互式地定位线的端点,那么沿着一条线开始一个流线耙就很容易执行。

        VTK的3D小部件旨在提供此功能。像类vtkInteractorStyle, VTK的小部件是vtkInteractorObserver的子类。也就是说,它们监听由vtkRenderWindowInteractor调用的鼠标和键盘事件。然而,与vtkInteractorStyle不同的是,这些小部件在场景中有一些几何表示,用户通常与之交互。VTK提供了许多定制的小部件,以执行从测量和注释到分割,场景参数操作,探测等任务。

        自从它们进入VTK以来,小部件架构经历了重新设计。旧的小部件派生自vtk3DWidget。下面,我们将讨论新部件的体系结构。这些派生自vtkAbstractWidget,它派生自vtkInteractorObserver。这个类定义了小部件的行为(它的交互等)。小部件的几何形状(它在场景中的呈现方式)被封装在道具的形式中。这是一个派生自vtkWidgetRepresentation的类,它派生自vtkProp。这种行为(交互)与表示(几何)的解耦允许为同一个小部件创建多个表示。这允许用户用自己的表示覆盖现有的表示,而不必重新实现事件处理。它们在并行的分布式计算环境中非常有用,因为事件处理能力可能不存在。用于表示种子的vtkHandleWidget有四种几何表示,即:vtkPointHandleRepresentation2D, vtkPointHandleRepresentation3D, vtkSphereHandleRepresentation和vtkPolygonalHandleRepresentation。它们分别将手柄渲染为2D准星、3D准星、球体或用户提供的多边形形状。下面的代码片段位于Widgets/Testing/Cxx/TestHandleWidget中。CXX展示了如何创建小部件并将其绑定到它的表示。在这里,我们将创建一个可以在3D世界中移动的句柄小部件。手柄通过3D十字准星表示,这是由它的表示方式决定的。

// Create a render window interactor
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
 iren->SetRenderWindow(renderWindow);
// Create a 3D cross hair representation for a handle
double worldPos[3] = {-0.0417953, 0.202206, -0.0538641};
vtkPointHandleRepresentation3D *handleRep
= vtkPointHandleRepresentation3D::New();
handleRep->SetHandleSize(10);
handleRep->SetWorldPosition(worldPos);
// Create the handle widget.
vtkHandleWidget *handleWidget = vtkHandleWidget::New();
handleWidget->SetInteractor(iren);
handleWidget->SetRepresentation(handleRep);
handleWidget->EnabledOn();

        虽然每个小部件提供不同的功能和不同的API,但3D小部件的设置和使用方式是相似的。一般程序如下。

1. 实例化小部件

2。指定小部件将观察用户事件的呈现窗口交互器

3。根据需要使用命令/观察者机制创建回调(即命令)。请参阅第29页的“用户方法、观察者和命令”。小部件通常调用指示它们正在与之交互的通用事件,以及在交互期间特定于小部件的事件,如StartInteractionEvent、InteractionEvent和EndInteractionEvent。用户通常观察这些事件来更新数据、可视化参数或应用程序的用户界面。

4. 创建适当的表示并使用SetRepresentation将其提供给小部件,或者使用小部件提供的默认表示。

5. 最后,必须启用小部件,使其在场景中可见。默认情况下,按“i”键将启用小部件,它将出现在场景中。

        虽然SetEnabled切换小部件的可见性,但在某些情况下,可能有必要禁用小部件的交互,同时保持它在场景中可见。可以通过以下方式禁用新部件的事件处理:

widget->ProcessEventsOff();

这将导致小部件停止响应交互,而交互最终将由底层交互器样式处理。

可重构绑定

        由于个人偏好或使用不同的交互设备,用户可能还希望为小部件定制鼠标/键盘绑定。新架构的小部件允许您重新配置绑定。所有用户事件都与特定的小部件操作相关联。小部件使用一个称为“事件转换器”的中间类将用户事件转换为特定于小部件的事件。然后,将小部件事件映射到小部件上的方法调用。事件转换器可用于更改默认绑定,如下面的代码(摘自Widgets/Testing/Cxx/TestSliderWidget.cxx)所示

vtkWidgetEventTranslator *translator =
sliderWidget->GetEventTranslator();
 translator->SetTranslation(
vtkCommand::RightButtonPressEvent, vtkWidgetEvent::Select);
translator->SetTranslation(
vtkCommand::RightButtonReleaseEvent, vtkWidgetEvent::EndSelect);

因此,除了默认的左键外,用户还可以使用鼠标右键来操作滑块的凹槽。用户还可以使用RemoveTranslation方法删除现有的绑定。

translator->RemoveTranslation( vtkCommand::LeftButtonPressEvent );
translator->RemoveTranslation( vtkCommand::LeftButtonReleaseEvent );

与部件相关的翻译列表可以通过执行其Print语句获得:

translator->Print( std::cout );

光标管理和高亮显示

        大多数小部件还可以管理光标,当鼠标悬停在小部件的一部分上以指示操作时,可以适当地改变光标的形状。高亮显示是另一个常见的功能,例如,当鼠标悬停在/选择框小部件上时,它的手柄会改变颜色,以表明它可以被操纵。

小部件层次结构

        小部件还支持层次结构。一个小部件可以被另一个小部件“父化”,以便使用一个或多个现有小部件创建复合小部件。例如,一个vtkDistanceWidget内部包含两个vtkhandlewidget,作为它的子控件,表示端点。子进程侦听父进程的事件,而不是侦听呈现窗口交互器,从而允许父进程在必要时修改它们的行为。在VTK中,handle小部件被用作其他几个小部件的子部件,如角度、二维、框、平行六边形、线和种子小部件。

  • 定时器

        除了响应用户的事件外,VTK的小部件还可以响应其他事件,例如计时器事件。例如,vtkBalloonWidget用于弹出文本/图像注释,当鼠标悬停在一个演员为用户指定的时间。为此,小部件观察交互器的MouseMoveEvent和TimerEvent,以便当鼠标停留在actor上的时间超过用户指定的“TimerDuration”时,小部件可以采取操作。

        下面摘自Rendering/Testing/Cxx/TestInteractorTimers。CXX演示了如何请求和观察计时器的呈现窗口交互器。

// Observe the interactor for timers with a callback
iren->AddObserver(vtkCommand::TimerEvent, myCallback);
// Create a timer that repeats every 3 milliseconds
tid = iren->CreateRepeatingTimer(3);
// Create a timer that fires once after 1 second.
tid = iren->CreateOneShotTimer(10000);
  • 优先顺序

        多个类可以同时观察呈现窗口交互器以获取用户事件。这些包括vtkInteractorObserver的所有子类,比如交互器样式和场景中的一个或多个小部件。在场景中移动鼠标,而不是在任何特定的小部件上移动鼠标,将激活vtkInteractorStyle,但是在特定的小部件上移动鼠标只会激活该小部件——通常没有其他小部件或交互器样式会看到事件。(一个值得注意的例外是类vtkInteractorEventRecorder,它记录事件,然后传递它们。这个类还可以播放事件,因此对于记录会话非常有用。该类在VTK中用于对小部件进行回归测试)。这种情况可能导致事件竞争。用户事件的竞争是通过“优先级”来处理的。vtkInteractorObserver的所有子类都可以使用SetPriority方法分配优先级。具有较高优先级的对象有机会在具有较低优先级的对象之前处理事件。它们还可以选择中止给定事件的事件处理,从而有效地获取“焦点”。

        事实上,小部件在交互器样式之前处理事件处理的原因是它们比交互器样式具有更高的优先级。

存放点

        注意,交互发生在2D窗口中。3D小部件可能需要将2D坐标转换为3D世界中的坐标。例如,考虑使用vtkHandleWidget在呈现窗口上放置一个种子点。种子应该放置在3D场景的什么深度?VTK提供了一些标准的方法来定义这种映射和一个框架来创建自己的映射。这是通过一个名为vtkPointPlacer的类完成的。轮廓小部件和手柄小部件具有接受点放置器的表示,它们将从2D坐标转换为3D坐标的责任委托给点放置器。可以使用这些来指定节点可以移动到哪里的约束。例如,下面的摘录可以在Widgets/Testing/Cxx/TestSurfaceConstrainedHandleWidget中找到。CXX将种子的放置和相互作用限制在一个多边形表面上:

vtkHandleWidget *widget = vtkHandleWidget::New();
vtkPointHandleRepresentation3D *rep =
vtkPointHandleRepresentation3D::SafeDownCast(
widget->GetRepresentation());
// Restrict the placement of seeds to the polygonal surface defined by
// "polydata" and rendered as "actor"
vtkPolygonalSurfacePointPlacer * pointPlacer
= vtkPolygonalSurfacePointPlacer::New();
pointPlacer->AddProp(actor);
pointPlacer->GetPolys()->AddItem( polydata );
rep->SetPointPlacer(pointPlacer);

        类似地,可以使用类vtkImageActorPointPlacer来将轮廓小部件的控制点的位置限制为图像的一个切片,如下面的Widgets/Testing/摘录所示
Cxx / TestImageActorContourWidget.cxx。

vtkOrientedGlyphContourRepresentation *rep =
vtkOrientedGlyphContourRepresentation::New();
vtkImageActorPointPlacer * imageActorPointPlacer =
vtkImageActorPointPlacer::New();
imageActorPointPlacer->SetImageActor(ImageViewer->GetImageActor());
rep->SetPointPlacer(imageActorPointPlacer);

13.3小部件之旅

        以下是目前在VTK中找到的小部件列表,并简要介绍了它们的功能。请注意,这里提到的一些概念在本文中尚未涉及。请参考适当的交叉参考,以了解有关特定概念的更多信息。

测量小部件

        vtkDistanceWidget。vtkDistanceWidget用于测量2D中两点之间的距离,例如测量医学图像中肿瘤的直径。两个端点都可以单独放置,当他们被释放时,调用PlacePointEvent,这样您就可以执行自定义操作重新定位重点(对齐网格对齐到一个边缘,等等)小部件有两个不同的交互模式:第一个模式是使用当你最初定义小部件的测量(即,将两个点),然后操作模式是用于允许您调整两个点的位置。

        要使用这个小部件,请指定vtkDistanceWidget的实例和表示(vtkDistanceRepresentation的子类)。这个小部件是使用vtkHandleWidget的两个实例来实现的,它们用于定位线的端点。这两个句柄小部件的表示由vtkDistanceRepresentation提供。以下是VTK/Widgets/ Testing/Cxx/TestDistanceWidget.cxx中的vtkDistanceWidget的示例。

vtkPointHandleRepresentation2D *handle =
vtkPointHandleRepresentation2D::New();
vtkDistanceRepresentation2D *rep =
vtkDistanceRepresentation2D::New();
rep->SetHandleRepresentation(handle);
vtkDistanceWidget *widget = vtkDistanceWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);

        vtkAngleWidget。vtkAngleWidget用于测量两条光线之间的角度(由三个点定义)。三个点(两个端点和一个中心)可以在2D或3D中独立定位。与vtkDistanceWidget类似,当一个句柄位置发生改变时调用PlacePointEvent,以便您可以调整点的位置以捕捉到网格或执行其他专门的放置选项。同样类似于vtkDistanceWidget, vtkAngleWidget有两种操作模式。第一个是在定义角度小部件并初始放置三个点时生效。

        之后,小部件切换到操作交互模式,允许您调整定义角度的三个点的位置。要使用这个小部件,请指定vtkAngleWidget的实例和表示(vtkangleerepresentation的子类)。这个小部件是使用vtkHandleWidget的三个实例实现的,它们用于定位这三个点。这些句柄小部件的表示由vtkAngleRepresentation提供。下面是vtkAngleWidget的一个例子,摘自VTK/Widgets/Testing/Cxx/TestAngleWidget3D.cxx。

vtkPointHandleRepresentation3D *handle =
vtkPointHandleRepresentation3D::New();
vtkAngleRepresentation3D *rep = vtkAngleRepresentation3D::New();
rep->SetHandleRepresentation(handle);
vtkAngleWidget *widget = vtkAngleWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);

类似地,可以实例化表示vtkAngleRepresentation2D来测量2D中的角度

vtkPointHandleRepresentation2D *handle =
vtkPointHandleRepresentation2D::New();
vtkAngleRepresentation2D *rep = vtkAngleRepresentation2D::New();
rep->SetHandleRepresentation(handle);
widget->SetRepresentation(rep);

        vtkBiDimensionalWidget。vtkBiDimensionalWidget用于测量对象的二维长度。二维测量是由两条有限的、正交的线定义的,它们在两条线的有限范围内相交。这两条线的长度给出了二维度量。每行由位于每行末端的两个句柄小部件定义。

        两条线上的正交约束限制了四个端点的定位方式。可以任意放置前两点来定义第一行(类似于vtkDistanceWidget)。第三个点的位置受限于第一行的有限范围。当放置第三个点时,第四个点放置在第一条线的对面。一旦放置了第三个点,就定义了第二条线,因为第四个点同时被定义了,但第四个点可以沿着第二条线移动(即保持两条线的正交关系)。一旦定义,这四个点中的任何一个都可以沿着它们的约束线移动。此外,每条线都可以沿着另一条线平移(在正交方向上),并且整个二维小部件可以围绕其中心点旋转。最后,通过选择两个正交轴相交的点,整个小部件可以在任何方向上平移。

        放置任何点都会导致一个特殊的PlacePointEvent调用,以便可以执行特殊操作来重新定位该点。任何一点的移动、移动线条或旋转小部件都会导致调用InteractionEvents。注意,小部件有两个基本模式:定义模式(最初放置点时)和操作模式(放置点后)。线条平移和旋转只有在操纵模式下才有可能。

        要使用这个小部件,指定一个vtkBiDimensionalWidget的实例和一个表示(例如,vtkBiDimensionalRepresentation2D)。这个小部件是使用vtkHandleWidget的四个实例实现的,它们用于定位两条相交线的端点。这些句柄小部件的表示由vtkBiDimensionalRepresentation2D类提供。一个取自VTK/Widgets/TestBiDimensionalWidget的例子。CXX如下图:

vtkBiDimensionalRepresentation2D *rep =
vtkBiDimensionalRepresentation2D::New();
vtkBiDimensionalWidget *widget = vtkBiDimensionalWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);

用于探测或操作底层数据的小部件

        vtkHandleWidget。vtkHandleWidget提供了一个句柄,可以在2D或3D空间中进行交互式定位。它们也可用作基准。提供了几种几何表示,能够在2D和3D中创建各种形状。手柄可以用鼠标左键在2D/3D空间中转换。按住shift键拖动它会限制其沿其中一个坐标轴的平移;将轴确定为与鼠标运动向量最对齐的轴。可以使用鼠标右键调整句柄的大小。小部件在操作句柄期间调用InteractionEvent,在交互之后调用EndInteractionEvent,允许用户在必要时响应。        

        vtkhandlererepresentation是句柄的许多表示的抽象超类。vtkPointHandleRepresentation3D通过3D交叉毛表示手柄。vtkPointHandleRepresentation2D通过叠加平面上的2D交叉毛表示它。vtkSphereHandleRepresentation通过一个3D球体来表示它。vtkPolygonalHandleRepresentation3D允许用户插入vtkPolyData的实例,以便在用户定义的形状中呈现句柄。无数的表示允许人们以各种形状表示距离,角度和二维部件的端点。一个例子:

vtkHandleWidget *widget = vtkHandleWidget::New();
vtkPointHandleRepresentation3D *rep =
vtkPointHandleReprentation3D::New()
widget->SetRepresentation(rep);

对句柄放置和移动的约束可以通过vtkPointPlacer的子类选择性地放置。一个vtkPolygonalSurfacePointPlacer将把句柄限制在一个vtkPolyData的表面。

// Restrict the placement of seeds to the polygonal surface defined by
// “polydata” and rendered as “actor”
vtkPolygonalSurfacePointPlacer * pointPlacer =
vtkPolygonalSurfacePointPlacer::New();
pointPlacer->AddProp(actor);
pointPlacer->GetPolys()->AddItem( polydata );
rep->SetPointPlacer(pointPlacer);

类似地,可以使用vtkTerrainDataPointPlacer将句柄限制为一个高度字段(一个数字字段)
海拔地图)。

vtkTerrainDataPointPlacer * placer = vtkTerrainDataPointPlacer::New();
placer->SetHeightOffset( 5.0 );
// height over the terrain to constrain the points to
placer->AddProp( demActor ); // prop representing the DEM.
rep->SetPointPlacer( placer );

vtkImageActorPointPlacer将把句柄限制为一个图像,由vtkImageActor的实例表示。此外,还可以在此放置边界,以通过SetBounds进一步限制图像actor内的点。

vtkImageActorPointPlacer *placer = vtkImageActorPointPlacer::New();
placer->SetImageActor( imageActor );

        vtkLineWidget2。类vtkLineWidget2允许在3D空间中定义和操作有限直线。可以在它的端点(由vtkHandleWidget的实例表示)上挑选这条线,以定向和拉伸这条线。它也可以沿着线的任何地方挑选,以便在场景中翻译。与vtkHandleWidget非常相似,可以通过按住shift键拖动将端点或中心的移动限制到其中一个轴上。可以使用鼠标右键缩放线的中心。通过将鼠标“向上”移动到渲染窗口,线条将变得更大;通过向下移动渲染窗口,线条变得更小。line小部件的常见用途是探测(第100页的“探测”)和绘制数据(第66页的“X-Y图”)或生成流线(第95页的“流线”)或流表面(第97页的“流表面”)。vtkLineRepresentation为线小部件提供了几何图形。还可以启用行长度的注释。小部件在行操作期间调用InteractionEvent,在交互之后调用EndInteractionEvent,允许用户在必要时响应。这是Widgets/Testing/Cxx/TestLineWidget2.cxx的摘录。

vtkLineRepresentation *rep = vtkLineRepresentation::New();
p[0] = 0.0; p[1] = -1.0; p[2] = 0.0;
rep->SetPoint1WorldPosition(p);
p[0] = 0.0; p[1] = 1.0; p[2] = 0.0;
rep->SetPoint2WorldPosition(p);
rep->PlaceWidget(pl3d->GetOutput()->GetBounds());
rep->GetPolyData(seeds); // used to seed a streamline later
rep->DistanceAnnotationVisibilityOn();
vtkLineWidget2 *lineWidget = vtkLineWidget2::New();
lineWidget->SetInteractor(iren);
lineWidget->SetRepresentation(rep);
lineWidget->AddObserver(vtkCommand::InteractionEvent,myCallback);

        vtkPlaneWidget。此小部件可用于确定有限平面的方向和位置。平面分辨率是可变的。该小部件产生一个隐式函数,可以通过GetPlane方法查询,并产生一个多边形输出,可以通过GetPolyData方法查询。平面小部件可用于探测和播种流线。平面有四个手柄(在它的角顶点上),一个法向量,以及平面本身。通过抓住四个手柄中的一个(使用鼠标左键),可以调整平面的大小。通过抓取平面本身,整个平面可以任意平移。按住Control键同时抓住平面将使平面绕法线旋转。如果你选择正常的vecvtkLineWidget2 ,平面可以任意旋转。使用鼠标中键选择小部件的任何部分,可以沿其法线平移平面。

        (使用鼠标中键选中后,在法线方向移动鼠标,将平面平移到法线方向;在与法线相反的方向上移动,使平面在与法线相反的方向上移动。缩放(关于平面的中心)是通过使用鼠标右键实现的,向上拖动渲染窗口使平面变大;“down”是让它变小。小部件的公共API还允许用户更改平面和句柄的属性。还可以将平面法线约束到一个坐标轴上,如下面的代码片段所示。小部件在操作期间调用InteractionEvent,在交互之后调用EndInteractionEvent。以下摘自Widgets/Testing/Cxx/TestPlaneWidget。CXX演示了这个小部件的用法。

vtkPlaneWidget *planeWidget = vtkPlaneWidget::New();
planeWidget->SetInteractor(iren);
planeWidget->SetInput(pl3d->GetOutput());
planeWidget->NormalToXAxisOn();
planeWidget->SetResolution(20);
planeWidget->SetRepresentationToOutline();
planeWidget->PlaceWidget();
planeWidget->AddObserver(vtkCommand::InteractionEvent,myCallback);

        vtkImplicitPlaneWidget2。此小部件可用于定位无界平面的方向。可以从这个小部件查询隐式函数和多边形输出。这个小部件由四个部分组成:1)一个包含在边界框中的平面,3)一个平面法线,它植根于平面上的一个点。可以使用鼠标右键缩放小部件。可以选择并拖动法线来确定平面的方向。法线的根也可以被翻译来改变法线的原点。可以使用鼠标中键翻译整个小部件。多边形输出是通过使用边界框剪切平面来创建的。小部件通常用于“切割”和“裁剪”。人们可以改变平面上的各种属性。SetTubing可以用来显示平面的管状轮廓。这段摘自Widgets/Testing/Cxx/ TestImplicitPlaneWidget2。cxx演示了vtkImplicitPlaneWidget2的使用以及vtkImplicitPlaneRepresentation的实例

vtkImplicitPlaneRepresentation *rep =
vtkImplicitPlaneRepresentation::New();
rep->SetPlaceFactor(1.25);
rep->PlaceWidget(glyph->GetOutput()->GetBounds());
vtkImplicitPlaneWidget2 *planeWidget = vtkImplicitPlaneWidget2::New();
planeWidget->SetInteractor(iren);
planeWidget->SetRepresentation(rep);
planeWidget->AddObserver(vtkCommand::InteractionEvent,myCallback);

        vtkBoxWidget2。这个小部件定位和定位一个边界框。小部件生成隐式函数和转换矩阵。该小部件与vtkBoxRepresentation的实例一起使用。这个图案代表了一个有七个把手的盒子:六个面各一个,再加上一个中心把手。六面体的内角为90度(面是正交的)。7个手柄中的每一个都可以被鼠标点击和操纵。显示边界框轮廓,可以选择其“面”进行对象缩放。在交互过程中,相应的脸或手柄变得高亮,提供增强的视觉提示。可以使用PlaceWidget()方法来初始定位小部件。通过抓住六个面柄(使用鼠标左键),可以移动面。通过抓住中心手柄(用鼠标左键),可以翻译整个六面体。(也可以通过在小部件内部使用“shift-鼠标左键”组合来进行翻译。)缩放是通过使用鼠标右键实现的;“向上”表示渲染窗口(使小部件变大),“向下”表示渲染窗口(使小部件变小)。

        vtkBoxWidget2可用于选择、剪切、剪辑或执行依赖于隐式函数的任何其他操作(在表示上使用GetPlanes()方法);也可以使用线性转换来转换对象(在表示上使用GetTransform()方法)。小部件通常还用于定义感兴趣的区域,该区域可用于注释或裁剪数据集。小部件在交互之前、期间和之后调用StartInteractionEvent、InteractionEvent和EndInteractionEvent事件。可以使用vtkBoxRepresentation中的SetOutlineCursorWires打开/关闭手柄之间的轮廓显示。盒子小部件用于转换vtkProp3D和子类(“转换数据”在第70页)或剪切(“切割”在第98页)或剪辑数据(“剪辑数据”在第110页)。这个节选自VTK/Widgets/Testing/Cxx/BoxWidget2。CXX展示了如何使用这个小部件来转换场景中的其他道具

// Callback for the interaction
class vtkBWCallback2 : public vtkCommand
{
virtual void Execute(vtkObject *caller, unsigned long, void*)
{
vtkBoxWidget2 *boxWidget = reinterpret_cast<vtkBoxWidget2*>(caller);
vtkBoxRepresentation *boxRep =
reinterpret_cast<vtkBoxRepresentation*>(boxWidget->
GetRepresentation());
boxRep->GetTransform(this->Transform);
this->Actor->SetUserTransform(this->Transform);
}
vtkTransform *Transform;
vtkActor *Actor;
};
...
vtkBoxRepresentation *boxRep = vtkBoxRepresentation::New();
boxRep->SetPlaceFactor( 1.25 );
boxRep->PlaceWidget(glyph->GetOutput()->GetBounds());
vtkBoxWidget2 *boxWidget = vtkBoxWidget2::New();
boxWidget->SetRepresentation( boxRep );
boxWidget->AddObserver(vtkCommand::InteractionEvent,myCallback);
vtkTransform *t = vtkTransform::New();
vtkBWCallback2 *myCallback = vtkBWCallback2::New();
myCallback->Transform = t;
myCallback->Actor = maceActor;

        vtkAffineWidget。这个小部件支持交互式地定义仿射转换(剪切/旋转/缩放/平移)。与vtkAffineRepresentation实例一起使用的小部件。vtkAffineRepresentation2D是vtkAffineRepresentation的一个具体子类,用于表示2D中的仿射变换。这种表示的几何结构由三个部分组成:一个盒子、一个圆圈和一个十字架。该箱体用于结垢和剪切。可以使用鼠标左键通过单击边缘来沿着其中一个轴拉伸框,或者通过选择角来沿着两个轴拉伸框。这个圆是用来旋转的。可以选择中间的十字来实现翻译。在分别对框、圆、叉进行操作时,仿射变换的尺度、角度或平移分量可选择作为随附注释显示。所有的几何图形都是由vtkAffineRepresentation在覆盖平面上绘制的,保持一个恒定的大小(宽度和高度),根据标准化的视口坐标指定。

        该表示维护一个转换矩阵,用户可以使用GetTransform()方法查询该矩阵,以便对底层道具或数据集应用转换。这个小部件生成的转换假设表示位于x-y平面。如果不是这种情况,则用户负责将该表示的矩阵转换为正确的坐标空间(通过明智的矩阵乘法)。注意,GetTransform()返回的转换矩阵是相对于最后一次PlaceWidget()调用的。(PlaceWidget()方法设置发生旋转和缩放的原点,原点是所提供的边界框的中心点。)VTK / widget /测试/ Cxx / TestAffineWidget。CXX展示了如何使用仿射小部件对底层图像应用转换。小部件在交互期间调用InteractionEvent,在交互之后调用EndInteractionEvent。

class vtkAffineCallback : public vtkCommand
{
virtual void Execute(vtkObject *caller, unsigned long, void*)
{
this->AffineRep->GetTransform(this->Transform);
this->ImageActor->SetUserTransform(this->Transform);
}
vtkImageActor *ImageActor;
vtkAffineRepresentation2D *AffineRep;
vtkTransform *Transform;
};
vtkAffineRepresentation2D *rep = vtkAffineRepresentation2D::New();
rep->SetBoxWidth(100);
rep->SetCircleWidth(75);
rep->SetAxesWidth(60);
rep->DisplayTextOn();
rep->PlaceWidget(bounds);
vtkAffineWidget *widget = vtkAffineWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);
vtkAffineCallback *acbk = vtkAffineCallback::New();
acbk->AffineRep = rep;
acbk->ImageActor = imageActor;
widget->AddObserver(vtkCommand::InteractionEvent,acbk);
widget->AddObserver(vtkCommand::EndInteractionEvent,acbk);

        vtkParallelopipedWidget。vtkParallelopipedWidget可以在3D中交互式地操纵平行六边形。它意味着与vtkParallelopipedRepresentation的实例一起使用。平行六面体由8个手柄和6个面表示。手柄可以拾取和拖动,以操纵平行六面体。句柄是vtkHandleWidget的实例,表示为球体(vtkSphereHandleRepresentation)。左键单击一个手柄并拖动它在空间中移动手柄,沿着该手柄共享的面的手柄也可以移动,以保持拓扑结构为平行六边形。拖动手柄并按下shift按钮,可沿轴线调整平行六边形的大小。parallelopiped小部件还有一个特殊的模式,用于探测底层数据并显示其中的切口。通过ctrl-左键点击手柄,它会向内弯曲,从平行六边形中雕刻出一把“椅子”。在此模式下,平行六面体有14个手柄和9个面。这些手柄可以再次被挑选来操纵平行六面体或椅子的凹陷。以下摘自VTK/Widgets/Testing/Cxx/TestParallelopipedWidget。cxx演示了vtkParallelopipedWidget的使用。

vtkParallelopipedWidget *widget = vtkParallelopipedWidget::New();
vtkParallelopipedRepresentation *rep =
vtkParallelopipedRepresentation::New();
widget->SetRepresentation(rep);
widget->SetInteractor( iren );
rep->SetPlaceFactor( 0.5 );
rep->PlaceWidget(parallelopipedPts);

        vtkImagePlaneWidget。这个小部件在3D场景中定义一个平面,以交互方式重新切片图像体积。平面方向可以交互式地定义。附加功能包括窗口级重切片数据的能力和定义插值的程度,而重切片。在内部,小部件包含vtkImageReslice的实例。这将基于定义的平面对底层体积图像数据进行切片。这个类的输出是纹理映射到平面上,创建一个“图像平面小部件”。使用鼠标中键选择小部件(无论是否按住shift或control键)都可以启用复杂的剪切功能。一组“边距”(左、右、上、下)显示为一组平面轴对齐的线。在没有键盘修饰符的情况下:选择平面边缘的中间位置可以使平面沿着法线平移。选择边界内的一个角,就可以绕平面中心的法线旋转。在边界内选择允许围绕平面的中心围绕与边界对齐的轴旋转(即,选择左边界允许围绕平面的局部y '轴旋转)。使用control键修饰符:margin选择启用边缘平移(即缩放的约束形式)。在页边距内选择可以平移整个平面。使用shift键修饰符:启用均匀平面缩放。向上移动鼠标使平面放大,向下移动鼠标使平面缩小。选中后,平面轮廓将突出显示以提供视觉提示。

        使用鼠标右键可以实现窗口级。窗口级别的值可以通过shift + 'r'或control + 'r'来重置。按“r”或“r”键可以重置相机。鼠标左键可用于使用快照-交叉毛线游标查询底层图像数据。输入图像数据中离鼠标光标最近的点生成十字线。对于斜切,这种行为可能看起来不令人满意。文本注释显示窗口级和图像坐标/数据值。文本注释可以通过SetDisplayText来打开或关闭。小部件在交互的开始、过程和结束时调用StartInteractionEvent、InteractionEvent和EndInteractionEvent。事件StartWindowLevelEvent, WindowLevelEvent, EndWindowLevelEvent和ResetWindowLevelEvent在它们相应的动作中被调用。

        vtkImagePlaneWidget有额外的公共API,允许它被使用,有几个方法可以与其他VTK对象一起使用。GetPolyData()方法可用于获得平面的多边形表示,并可用作其他VTK对象的输入。该类的一些附加特性包括控制小部件属性的能力。您可以设置以下属性:选定和未选中的平面轮廓表示;文本actor通过它的vtkTextProperty;十字毛线游标。此外,还有一些方法可以约束平面,使其沿x-y-z轴对齐。最后,可以指定用于重切片数据的插值程度:最近邻、线性和三次。您还可以选择以体素为中心或连续光标探测。使用以体素为中心的探测,光标会锁定最近的体素,并且报告的光标坐标是基于范围的。通过连续探测,体素数据使用vtkDataSetAttributes的InterpolatePoint方法进行插值,报告的坐标是三维空间连续的。VTK / widget /测试/ Cxx / ImagePlaneWidget。cxx使用vtkImagePlaneWidget交互显示轴,冠状和矢状切片在三维体积。下面的摘录说明了这个小部件的用法。

vtkImagePlaneWidget* planeWidgetX = vtkImagePlaneWidget::New();
planeWidgetX->SetInteractor( iren);
planeWidgetX->SetKeyPressActivationValue('x');
planeWidgetX->SetPicker(picker);
planeWidgetX->RestrictPlaneToVolumeOn();
planeWidgetX->GetPlaneProperty()->SetColor(1,0,0);
planeWidgetX->SetTexturePlaneProperty(ipwProp);
planeWidgetX->TextureInterpolateOff();
planeWidgetX->SetResliceInterpolateToNearestNeighbour();
planeWidgetX->SetInput(v16->GetOutput());
planeWidgetX->SetPlaneOrientationToXAxes();
planeWidgetX->SetSliceIndex(32);
planeWidgetX->DisplayTextOn();
planeWidgetX->On();

        vtkTensorProbeWidget。这个小部件可以用来沿着轨迹探测张量。轨迹通过折线(vtkPolyLine)表示。该类旨在与vtkTensorProbeRepresentation的实例一起使用。表示类还负责呈现张量。vtkEllipsoidTensorProbeRepresentation将张量呈现为椭球体。椭球的方向和半径说明了张量的主要、中等和次要特征值/特征向量。小部件的交互由鼠标左键控制。在张量上左键点击选择它。它可以绕着轨迹移动来探测它上面的张量。下面的例子取自Widgets/Testing/ Cxx/TestTensorProbeWidget.cxx。

vtkTensorProbeWidget *w = vtkTensorProbeWidget::New();
w->SetInteractor(iren);
vtkTensorProbeRepresentation * rep =
vtkTensorProbeRepresentation::SafeDownCast(w->GetRepresentation());
rep->SetTrajectory(pd);

注释的小部件

        vtkScalarBarWidget。该类提供了对标量条的位置、大小和方向进行交互式操作的支持。这个小部件通常用于在场景中显示颜色图例。图例显示在叠加平面。vtkScalarBarWidget意味着与vtkScalarBarRepresentation的实例一起使用。该小部件允许调整标量条的大小、重新定位或重新定向。如果光标位于标量条的边或角上,则光标形状将更改为可调整边/角大小的形状。然后,用左键拖动可调整标量条的大小。类似地,如果光标在标量条内,它会改变形状以表明它可以被翻译。也可以通过按鼠标中键来重新定位标量条。如果一个标量条的位置被移动到接近vtkTensorProbeWidget vtkScalarBarWidget 的一个窗口的四个边缘的中心,那么标量条将改变其方向,以对齐该边缘。这个方向是粘性的,因为它将保持这个方向,直到位置移动到另一个边缘附近。方向也可以通过编程方式指定。可以通过从小部件或表示中检索或设置标量条来查询或指定标量条本身的文本注释。然后可以设置查找表或文本注释等属性。还可以通过在小部件中设置SetResizable()方法来禁用调整大小。类似地,可以使用小部件中的SetSelectable()标志禁用重新定位。这个节选自VTK/Widgets/Testing/ Cxx/TestScalarBarWidget。CXX说明了它的用法。

vtkScalarBarWidget *scalarWidget = vtkScalarBarWidget::New();
scalarWidget->SetInteractor(iren);
scalarWidget->GetScalarBarActor()->SetTitle("Temperature");
scalarWidget->GetScalarBarActor()->
SetLookupTable(outlineMapper->GetLookupTable());

        vtkCaptionWidget。这个小部件支持在2D覆盖平面上交互式地放置文本标题,以及从文本指向场景中要注释的点的引线(例如,箭头)。标题由vtkCaptionRepresentation表示。一个人可以互动地锚定领导者的位置。小部件表示内部包含一个vtkCaptionActor2D的实例来显示标题。可以直接在小部件上设置标题actor。标题框根据其字体大小、对齐和其他文本属性自动调整自身以适合文本。小部件在交互的开始、过程和结束时调用StartInteractionEvent、InteractionEvent和EndInteractionEvent。当选择标题文本时,小部件发出一个观察者可以监视的ActivateEvent。这对于打开GUI对话框以调整字体特征等非常有用。以下摘自VTK/Widgets/ Testing/Cxx/TestCaptionWidget。CXX展示了如何使用这个小部件对场景进行注释。

// Create the widget
vtkCaptionActor2D *rep = vtkCaptionActor2D::New();
rep->SetCaption("This is a test\nAnd it has two lines");
rep->GetTextActor()->GetTextProperty()->
SetJustificationToCentered();
rep->GetTextActor()->GetTextProperty()->
SetVerticalJustificationToCentered();
vtkCaptionWidget *widget = vtkCaptionWidget::New();
widget->SetInteractor(iren);
widget->SetCaptionActor2D(rep);

        vtkOrientationMarkerWidget。vtkOrientationMarkerWidget提供了对表示方向标记的道具的位置、大小和方向进行交互式操作的支持。输入方向标记被渲染为父渲染器上的叠加,因此它看起来叠加在父场景中提供的所有道具上。方向标记的相机视图与父视图匹配,因此它与场景的方向匹配。这个类维护自己的renvtkCaptionWidget ,它被添加到不同层的父渲染窗口中。通过命令观察者机制,使方向标记的相机视图与父视图相匹配。这给人一种错觉,即标记的方向反映了父场景中道具的方向。

        这个小部件监听鼠标左键和鼠标移动事件。它将根据光标的位置改变光标的形状。如果光标在覆盖渲染器上,它会将光标形状更改为SIZEALL形状。通过点击和拖动,方向标记可以被转换(以及覆盖视窗)。如果鼠标光标靠近某个角,则光标将变为调整角大小的形状(例如,SIZENW)。通过单击和拖动,视口及其包含的方向标记将被调整大小。宽高比在释放鼠标左键后保持,通过使两边等于最小边缘大小来强制叠加渲染器为正方形。当鼠标光标在小部件上时,该小部件还通过显示方向标记的轮廓来高亮显示自身。这个小部件需要设置一个方向标记道具的实例。标记道具本身可以是vtkProp的任何子类。具体来说,vtkAxesActor和vtkAnnoatedCubeActor是两个被设计为方向道具的类。前者以带注释的XYZ轴的形式提供注释。后者显示为一个立方体,6个面用用户指定文本创建的纹理注释。复合方向标记也可以通过将vtkAxesActor和vtkAnnoatedCubeActor的实例添加到vtkpropassemassembly中来生成,然后将其设置为输入方向标记。小部件也可以通过编程方式设置,通过将Interactive设置为Off,并通过调用小部件的SetViewport方法将覆盖渲染器大小调整/放置在其父视图中,以非交互式方式设置。下面举例说明一个典型的用法;对于更复杂的用例,请参阅VTK/Widgets/Testing/Cxx/TestOrientationMarkerWidget.cxx。

vtkAnnotatedCubeActor* cube = vtkAnnotatedCubeActor::New();
cube->SetXPlusFaceText ( "A" );
cube->SetXMinusFaceText( "P" );
cube->SetYPlusFaceText ( "L" );
cube->SetYMinusFaceText( "R" );
cube->SetZPlusFaceText ( "S" );
cube->SetZMinusFaceText( "I" );
cube->SetFaceTextScale( 0.666667 );
cube->SetFaceTextScale( 0.65 );
property = cube->GetCubeProperty();
property->SetColor( 0.5, 1, 1 );
property = cube->GetTextEdgesProperty();
property->SetLineWidth( 1 );
property->SetDiffuse( 0 );
property->SetAmbient( 1 );
property->SetColor( 0.1800, 0.2800, 0.2300 );
// this static function improves the appearance of the text edges
// since they are overlaid on a surface rendering of the cube's faces
vtkMapper::SetResolveCoincidentTopologyToPolygonOffset();
vtkOrientationMarkerWidget* widget = vtkOrientationMarkerWidget::New();
widget->SetOutlineColor( 0.9300, 0.5700, 0.1300 );
widget->SetOrientationMarker( cube );
widget->SetInteractor( iren );
widget->SetViewport( 0.0, 0.0, 0.4, 0.4 );
widget->SetEnabled( 1 );

        vtkBalloonWidget。这个小部件用于在鼠标悬停在参与者上一段指定时间时弹出注释。当鼠标在角色上悬停指定时间时,注释可以是文本和/或图像注释。这个小部件通过将一个vtkProp实例与一个“气球”实例相关联来跟踪用户选择的道具。气球封装注释(文本和/或图像)。当鼠标光标在vtkProp上悬停指定的延迟时,气球将带用户指定的属性出现在vtkProp附近。使用vtkBalloonRepresentation的实例来绘制气球。要使用这个小部件,首先指定vtkBalloonWidget的实例和表示形式。然后列出vtkProp的所有实例,一个文本字符串,和/或vtkImageData的实例与每个vtkProp相关联。(注意,您可以同时指定文本和图像,也可以只指定其中一个。)您可能还希望指定悬停延迟。小部件在弹出气球之前调用WidgetActivateEvent,观察者可以监视气球。VTK / widget /测试/ Cxx / TestBalloonWidget。CXX说明了一个典型的用法。

class vtkBalloonCallback : public vtkCommand
{
virtual void Execute(vtkObject *caller, unsigned long, void*)
{
vtkBalloonWidget *balloonWidget =
reinterpret_cast<vtkBalloonWidget*>(caller);
if ( balloonWidget->GetCurrentProp() != NULL )
{
cout << "Prop selected\n";
}
}
};
...
vtkBalloonRepresentation *rep = vtkBalloonRepresentation::New();
rep->SetBalloonLayoutToImageRight();
vtkBalloonWidget *widget = vtkBalloonWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);
widget->SetTimerDuration( 3000 ); // hover delay in ms.
widget->AddBalloon(sph,"This is a sphere",NULL);
widget->AddBalloon(cyl,"This is a\ncylinder",image1->GetOutput());
widget->AddBalloon(cone,"This is a\ncone,\na really big cone,\nyou
wouldn't believe how big",image1->GetOutput());
vtkBalloonCallback *cbk = vtkBalloonCallback::New();
widget->AddObserver(vtkCommand::WidgetActivateEvent,cbk);

        vtkTextWidget。这个类提供了在2D覆盖平面上交互式放置文本的支持。文本由vtkTextActor的实例定义。它派生自vtkBorderWidget,并继承了它的边框选择和大小调整功能。可以用鼠标左键选择文本边框。单击并拖动可沿特定方向调整边界大小,该方向由选定文本边界的角或面决定。文本及其边界也可以通过选择靠近中心的文本框进行翻译。可以通过转动小部件上的Selectable标志来禁用调整大小和移动。此外,当文本被选中时,小部件会发出一个WidgetActivateEvent,观察者可以监视它。这对于打开GUI对话框以调整字体特征等非常有用。小部件还在用户与小部件交互之前、期间和之后调用StartInteractionEvent、InteractionEvent和EndInteractionEvent。

        可以从小部件管理的文本actor中检索文本属性(vtkTextProperty),以更改文本的属性(字体、字体大小、对齐等)。以下摘自VTK/Widgets/Testing/Cxx/TestTextWidget。CXX说明了这个小部件的用法。

vtkTextActor *ta = vtkTextActor::New();
ta->SetInput("This is a test");
vtkTextWidget *widget = vtkTextWidget::New();
widget->SetInteractor(iren);
widget->SetTextActor(ta);
widget->SelectableOff();

分割/注册小部件

        vtkContourWidget。轮廓小部件是一个非常灵活的类,可以通过交互式地定义一组控制点来绘制闭合或打开的轮廓。这个小部件有两种模式。启用后,将进入“定义”模式,用户可以通过单击鼠标左键连续放置控制点。通过节点绘制轮廓线,并根据插值核在节点之间进行插值。用户放置好点后,按鼠标右键。这将使小部件进入“操纵”模式。如果用户在第一个控制点附近单击关闭轮廓,则小部件也可以进入“操纵”模式。在这种模式下,用户可以交互式地操作轮廓。将鼠标悬停在一个控制点上将突出显示该控制点;用户可以点击控制点并移动它。这将移动节点及其相关的线,从而满足插值器施加的约束。单击轮廓线(而不是节点),将在该点添加一个节点。该节点可能被进一步操纵。将鼠标悬停在一个节点上并按“删除”或“退格”键将删除该节点,并使用剩余节点重新插入线条。

        轮廓小部件被设计为与vtkContourRepresentation的子类一起工作。提供了几种表述。轮廓小部件使用的两个重要辅助类是“vtkContourLineInterpolator”和“vtkPointPlacer”。类vtkContourLineInterpolator是一个抽象类,允许用户指定用于定义节点之间曲线的插值。类vtkPointPlacer允许用户对控制点的位置施加约束。提供了几个点放置器和插值器。例如,类vtkBezierContourLineInterpolator将节点之间的插值约束为一条bezier曲线。

vtkOrientedGlyphContourRepresentation *contourRep =
vtkOrientedGlyphContourRepresentation::New();
vtkContourWidget *contourWidget = vtkContourWidget::New();
contourWidget->SetInteractor(iren);
contourWidget->SetRepresentation(contourRep);
vtkBezierContourLineInterpolator * interpolator =
vtkBezierContourLineInterpolator::New();
contourRep->SetLineInterpolator(interpolator);
contourWidget->SetEnabled(1);

        用户可以使用vtkPolygonalSurfaceContourLineInterpolator在多边形表面上绘制轮廓。这个插值器将其线条放置在指定的vtkPolyData的表面上。它意味着与vtkPolygonalSurfacePointPlacer一起使用。这个砂纸约束了控制点节点在polydata表面上的放置。插值器内部使用Dijkstra单源最短路径算法来计算从一个控制点到下一个控制点的最短路径。路径的代价由网格中的边长度决定。生成的路径沿着网格的边缘从一个节点遍历到下一个节点。这个例子来自VTK/Widgets/Testing/Cxx/TestDijkstraGraphGeodesicPath。CXX说明了它的用法。

vtkContourWidget *contourWidget = vtkContourWidget::New();
contourWidget->SetInteractor(iren);
vtkOrientedGlyphContourRepresentation *rep =
vtkOrientedGlyphContourRepresentation::SafeDownCast(
contourWidget->GetRepresentation());
vtkPolygonalSurfacePointPlacer * pointPlacer
= vtkPolygonalSurfacePointPlacer::New();
pointPlacer->AddProp(demActor);
pointPlacer->GetPolys()->AddItem( pd );
rep->SetPointPlacer(pointPlacer);
vtkPolygonalSurfaceContourLineInterpolator * interpolator =
vtkPolygonalSurfaceContourLineInterpolator::New();
interpolator->GetPolys()->AddItem( pd );
rep->SetLineInterpolator(interpolator);

        使用vtkTerranContourLineInterpolator,可以在高度域上绘制轮廓,例如数字高程地图vtkTerrainContourLineInterpolator。这个插值器约束控制点之间的线位于高度场的表面上。还可以通过使用插值器上的SetHeightOffset方法来指定线条的偏移量。类内部使用vtkProjectedTerrainPath在表面上投影折线。投影机上可以指定各种投影模式。这个插值器意味着与vtkTerrainDataPointPlacer一起使用,后者将控制点节点限制在地形表面上。下面的代码片段,来自VTK/Widgets/Testing/Cxx/TerrainPolylineEditor。CXX说明了如何使用这个插值器和点砂石。

vtkContourWidget *contourWidget = vtkContourWidget::New();
vtkOrientedGlyphContourRepresentation *rep =
vtkOrientedGlyphContourRepresentation::SafeDownCast(
contourWidget->GetRepresentation());
vtkTerrainDataPointPlacer * pointPlacer =
vtkTerrainDataPointPlacer::New();
pointPlacer->AddProp(demActor); // the actor(s) containing the terrain
rep->SetPointPlacer(pointPlacer);
// Set a terrain interpolator. Interpolates points as they are placed,
// so that they lie on the terrain.
vtkTerrainContourLineInterpolator *interpolator =
vtkTerrainContourLineInterpolator::New();
rep->SetLineInterpolator(interpolator);
interpolator->SetImageData(demReader->GetOutput());
// Set the default projection mode to hug the terrain, unless user
// overrides it.
interpolator->GetProjector()->SetProjectionModeToHug();
interpolator->GetProjector()->SetHeightOffset(20.0);
pointPlacer->SetHeightOffset(20.0);

        特别有趣的是“活线”插值器(vtkDijkstraImageContourLineInterpolator),其中控制点之间的线是基于在图像上计算的梯度代价函数的最短路径进行插值的,从而使轮廓被吸引到图像的边缘。随着控制点的移动,计算出一条新的最短路径。这是理想的交互式分割器官等。这个插值器内部使用vtkDijkstraImageGeodesicPath,它通过将代价函数图像作为具有VTK_PIXEL单元格的图来生成单个源最短路径。用户可以自由插入cost函数。灰度图像的典型代价函数可能由以下管道生成:

Image --> vtkImageGradientMagnitude --> vtkImageShiftScale

        对梯度幅度图像进行倒置处理,使强边缘具有较低的成本值。从一个顶点移动到另一个顶点的代价使用加权加性方案计算。可以设置边缘长度权值、曲率权值以及与归一化图像代价相关的权值。这些影响用于确定最短路径的计算成本函数。轮廓线被放置在图像actor上,因此使用了类vtkImageActorPointPlacer。这限制了控制点节点在包含图像的平面上的放置。下面的代码片段来自VTK/ Widgets/Testing/Cxx/TestDijkstraImageGeodesicPath。CXX说明了它的用法。

vtkOrientedGlyphContourRepresentation *rep =
vtkOrientedGlyphContourRepresentation::New();
vtkImageActorPointPlacer *placer = vtkImageActorPointPlacer::New();
placer->SetImageActor( actor );
rep->SetPointPlacer( placer );
vtkDijkstraImageContourLineInterpolator *interpolator =
vtkDijkstraImageContourLineInterpolator::New();
interpolator->SetCostImage( gradInvert->GetOutput() );
rep->SetLineInterpolator( interpolator );
vtkDijkstraImageGeodesicPath* path =
interpolator->GetDijkstraImageGeodesicPath();
path->StopWhenEndReachedOn();
// prevent contour segments from overlapping
path->RepelPathFromVerticesOn();
// weights are scaled from 0 to 1 as are associated cost components
path->SetCurvatureWeight( 0.15 );
path->SetEdgeLengthWeight( 0.8 );
path->SetImageWeight( 1.0 );

        vtkImageTracerWidget。这个小部件提供了通过平面跟踪自由形状轮廓的支持(即,手动跟踪图像数据)。用户可以单击图像上方的左键,按住并拖动以绘制徒手线。单击左键并释放将删除小部件行(如果存在),并重新定位第一个句柄。单击中间按钮开始快速绘制线条。在按下ctrl键的同时单击中间键可以终止这行。当用户在第一个手柄的指定公差范围内单击最后一个光标位置时,所跟踪的轮廓环将自动关闭。用户可以拖动手柄(及其关联的线段),方法是单击任何手柄上的右键,该手柄属于一个快速绘制的线条的一部分。如果路径是打开的,并且AutoClose标志设置为On,则可以通过重新定位第一个点和最后一个点来关闭路径。可以通过按ctrl键和手柄上的右键来擦除手柄。同样,快照绘制的线段被更新。如果该行是通过连续跟踪形成的,则该行被删除,留下一个句柄。可以通过按shift键和右键插入手柄。这将在光标位置插入一个句柄。线段相应地在光标的两侧被分割。可以使用SetInteraction方法禁用小部件上的交互。

        vtkImageTracerWidget 由于小部件存在于平面上(手柄等是2D字形),必须指定小部件所在的平面。这是通过SetProjectionNormal指定投影法向量,通过SetProjectionPosition指定平面位置来实现的。在下面的摘录中,投影法线被设置为X轴。用户可以通过使用SnapToImage标志在跟踪时强制捕捉图像数据。用户可以改变句柄和行属性,使用方法SetHandleProperty和SetLineProperty,或者SetSelectedHandleProperty和SetSelectedLineProperty。

        小部件调用InteractionEvent和EndInteractionEvents。此时,可以通过GetPath方法将当前路径作为polydata检索,以便对底层图像执行分割等操作。通过使用InitializeHandles方法,还可以从用户指定的控制点集初始化小部件。它接受一个指向vtkPoints实例的指针,该实例包含点列表。VTK / widget /测试/ Cxx / TestImageTracerWidget。cxx演示了如何使用vkImageTracerWidget和vtkSplineWidget来分割图像。以下是节选。

vtkImageTracerWidget* imageTracerWidget = vtkImageTracerWidget::New();
imageTracerWidget->SetDefaultRenderer(ren1);
imageTracerWidget->SetCaptureRadius(1.5);
imageTracerWidget->GetGlyphSource()->SetColor(1, 0, 0);
imageTracerWidget->GetGlyphSource()->SetScale(3.0);
imageTracerWidget->GetGlyphSource()->SetRotationAngle(45.0);
imageTracerWidget->GetGlyphSource()->Modified();
imageTracerWidget->ProjectToPlaneOn();
imageTracerWidget->SetProjectionNormalToXAxes();
imageTracerWidget->SetProjectionPosition(imageActor1->
GetBounds()[0]);
imageTracerWidget->SetViewProp(imageActor1);
imageTracerWidget->SetInput(shifter->GetOutput());
imageTracerWidget->SetInteractor(iren);
imageTracerWidget->PlaceWidget();
imageTracerWidget->SnapToImageOff();
imageTracerWidget->AutoCloseOn();

        vtkSplineWidget。这是另一个可用于使用样条核跟踪轮廓的小部件。这个小部件早于以vtkContourWidget告终的重构工作。它派生自vtk3DWidget。样条有手柄,手柄的数量可以改变,另外它可以在样条上被选中,在场景中平移或旋转它。小部件响应以下键盘和鼠标修饰符。1)按下左键并拖动其中一个球形手柄以改变样条的形状:手柄充当“控制点”。2)左键或中键按在形成样条的线段上,可使小部件均匀平移。3)在小部件上按下CTRL +中间键可以使小部件围绕其中心旋转。4)在小部件上按下右键,可以缩放小部件。通过将鼠标“向上”移动到渲染窗口,样条将变得更大;通过向下移动渲染窗口,小部件将变得更小。5) ctrl键+右键按下任何手柄将擦除它提供vtkSplineWidget 将有两个或更多的点剩余形成样条。6)在任意线段上按shift键+右键将在光标位置的样条上插入一个手柄。

        vtkSplineWidget有几个方法可以与其他VTK对象一起使用。Set/GetResolution()方法控制样条的细分数量。GetPolyData()方法可用于获得多边形表示,并用于诸如播种流线或探测其他数据集之类的事情。通常,小部件用于使用StartInteractionEvent、InteractionEvent和EndInteractionEvent事件。InteractionEvent在鼠标移动时被调用,另外两个事件在按下按钮和按上按钮(左键或右键)时被调用。

        该类的一些附加特性包括控制小部件属性的能力。可以设置样条的选定和未选定表示形式的属性。例如,您可以为句柄和样条设置属性。此外,还有一些方法可以约束样条,使其与平面对齐。与vtkImageTracerWidget一样,可以指定小部件所在的平面。这是通过SetProjectionNormal指定投影法向量,通过SetProjectionPosition指定平面位置来实现的。GetSummedLength通过将构成样条的线段相加返回样条的近似弧长。SetClosed方法可用于关闭样条循环。

        使用SetParametricSpline方法,还可以设置参数样条对象。通过vtkparameterspline的API,用户可以提供和配置当前两种类型的样条之一:vtkCardinalSpline或vtkKochanekSpline。小部件控制样条的打开或关闭配置。以下摘自VTK/Widgets/Testing/Cxx/TestSplineWidget。CXX演示了这个小部件的用法。

vtkSplineWidget* spline = vtkSplineWidget::New();
spline->SetInput(v16->GetOutput());
spline->SetPriority(1.0);
spline->KeyPressActivationOff();
spline->PlaceWidget();
spline->ProjectToPlaneOn();
spline->SetProjectionNormal(0);
spline->SetProjectionPosition(102.4); //initial plane position
spline->SetProjectionNormal(3); //allow oblique orientations
spline->SetPlaneSource(
static_cast<vtkPlaneSource*>(ipw->GetPolyDataAlgorithm()));
// Specify the type of spline (change from default vtkCardinalSpline)
vtkKochanekSpline* xspline = vtkKochanekSpline::New();
vtkKochanekSpline* yspline = vtkKochanekSpline::New();
vtkKochanekSpline* zspline = vtkKochanekSpline::New();
vtkParametricSpline* para = spline->GetParametricSpline();
para->SetXSpline(xspline);
para->SetYSpline(yspline);
para->SetZSpline(zspline);
vtkPolyData* poly = vtkPolyData::New();
spline->GetPolyData(poly);

        vtkCheckerboardWidget。棋盘小部件用于通过显示两个图像的图像actor交互式地控制棋盘。这在评估图像配准的质量时很有用。用户可以在二维图像的每个i-j方向上调整棋盘划分的数量。这个小部件应该与vtkCheckerboardRepresentation一起使用。当启用时,vtkImageActor周围会出现一个帧,帧的每一边都有滑动条。沿着i和j方向,为两个棋盘提供了总共4个滑块。(这在内部使用vtkSliderRepresentation3D)。用户可以交互式地调整滑块(参见vtkSliderWidget)以达到所需的棋盘细分数量。用户可以通过在小部件上设置自己的滑块表示来覆盖默认的滑块表示。这个小部件需要一个vtkImageCheckerBoard的实例,这个实例需要两个图像作为输入来生成棋盘。下面的例子来自VTK/Widgets/Testing/Cxx/TestCheckerboardWidget。CXX说明了一个典型的用法。

vtkImageCheckerboard *checkers = vtkImageCheckerboard::New();
checkers->SetInput(0,image1);
checkers->SetInput(1,image2);
checkers->SetNumberOfDivisions(10,6,1);
vtkImageActor *checkerboardActor = vtkImageActor::New();
checkerboardActor->SetInput(checkers->GetOutput());
vtkCheckerboardRepresentation *rep =
vtkCheckerboardRepresentation::New();
rep->SetImageActor(checkerboardActor);
rep->SetCheckerboard(checkers);
vtkCheckerboardWidget *checkerboardWidget =
vtkCheckerboardWidget::New();
checkerboardWidget->SetInteractor(iren);
checkerboardWidget->SetRepresentation(rep);

        vtkRectilinearWipeWidget。vtkreclinearwipewidget显示一对图像的分割视图(2x2棋盘),允许一个人控制分割的位置。这在比较两幅图像时很有用,通常是在图像配准管道中从源图像进行配准的图像。直线擦除是通过组合两个独立的图像创建的2x2棋盘图案,其中各种组合的方格是可能的。必须注意的是,尽管这个小部件在功能上看起来与棋盘小部件相似,但有重要的区别。使用这个小部件,用户可以调整检查器模式的布局,例如移动中心点、移动水平分隔符或移动垂直分隔符。擦除的位置(两个图像之间的接口)可以更改为图像中的任何一点,这与棋盘小部件不同,在棋盘小部件中,只能交互地更改棋盘的分辨率。可以通过使用鼠标左键选择分隔符来选择水平分隔符和垂直分隔符。按住按钮拖动可移动分隔符。选择中心点允许您移动vtkCheckerboardWidget 水平和垂直分隔符同时。要使用这个小部件,请指定它的表示(默认情况下,表示是vtkreclinearwipeprop的一个实例)。

        这个表示要求你指定一个vtkImageRectilinearWipe的实例和一个vtkImageActor的实例。可以在vtkImageRectilinearWipe实例上指定各种“擦除”模式。这些模式决定了如何将两个输入图像组合在一起。第一种是四元模式,使用SetWipeToQuad方法。在这种模式下,输入水平和垂直交替。你可以使用SetWipeToHorizontal或SetWipeToVertical来获得一个纯粹的水平或垂直擦拭。在这种模式下,图像的一半来自一个输入,另一半来自另一个输入。你也可以得到一个角擦除,有3个输入来自一个输入图像,一个来自另一个输入图像,通过使用SetWIpeToLowerLeft, SetWipeToLowerRight, SetWipeToUpperLeft和SetWipeToUpperRight方法。以下摘自VTK/Widgets/Testing/Cxx/ testreclinearwipewidget。CXX说明了它的用法。

vtkImageRectilinearWipe *wipe = vtkImageRectilinearWipe::New();
wipe->SetInput(0,pad1->GetOutput());
wipe->SetInput(1,pad2->GetOutput());
wipe->SetPosition(100,256);
wipe->SetWipeToQuad();
vtkImageActor *wipeActor = vtkImageActor::New();
wipeActor->SetInput(wipe->GetOutput());
vtkRectilinearWipeWidget *wipeWidget = vtkRectilinearWipeWidget::New();
vtkRectilinearWipeRepresentation *wipeWidgetRep=
static_cast<vtkRectilinearWipeRepresentation *>(
wipeWidget->GetRepresentation());
wipeWidgetRep->SetImageActor(wipeActor);
wipeWidgetRep->SetRectilinearWipe(wipe);
wipeWidgetRep->GetProperty()->SetLineWidth(2.0);
wipeWidgetRep->GetProperty()->SetOpacity(0.75);

        vtkSeedWidget。vtkSeedWidget可用于放置多个种子点。这些通常用于连接、分割、区域增长、图像配准基准等操作。这个小部件与vtkSeedRepresentation的实例(vtkSeedRepresentation的子类)一起工作。小部件内部包含vtkHandleWidget的实例,以表示每个种子。句柄小部件反过来可以由vtkhandlererepresentation的任何子类表示。vtkPointHandleRepresentation2D可以用来定义2D覆盖平面上的种子。vtkPointHandleRepresentation3D可以用来表示vtkdireclinearwipewidget vtkSeedWidget 种子在一个3D场景。可以使用vtkSeedRepresentation中的SetHandleRepresentation方法设置适当的句柄表示。

        一旦启用了vtkSeedWidget,用户就可以通过按鼠标左键来掉落种子点。在用户完成播撒种子后,点击右键将终止播撒,并将小部件发送到“操纵”模式。在这种模式下,用户可以通过用鼠标左键点击选择一个种子,并按下按钮拖动它来翻译它。就像手柄小部件一样,种子通过按下shift键拖动轴来响应轴的平移;将轴确定为与鼠标运动向量最对齐的轴。按“删除”键可以删除当前选定的句柄。如果没有选择种子,按delete键将删除最后添加的种子。

        放置种子时,小部件调用PlacePointEvent,观察者可以监视该事件。与其他小部件非常相似,vtkSeedWidget也在用户交互之前、期间和之后调用StartInteractionEvent、InteractionEvent和EndInteractionEvent。以下摘自VTK/ Widgets/Testing/Cxx/TestSeedWidget2。CXX说明了一个典型的用法。

vtkPointHandleRepresentation2D *handle =
vtkPointHandleRepresentation2D::New();
handle->GetProperty()->SetColor(1,0,0);
vtkSeedRepresentation *rep = vtkSeedRepresentation::New();
rep->SetHandleRepresentation(handle);
vtkSeedWidget *widget = vtkSeedWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);
  • 其它

        vtkXYPlotWidget。vtkXYPlotWidget为交互式操作XY绘图的位置、大小和方向提供了支持。小部件通常用于从一个或多个输入数据集或字段数据生成XY图。它内部包含一个vtkXYPlotActor的实例来执行绘图功能。可以通过GetXYPlotActor()检索这个实例。vtkXYPlotActor中的x轴值是通过取点id,计算累积弧长或规范化弧长来生成的。可以指定多个输入数据集来生成多个图。或者,如果字段数据作为输入提供,则该类将一个组件与另一个组件进行对比。用户必须指定使用哪个组件作为x轴,哪个组件作为y轴。

        若要使用该类绘制数据集,用户需要指定一个或多个包含标量和点数据的输入数据集。要使用这个类来绘制字段数据,用户需要指定一个或多个输入数据对象及其关联的字段数据。在绘制字段数据时,直接使用x和y值(即,没有标准化组件的选项)。用户可以使用SetTitle、SetXTitle和settytitle方法指定轴标签、标签格式和绘图标题。还可以使用SetXRange和SetYRange方法手动指定x和y绘图范围(默认情况下它们是自动计算的)。超出指定范围的数据被截断。您还可以使用SetNumberOfXLabels和SetNumberOfYvtkXYPlotWidget来指定沿轴的注释标签的数量。个label方法的介绍。类似地,X和Y小刻度的数量可以使用SetNumberOfXMinorTicks和SetNumberOfYMinorTicks方法来控制。Border实例变量用于在绘图窗口的边界之间创建空间,该区域可以交互式地调整大小。绘图标题的字体属性可以使用SetTitleTextProperty来修改。坐标轴标题和标签的字体属性也可以使用SetAxisTitleTextProperty和SetAxisLabelTextProperty来修改。用户还可以使用GetXAxisActor2D或GetYAxisActor2D方法来访问每个单独的轴角色以修改其字体属性。这会返回vtkAxisActor2D的实例。以同样的方式,GetLegendBoxActor方法可以用来访问图例框actor来修改它的字体属性。

        用户还可以为每条曲线分配属性(如颜色和绘图符号)。用户可以选择添加图形图例,以图形方式表示曲线、曲线符号和数据源之间的对应关系。图例可以使用LegendOn/ off()打开/关闭。用户还可以通过使用ExchangeAxis方法交换x轴和y轴来重新定向绘图。用户还可以通过使用ReverseXAxis和ReverseYAxis方法反转X轴和Y轴。用户可以使用LogXOn()在对数刻度上绘图。

        小部件允许交互式地调整角色的大小和重新定位。它监听鼠标左键事件和鼠标移动。它将根据光标的位置改变光标的形状。如果光标位于绘图的边缘上,它将把光标形状更改为适当的调整大小边缘形状。然后,用户可以左键单击并拖动来调整大小。如果光标在中心附近徘徊,则光标将变为四向平移形状。然后,用户可以左键点击并拖动来重新定位绘图。如果将XY绘图的位置移动到接近视口四条边之一的中心,则XY绘图将改变其方向以与该边对齐。这个方向是粘性的,因为它将保持这个方向,直到位置移动到另一个边缘附近。下面的代码摘录展示了如何使用这个小部件。

vtkXYPlotWidget * widget = vtkXYPlotWidget::New();
widget->SetInteractor(iren);
// Get the plot actor so we can adjust properties on the actor.
vtkXYPlotActor *plotActor = widget->GetXYPlotActor();
xyplot->AddInput(probe->GetOutput());
xyplot->AddInput(probe2->GetOutput());
xyplot->AddInput(probe3->GetOutput());
xyplot->GetPositionCoordinate()->SetValue(0.0, 0.67, 0);
xyplot->GetPosition2Coordinate()->SetValue(1.0, 0.33, 0);
// relative to Position
xyplot->SetXValuesToArcLength();
xyplot->SetNumberOfXLabels(6);
xyplot->SetTitle("Pressure vs. Arc Length - Zoomed View");
xyplot->SetXTitle(""); // no X title
xyplot->SetYTitle("P");
xyplot->SetXRange(.1, .35);
xyplot->SetYRange(.2, .4);
xyplot->GetProperty()->SetColor(0, 0, 0);
xyplot->GetProperty()->SetLineWidth(2);
vtkTextProperty *tprop = xyplot->GetTitleTextProperty();
tprop->SetColor(xyplot->GetProperty()->GetColor());
xyplot->SetAxisTitleTextProperty(tprop);
xyplot->SetAxisLabelTextProperty(tprop);
xyplot->SetLabelFormat("%-#6.2f");
widget->SetEnabled(1);

        vtkCompassWidget。compass小部件为交互式注释和操作地理空间场景的方向提供了支持。该类还具有缩放和倾斜控件,用于在地理空间视图中定位自己。这个小部件在VTK的GeoVis视图中使用(第207页的“地理空间可视化”)。您可以拖动标题轮来更改小部件的标题,也可以拖动滑块来设置小部件的缩放级别或倾斜。这个小部件最容易与vtkgeoccamera结合使用,vtkgeoccamera根据三个参数(heading、tilt和zoom)保留相机位置。下面的代码展示了如何将小部件的属性链接到小部件的InteractionEvent事件处理程序中的vtkgeoccamera。

vtkGeoCamera* camera = vtkGeoCamera::New();
vtkCompassWidget* widget = vtkCompassWidget::New();
widget->CreateDefaultRepresentation();
// In callback for InteractionEvent:
camera->SetHeading(widget->GetHeading()*360.0);
camera->SetTilt(widget->GetTilt());
camera->SetDistance(widget->GetDistance());

        vtkSliderWidget。这个小部件提供沿1D范围操作滑块的功能。这个小部件应该与vtkSliderRepresentation的实例一起使用。该工具包提供了两个具体的表示:vtkSliderRepresentation2D和vtkSliderRepresentation3D。vtkSliderRepresentation2D在覆盖平面上渲染滑块,而vtkSliderRepresentation3D在3D空间中渲染滑块。该范围由一根管子表示,管子上有一个用于滑块的头,两端有两个盖子,用来划定下限和上限。这些属性可以通过使用vtkSliderRepresentation上的SetSliderWidth(), SetSliderLength(), SetTubeWidth(), SetEndCapLength()和SetEndCapWidth()方法来改变。也可以检索和修改帽/管等的属性。类似地,滑动条属性也可以在被选中和未被选中时进行修改。

        可以使用SetTitleText()方法在滑动条旁边显示标题。还可以使用ShowSliderLabelOn()方法显示它旁边的当前滑动条值。

        滑动条值的下界和上界可以使用SetMinimumValue()和SetMaximumValue()设置。SetValue()方法本身可用于以编程方式设置滑块的当前值。

        使用左键选择滑块。在按下左键的情况下拖动滑块沿着管道移动。如果选择了管子或两个端盖中的一个,则滑块将跳转或移动到所选位置。用户可以使用SetAnimationModeToJump()或SetAnimationModeToAnimate()方法来选择想要的行为。用于动画的步骤数(如果vtkCompassWidget vtkSliderWidget 模式之旅是动画)可以使用SetNumberOfAnimationSteps()来控制。或者,可以使用SetAnimationModeToOff()完全禁用此行为。小部件在用户交互之前、期间和之后调用StartInteractionEvent、InteractionEvent和EndInteractionEvent。以下摘自VTK/Widgets/Testing/Cxx/TestSliderWidget。cxx演示了vtkSliderWidget与vtkSliderRepresentation3D的结合用法。

vtkSliderRepresentation3D *sliderRep =
vtkSliderRepresentation3D::New();
sliderRep->SetValue(0.25);
sliderRep->SetTitleText("Spike Size");
sliderRep->GetPoint1Coordinate()->SetCoordinateSystemToWorld();
sliderRep->GetPoint1Coordinate()->SetValue(0,0,0);
sliderRep->GetPoint2Coordinate()->SetCoordinateSystemToWorld();
sliderRep->GetPoint2Coordinate()->SetValue(2,0,0);
sliderRep->SetSliderLength(0.075);
sliderRep->SetSliderWidth(0.05);
sliderRep->SetEndCapLength(0.05);
vtkSliderWidget *sliderWidget = vtkSliderWidget::New();
sliderWidget->SetInteractor(iren);
sliderWidget->SetRepresentation(sliderRep);
sliderWidget->SetAnimationModeToAnimate();
sliderWidget->EnabledOn();

以下摘录自VTK/Widgets/Testing/Cxx/TestSliderWidget2D,说明了vtkSliderWidget与vtkSliderRepresentation2D一起在覆盖平面上渲染滑块的用法。

vtkSliderRepresentation2D *sliderRep =
vtkSliderRepresentation2D::New();
sliderRep->SetValue(0.25);
sliderRep->SetTitleText("Spike Size");
sliderRep->GetPoint1Coordinate()->
SetCoordinateSystemToNormalizedDisplay();
sliderRep->GetPoint1Coordinate()->SetValue(0.2,0.1);
sliderRep->GetPoint2Coordinate()->
SetCoordinateSystemToNormalizedDisplay();
sliderRep->GetPoint2Coordinate()->SetValue(0.8,0.1);
sliderRep->SetSliderLength(0.02);
sliderRep->SetSliderWidth(0.03);
sliderRep->SetEndCapLength(0.01);
sliderRep->SetEndCapWidth(0.03);
sliderRep->SetTubeWidth(0.005);
vtkSliderWidget *sliderWidget = vtkSliderWidget::New();
sliderWidget->SetInteractor(iren);
sliderWidget->SetRepresentation(sliderRep);
sliderWidget->SetAnimationModeToAnimate();

        vtkCenteredSliderWidget。pvtkcenteredsliderwidget类似于vtkSliderWidget。然而,它的交互提供了基于滑块的操纵杆控制。这个小部件应该与vtkCenteredSliderRepresentation的实例一起使用。未选中时,滑块始终保持在中心位置。用户可以通过按左键选择滑块。然后,用户可以在按下按钮的情况下向上或向下拖动滑块,从而增加或减少滑块所表示的值。增加(或减少)与滑块被压下并保持远离中心的时间以及滑块偏离其中心的幅度成正比。在释放时,滑块返回到中点。该表示在vtkCompassRepresentation内部使用,用于表示罗盘的倾斜和距离值。因此,你可以轻轻向上移动滑块,看着相机慢慢向前倾斜。或者,你也可以向上拉滑块,使相机快速向前倾斜。像其他小部件一样,vtkCenteredSliderWidget在用户交互之前,期间和之后调用StartInteractionEvent, InteractionEvent和EndInteractionEvent。居中滑块小部件的用法与vtkSliderWidget非常相似。小部件上的GetValue()方法可用于随时查询该值。

        vtkCameraWidget。vtkCameraWidget支持交互式保存和播放一系列摄像机视图到插值路径。插值本身是使用vtkCameraInterpolator实例完成的。用户可以使用小部件记录一系列视图,然后使用vtkCameraInterpolator回放插值的相机视图。要使用这个小部件,用户需要指定一个摄像机进行插值,然后点击“record”按钮开始录制。然后操纵摄像机(通过使用交互器、直接脚本或任何其他方式)。交互完成后,保存相机视图。可以重复这个过程来记录一系列视图。

        这个小部件应该与vtkCameraRepresentation的实例一起使用。表示的几何图形由一个相机图标、一个播放-停止图标和一个删除图标组成。这些是在覆盖平面上渲染的。按下相机图标将当前相机参数定义的视图添加到插值相机路径中。按播放按钮沿当前路径插值帧。相机插值器可以通过在表示上使用GetCameraInterpolator方法来检索。可以使用插值器来设置插值类型(线性或样条)。表示上的SetNumberOfFrames方法可用于控制在动画摄像机路径时用于两个摄像机节点之间插值的帧数。以下摘自VTK/Widgets/Testing/Cxx/TestCameraWidget。CXX说明了一个典型的用法。

vtkCameraRepresentation *rep = vtkCameraRepresentation::New();
rep->SetNumberOfFrames(2400);
vtkCameraWidget *widget = vtkCameraWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);

        vtkPlaybackWidget。该vtkPlaybackWidget提供了交互式控制的回放串行流的信息(例如,动画序列,视频)的支持。控制播放,停止,前进一步,后退一步,跳到开始,跳到结束是可用的。这个小部件与vtkPlaybackRepresentation的实例一起工作。表示存在于覆盖平面上,并派生自vtkBorderWidget。它可以使用角/边或靠近中心的位置交互式地调整大小或重新定位。回放小部件提供了6个图标形式的控件。这些控制允许(a)跳转到帧的开始(b)恢复一帧(c)停止播放(d)播放(e)向前跳转一帧(f)跳转到结束。实现留给子类。ie。期望用户子类化vtkPlaybackRepresentation来为上面的6个控件提供他们自己的实现。以下摘自VTK/Widgets/Testing/Cxx/TestPlaybackWidget。CXX说明了一个典型的用法。

class vtkSubclassPlaybackRepresentation : public
vtkPlaybackRepresentation
{
public:
static vtkSubclassPlaybackRepresentation *New()
{return new vtkSubclassPlaybackRepresentation;}
virtual void Play() {cout << "play\n";}
virtual void Stop() {cout << "stop\n";}
virtual void ForwardOneFrame() {cout << "forward one frame\n";}
virtual void BackwardOneFrame() {cout << "backward one frame\n";}
virtual void JumpToBeginning() {cout << "jump to beginning\n";}
virtual void JumpToEnd() {cout << "jump to end\n";}
};
...
vtkSubclassPlaybackRepresentation *rep =
vtkSubclassPlaybackRepresentation::New();
vtkPlaybackWidget *widget = vtkPlaybackWidget::New();
widget->SetInteractor(iren);
widget->SetRepresentation(rep);

一个例子

        下面的例子来自Widgets/Testing/Cxx/TestAffineWidget。cxx使用vtkAffineWidget来交互地转换(剪切/旋转/平移/缩放)2D图像。我们将观察小部件与类vtkAffineCallback的交互,以便更新图像actor上的转换。

class vtkAffineCallback : public vtkCommand
{
public:
static vtkAffineCallback *New()
 { return new vtkAffineCallback; }
 virtual void Execute(vtkObject *caller, unsigned long, void*);
 vtkAffineCallback():ImageActor(0),AffineRep(0)
{this->Transform = vtkTransform::New();}
 ~vtkAffineCallback()
 {this->Transform->Delete();}
 vtkImageActor *ImageActor;
 vtkAffineRepresentation2D *AffineRep;
 vtkTransform *Transform;
};
void vtkAffineCallback::Execute(vtkObject*, unsigned long, void*)
{
this->AffineRep->GetTransform(this->Transform);
this->ImageActor->SetUserTransform(this->Transform);
}
int TestAffineWidget( int argc, char *argv[] )
{
 // Create the pipeline
 char* fname = vtkTestUtilities::ExpandDataFileName(
argc, argv, "Data/headsq/quarter");

vtkVolume16Reader* v16 = vtkVolume16Reader::New();
 v16->SetDataDimensions(64, 64);
 v16->SetDataByteOrderToLittleEndian();
 v16->SetImageRange(1, 93);
 v16->SetDataSpacing(3.2, 3.2, 1.5);
 v16->SetFilePrefix(fname);
 v16->ReleaseDataFlagOn();
 v16->SetDataMask(0x7fff);
 v16->Update();
delete[] fname;
double range[2];
v16->GetOutput()->GetScalarRange(range);
vtkImageShiftScale* shifter = vtkImageShiftScale::New();
 shifter->SetShift(-1.0*range[0]);
 shifter->SetScale(255.0/(range[1]-range[0]));
 shifter->SetOutputScalarTypeToUnsignedChar();
 shifter->SetInputConnection(v16->GetOutputPort());
 shifter->ReleaseDataFlagOff();
 shifter->Update();
vtkImageActor* imageActor = vtkImageActor::New();
 imageActor->SetInput(shifter->GetOutput());
 imageActor->VisibilityOn();
 imageActor->SetDisplayExtent(0, 63, 0, 63, 46, 46);
 imageActor->InterpolateOn();
double bounds[6];
imageActor->GetBounds(bounds);
// Create the RenderWindow, Renderer and both Actors
vtkRenderer *ren1 = vtkRenderer::New();
vtkRenderWindow *renWin = vtkRenderWindow::New();
renWin->AddRenderer(ren1);
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
vtkInteractorStyleImage *style = vtkInteractorStyleImage::New();
iren->SetInteractorStyle(style);
// VTK widgets consist of two parts: event processing and the
// representation that defines how the widget appears in the scene
vtkAffineRepresentation2D *rep = vtkAffineRepresentation2D::New();
rep->SetBoxWidth(100);
 rep->SetCircleWidth(75);
 rep->SetAxesWidth(60);
 rep->DisplayTextOn();
 rep->PlaceWidget(bounds);
vtkAffineWidget *widget = vtkAffineWidget::New();
 widget->SetInteractor(iren);
 widget->SetRepresentation(rep);
vtkAffineCallback *acbk = vtkAffineCallback::New();
 acbk->AffineRep = rep;
 acbk->ImageActor = imageActor;
widget->AddObserver(vtkCommand::InteractionEvent,acbk);
widget->AddObserver(vtkCommand::EndInteractionEvent,acbk);
// Add the actors to the renderer, set the background and size
 ren1->AddActor(imageActor);
 ren1->SetBackground(0.1, 0.2, 0.4);
 renWin->SetSize(300, 300);
 iren->Initialize();
 renWin->Render();
 iren->Start();
}

13.4选择

        从最一般的意义上讲,选择是一种数据结构,它指定了其他内容的子集。可以突出显示该子集以显示数据中的特征,或者可以提取该子集以更详细地分析数据的一部分。VTK提供了一个框架,用于使用vtkSelection类在应用程序中生成、处理和共享选择,以及相关的选择源、过滤器和视图。

        vtkSelection是一个容器类,包含一个或多个vtkSelectionNode对象。每个节点包含指示选择数据的哪一部分的信息。复合选择被解释为单个节点选择的并集。我们允许选择由多个节点组成,这样在,我们就可以在数据的多个部分上表示选择。例如,几何体上的选择可能包含点和单元的vtkSelectionNode。另一个用例是将来自同一渲染器中的多个数据集的选择收集到一个地方。

13.5选择类型

        每个vtkSelectionNode都有一个选择类型,它指示如何解释选择。选择类型是在vtkSelectionNode.h中定义的常量。与选择相关联的值存储在由GetSelectionList()

检索的数组中。

为方便起见,我们将使用术语“元素”来表示可以为其分配属性的数据集的基本构建块。对于vtkDataSet子类,元素是点和单元格。vtkGraph子类的元素是顶点和边。对于vtkTable,元素是表的行。索引选择这是最基本的选择类型。索引选择的选择列表是一个vtkIdTypeArray,包含数据集中所选元素的原始从零开始的索引,使用数据集的内部排序。由于这些索引可能会随着数据集的处理或过滤而变化,因此索引选择通常只适用于单个数据集。不应该在具有不同拓扑结构的数据集之间共享索引选择。

系谱ID选择

系谱ID是分配给数据源数据集中每个元素的标识符,并沿着管道传播。通过在数据集的属性上调用SetPedigreeIds(),以与指定标量和向量等其他特殊属性相同的方式在数据集上指定系谱id。谱系ID数组可以是任何类型,包括vtkStringArray和vtkVariantArray。系谱ID选择包含来自数据集系谱ID数组的值列表。谱系ID和全局ID选择都通过名称引用元素,而不是通过索引选择中使用的特定于数据集的偏移量,这使得它们在来自同一来源的不同数据集之间更加健壮。

全局ID选择

全局ID选择与系谱ID选择非常相似,除了它们引用全局ID属性(使用SetGlobalIds()设置)。全局id的使用方式与系谱id类似,不同之处在于它们必须是数字的,并且一些过滤器会重新分配全局id以确保id不会重复。

截锥体选择

截锥体选择只是在选择中存储截锥体的几何形状。截锥体内的所有元素都被认为是选定的。这在用户在3D场景中拖拽选择一个区域的情况下是最有用的。屏幕上的矩形区域在3D场景中转化为截锥体。这种选择类型的选择列表必须是一个vtkDoubleArray,包含八个四组件元组。这些点的形式为(x,y,z,1),它们的顺序如下:

1. 左下角附近
2. 远左下方
3. 左上角附近
4. 最左上角
5. 近右下角
6. 右下角
7. 近右上方
8. 最右上方

值选择值

选择是指引用任意数组中的元素的选择。在值选择中,必须将选择列表的名称设置为要选择的数组的名称。例如,如果您有一个数据集,其中的点包含一个从0到10不等的整数属性“type”。要只选择值为1、3和7的点,请创建vtkIntArray,向其添加所需的值,然后将数组名称设置为“type”。最后,使用您创建的数组调用node- SetSelectionList(arr)。

阈值选择

阈值选择的工作原理与值选择类似,不同之处在于您使用数组中的每对元素指定值范围。虽然值选择可以是任何类型,但阈值选择只适用于数值数组,并且选择列表必须是vtkDoubleArray。要选择类型在0-5范围内的点,创建一个vtkDoubleArray并添加元素0和5。您可以通过添加更多的数字对来向阈值选择添加其他范围。

位置选择

顾名思义,您可以为这种类型的选择提供您想要选择的3D位置。位置选择必须是vtkDoubleArray,每个元组有3个组件。位置选择通常用于选择包含点的单元格。对于引用数据集点的位置选择,有一种方法可以指定所选数据集点到选择列表中点的最大距离:

n->GetProperties()->Set(vtkSelectionNode::EPSILON(), distance);

块的选择

VTK数据对象,vtkMultiBlockDataset,可以存储数据集的集合。块选择允许您指定要选择哪些块。选择列表必须是vtkUnsignedIntArray。
使用硬件选择器。VTK提供了类vtkHardwareSelector来帮助您从屏幕的矩形区域生成选择。这个过程类似于AreaPicking(第59页的“Picking”),但是能够返回关于所选内容的更细粒度的细节。

vtkHardwareSelector* hs = vtkHardwareSelector::New();
 hs->SetRenderer(ren);
 hs->SetArea(xmin, ymin, xmax, ymax);
vtkSelection* s = hs->Select();

硬件选择器执行特殊的呈现传递,以确定选择呈现器中的哪些数据集,以及选择这些数据集中的哪些单元格。在选择区域内呈现为至少一个像素的任何单元格都被插入到输出选择中。输出选择为每个选定的参与者包含一个vtkSelectionNode。默认情况下,这些节点是单元格索引选择,不过硬件选择器也可以配置为选择点。您可以通过访问选择节点的PROP属性来检索指向场景中相关演员的指针。

提取的选择。现在我们知道了如何定义选择,我们必须以某种方式使用它。最常见的任务之一是从数据集中提取选择。要做到这一点,使用vtkExtractSelection过滤器为vtkDataSets或vtkMultiBlockDataSets,或使用vtkExtractSelectedGraph为vtkGraphs。这两个过滤器的工作方式相似,并且接受任何类型的选择。要从vtkPolyData中提取一个选择,我们可以这样做:

vtkPolyData* pd = vtkPolyData::New();
// Populate the poly data here
vtkSelection* s = vtkSelection::New();
// Populate the selection here
vtkExtractSelection* ex = vtkExtractSelection::New();
ex->SetInput(0, pd);
ex->SetInput(1, s);
ex->Update();
vtkUnstructuredGrid* extracted = ex->GetOutput();

注意,因为vtkExtractSelection接受任何vtkDataSet子类,所以输出是最通用的数据集vtkUnstructuredGrid。输出类型不能匹配输入类型,因为,例如,在结构化类型(如vtkImageData)上表示任意子集的选择可能不再是结构化的。如果您希望简单地标记数据集的选定元素,请在更新过滤器之前调用ex-&gt;PreserveTopologyOn()。这将以相同的数据类型将数据结构不变地传递给输出。过滤器不会剔除被拒绝的元素,而是向每个元素添加一个布尔标志,指示它是否被选中。

本书为英文翻译而来,供学习vtk.js的人参考。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值