VTK提供了两种方法用于标注图像。第一种是可以在三维图形窗口的顶层上绘制的文本(和图形),通常涉及的是在层叠平面上绘制。第二种是创建三维的多边形数据的文本,可以像其他三维图形对象一样进行变换及显示。这两种类型的标注分别称为二维和三维标注,从图4-7中可以看出它们的区别。
图4-7 二维(左)和三维(右)标注
使用二维文本标注时,需要用到二维的Actor(vtkActor2D或它的子类,如vtkScaledTextActor)和Mapper(vtkMapper2D或其子类vtkTextMapper)。二维的Actor和Mapper跟三维的类似,不同的是前者是在图形或图像的顶层层叠平面(overlay plane)上进行渲染的。下面的例子摘自VTK/Examples/Annotation/Tcl/TestText.tcl,结果如图4-7所示。
vtkSphereSource sphere
vtkPolyDataMapper sphereMapper
sphereMapper SetInputConnection [sphere GetOutputPort]
sphereMapper GlobalImmediateModeRenderingOn
vtkLODActor sphereActor
sphereActor SetMapper sphereMapper
#Create a scaled text actor.
#Set the text, font, justification, and properties (bold, italics, etc.).
vtkTextActor textActor
textActor SetTextScaleModeToProp
textActor SetDisplayPosition 90 50
textActor SetInput "This is asphere"
# Set coordinates to match the oldvtkScaledTextActor default value
[textActor GetPosition2Coordinate] SetCoordinateSystemToNormalizedViewport
[textActor GetPosition2Coordinate] SetValue0.6 0.1
set tprop [textActor GetTextProperty]
$tprop SetFontSize 18
$tprop SetFontFamilyToArial
$tprop SetJustificationToCentered
$tprop BoldOn
$tprop ItalicOn
$tprop ShadowOn
$tprop SetColor 0 0 1
#Create the Renderer, RenderWindow, RenderWindowInteractor
#
vtkRenderer ren1
vtkRenderWindow renWin
renWin AddRenderer ren1
vtkRenderWindowInteractor iren
iren SetRenderWindow renWin
#Add the actors to the renderer; set the background and size; zoom in;
#and render.
#
ren1 AddViewProp textActor
ren1 AddViewProp sphereActor
vtkTextProperty实例可以设置字体(Arial,Courier或者Times等),文本颜色,粗体、斜体开关以及字体的阴影效果等。字体的阴影效果可以使标注的文本在复杂背景下可读性更强。标注文本的位置和颜色则通过关联的vtkActor2D控制的。在这个例子中,文本的位置是用显示坐标或者像素坐标进行设置的。
vtkTextProperty也支持对齐(垂直和水平)及多行文本。方法SetJustificationToLeft(),SetJustificationToCentered()和SetJustificationToRight()可以控制水平对齐方向。SetVerticalJustificationToBottom(),SetVerticalJustificationToCentered()和SetVerticalJustificationToTop()等方法可以控制垂直对齐方向,缺省的对齐方向是左下角对齐。文本中嵌入“\n”字符可以支持多行文本。图4-8是对齐和多行文本的效果,该例子摘自VTK/Examples/Annotation/Tcl/multiLineText.tcl。以下是例子的主要代码:
vtkTextMapper textMapperL
textMapperL SetInput "Thisis\nmulti-line\ntext output\n(left-top)"
set tprop [textMapperL GetTextProperty]
$tprop ShallowCopy multiLineTextProp
$tprop SetJustificationToLeft
$tprop SetVerticalJustificationToTop
$tprop SetColor 1 0 0
vtkActor2D textActorL
textActorL SetMapper textMapperL
[textActorL GetPositionCoordinate]SetCoordinateSystemToNormalizedDisplay
[textActorL GetPositionCoordinate] SetValue0.05 0.5
图4-8 文本对齐和多行文本。在文本里嵌入“\n”字符可以生成多行文本,支持水平和垂直对齐
注意,以上代码使用vtkCoordinate对象(调用方法GetPositionCoordinate()获得)控制Actor在NormalizedDisplay坐标系统下位置。参考“vtkCoordinate和坐标系统”一节,了解更多关于放置文本标注的信息。
三维文本标注的实现是使用vtkVectorText创建文本字符串的多边形表达形式(Polygonal Representation),然后把它放置在渲染场景中。放置三维文本标注的类是vtkFollower。该类是vtkActor的子类,vtkFollower的对象总是面向渲染器的当前相机,因此可以保证这种文本标注都是可读、可见的。以下的代码演示了如何使用这个类,代码摘自VTK/Examples/Annotation/Tcl/textOrigin.tcl,运行结果如图4-7所示。这个例子创建了一个坐标轴和一个vtkVectorText实例,结合vtkFollower对象标注该坐标轴的原点。
vtkAxes axes
axes SetOrigin 0 0 0
vtkPolyDataMapper axesMapper
axesMapper SetInputConnection [axes GetOutputPort]
vtkActor axesActor
axesActor SetMapper axesMapper
#Create the 3D text and the associated mapper and follower (a type of
#actor). Position the text so it isdisplayed over the origin of the axes.
vtkVectorText atext
atext SetText "Origin"
vtkPolyDataMapper textMapper
textMapper SetInputConnection [atext GetOutputPort]
vtkFollower textActor
textActor SetMapper textMapper
textActor SetScale 0.2 0.2 0.2
textActor AddPosition 0 -0.1 0
…etc…after rendering…
textActor SetCamera [ren1 GetActiveCamera]
当相机绕着坐标轴旋转时,vtkFollower对象会调整自己的方向,使其朝向相机。你可以试着在渲染窗口里,用鼠标移动相机,观察这种变化。
VTK提供了一些复合类用于实现绘图操作。包括绘制标量条、执行简单的X-Y平面绘图以及在三维空间中放置坐标轴等。
类vtkScalarBarActor用于创建与数值数据相关联的带关键颜色值的颜色条,如图4-9所示。这种标量条由三部分组成,分别是:一个带颜色的矩形条、标注和标题。使用vtkScalarBarActor时,必须含有如下信息:引用一个vtkLookupTable实例(该实例用于定义颜色和数值数据的范围),在层叠平面(overlay plane)上放置颜色条的位置并指定其方向,标注的个数以及标量的文本字符串等。以下例子演示了该类的用法。
图4-9vtkScalarBarActor用于创建颜色条
vtkScalarBarActor scalarBar
scalarBar SetLookupTable [mapper GetLookupTable]
scalarBar SetTitle "Temperature"
[scalarBar GetPositionCoordinate] SetCoordinateSystemToNormalizedViewport
[scalarBar GetPositionCoordinate] SetValue0.1 0.1
scalarBar SetOrientationToHorizontal
scalarBar SetWidth 0.8
scalarBar SetHeight 0.17
标量条的方向是通过方法SetOrientationToVertical()和SetOrientationToHorizontal()来指定的。位置(即标量条左下角)则是通过不同的坐标系统(允许使用任何坐标系统,见“vtkCoordinate和坐标系统”一节)设置,宽度和高度使用了NormalizedViewport坐标系下的坐标值来指定(或者也可以通过指定标量条右上角的位置,即设置Position2变量的值,间接来设置标量条的宽度和高度)。
类vtkXYPlotActor可根据输入的一个或多个数据集生成X-Y平面图形,如图4-10所示。该类在显示某个数据变量与一系列点之间的变化情况时非常有用,比如某个变量与探测线或者边界线之间的变化情况。
使用vtkXYPlotActor2D时,必须输入一个或多个数据集,指定坐标轴以及所绘制图形的标题、位置等。该类里的变量PositionCoordinate指定了X-Y图形左下角的位置(定义在Normalizedviewport坐标系下),而变量Position2Coordinate则指定图形的右上角位置坐标。注意:Position2Coordinate是相对于PositionCoordinate而言的,因此可以通过设置PositionCoordinate在视口里移动vtkXYPlotActor。这两个位置确定了图形所在的矩形区域。以下例子演示了该类的用法(程序摘自VTK/Examples/Annotation/Tcl/xyPlot.tcl)
vtkXYPlotActor xyplot
xyplot AddInput [probe GetOutput]
xyplot AddInput [probe2 GetOutput]
xyplot AddInput [probe3 GetOutput]
[xyplot GetPositionCoordinate] SetValue 0.00.67 0
[xyplot GetPosition2Coordinate] SetValue1.0 0.33 0;#relative to Position
xyplot SetXValuesToArcLength
xyplot SetNumberOfXLabels 6
xyplot SetTitle "Pressure vs. ArcLength (Zoomed View)"
xyplot SetXTitle ""
xyplot SetYTitle "P"
xyplot SetXRange .1 .35
xyplot SetYRange .2 .4
[xyplot GetProperty] SetColor 0 0 0
图4-10使用类vtkXYPlotActor2D来显示分别用三种不同的技术所获取的探测线数据(见VTK/Hybrid/Testing/Tcl/xyPlot.tcl)
注意X轴的定义,缺省情况下,以输入数据集的点的索引作为X轴。也可以使用线的弧长或归一化弧长作为vtkXYPlotActor的输入来生成X值。
另外一个复合的Actor类是vtkCubeAxesAxtor2D。该类可以用于标记相机所观察的空间位置,如图4-11所示。vtkCubeAxesActor2D可以沿着输入数据的包围盒的三个正交边显示X-Y-Z坐标值。当相机放缩时,坐标轴上的坐标值会自适应相机视口的变化而更新。用户可以控制显示的坐标值所用的字体属性以及字体大小等。字体大小可通过方法SetFontFactor()设置。下面的程序演示了这个类的用法(摘自VTK/Examples/Annotation/Tcl/cubeAxes.tcl)。
vtkTextProperty tprop
tprop SetColor 1 1 1
tprop ShadowOn
vtkCubeAxesActor2D axes
axes SetInput [normals GetOutput]
axes SetCamera [ren1 GetActiveCamera]
axes SetLabelFormat "%6.4g"
axes SetFlyModeToOuterEdges
axes SetFontFactor 0.8
axes SetAxisTitleTextProperty tprop
axes SetAxisLabelTextProperty tprop
图4-11vtkCubeAxesActor2D类的使用。左图中立方体边框的外边缘用于绘制坐标轴,右图将坐标轴放置在距离相机最近的顶点位置上。
注意绘制坐标轴时有两种模式,缺省模式是SetFlyModeToOuterEdges(),即绘制在包围盒的边框外边缘;另一种模式是SetFlyModeToClosestTriad(),把坐标轴放置在距离相机最近的顶点位置上。
在某些应用程序中可能需要根据底层的数据显示某些数值。vtkLabeledDataMapper就可以用于标记数据集里的点,包括标量、向量、张量、法向量、纹理坐标、域数据(Field Data)以及数据集里点的ID值。文本标记信息放置于所渲染图像的层叠平面上,如图4-12所示。该图是通过运行VTK/Examples/Annotation/Tcl/labeledMesh.tcl例子生成的,本节后面有该例子的部分代码。在这个例子里,用到了三个新类来标记球体的单元和点的ID值,分别是:vtkCellCenters、vtkIdFilter和vtkSelectVisiblePoints。其中vtkCellCenters用于在单元的中心位置生成点,vtkIdFilter则是根据单元和点的ID生成标量值或域数据,也就是说,点的属性数据标量值或域数据是从点的ID值生成的,单元的属性数据标量值或域数据则是根据单元的ID值生成的,vtkSelectVisiblePoints用于选择当前可见的点。另外vtkSelectVisiblePoints还可以在DISPLAY坐标系统下定义一个“窗口”来显示要标记的点的数值,并忽略窗口外的点使其不可见。
图4-12 在一个矩形窗口中标记其所对应的球体下的点和单元的ID值
#Create a sphere and its associated mapper and actor.
vtkSphereSource sphere
vtkPolyDataMapper sphereMapper
sphereMapper SetInputConnection [sphereGetOutputPort]
sphereMapper GlobalImmediateModeRenderingOn
vtkActors phereActor
sphereActor SetMapper sphereMapper
#Generate data arrays containing point and cell ids
vtkIdFilter ids
ids SetInputConnection [sphere GetOutputPort]
ids PointIdsOn
ids CellIdsOn
ids FieldDataOn
#Create the renderer here because vtkSelectVisiblePoints needs it.
vtkRenderer ren1
#Create labels for points
vtkSelectVisiblePoints visPts
visPts SetInputConnection [idsGetOutputPort]
visPts SetRenderer ren1
visPts SelectionWindowOn
visPts SetSelection $xmin [expr $xmin +$xLength] \
$ymin [expr $ymin + $yLength]
#Create the mapper to display the point ids. Specify the
#format to use for the labels. Alsocreate the associated actor.
vtkLabeledDataMapper ldm
ldm SetInputConnection [visPtsGetOutputPort]
# ldm SetLabelFormat "%g"
ldm SetLabelModeToLabelFieldData
vtkActor2DpointLabels
pointLabels SetMapper ldm
#Create labels for cells
vtkCellCenters cc
cc SetInputConnection [ids GetOutputPort]
vtkSelectVisiblePoints visCells
visCells SetInputConnection [ccGetOutputPort]
visCells SetRenderer ren1
visCells SelectionWindowOn
visCells SetSelection $xmin [expr $xmin +$xLength] \
$ymin [expr $ymin + $yLength]
#Create the mapper to display the cell ids. Specify the
#format to use for the labels. Alsocreate the associated actor.
vtkLabeledDataMapper cellMapper
cellMapper SetInputConnection [visCells GetOutputPort]
# cellMapper SetLabelFormat "%g"
cellMapper SetLabelModeToLabelFieldData
[cellMapper GetLabelTextProperty] SetColor0 1 0
vtkActor2D cellLabels
cellLabels SetMapper cellMapper
#Create the RenderWindow and RenderWindowInteractor
#
vtkRenderWindow renWin
renWin AddRenderer ren1
vtkRenderWindowInteractor iren
iren SetRenderWindow renWin
#Add the actors to the renderer; set the background and size;
#render
ren1AddActor sphereActor
ren1AddActor2D rectActor
ren1AddActor2D pointLabels
ren1AddActor2D cellLabels
ren1SetBackground 1 1 1
renWinSetSize 500 500
renWinRender