1package require vtk 2package require vtkinteraction 3 4# This example demonstrates how to use the vtkImagePlaneWidget 5# and a vtkSplineWidger to do profile probing of a 3D image 6# dataset. The use of vtkAnnotatedCubeActor, vtkAxesActor and 7# vtkOrientationMarkerWidget is also demostrated. 8# 9# GUI controls are provided as follows: 10# a) x,y,z buttons set the widgets to orthonormal 11# positioning, set the horizontal slider to move the 12# widgets along their common plane normal, and set the 13# camera to face the widgets 14# b) right clicking on x,y,z buttons pops up a menu to set 15# the widget's reslice interpolation mode 16# c) when in axes aligned, orthogonal orientation, the slider 17# will move the widget by slice index within the appropriate range 18# 19 20# Start by loading some data. 21# 22vtkVolume16Reader v16 23 v16 SetDataDimensions 64 64 24 v16 SetDataByteOrderToLittleEndian 25 v16 SetImageRange 1 93 26 v16 SetDataSpacing 3.2 3.2 1.5 27 v16 SetFilePrefix "$VTK_DATA_ROOT/Data/headsq/quarter" 28 v16 Update 29 30scan [[v16 GetExecutive] GetWholeExtent [v16 GetOutputInformation 0]] "%d %d %d %d %d %d" \ 31 xMin xMax yMin yMax zMin zMax 32 33set spacing [[v16 GetOutput] GetSpacing] 34set sx [lindex $spacing 0] 35set sy [lindex $spacing 1] 36set sz [lindex $spacing 2] 37 38set origin [[v16 GetOutput] GetOrigin] 39set ox [lindex $origin 0] 40set oy [lindex $origin 1] 41set oz [lindex $origin 2] 42 43# Create an outline of the 3D image data bounds. 44# 45vtkOutlineFilter outline 46 outline SetInputConnection [ v16 GetOutputPort ] 47 48vtkPolyDataMapper outlineMapper 49 outlineMapper SetInputConnection [ outline GetOutputPort ] 50 51vtkActor outlineActor 52 outlineActor SetMapper outlineMapper 53 54# Set up two renderers in one render window: one for the 55# vtkImagePlaneWidget, vtkSplineWidget, and outline, and 56# one for the profile plot. 57# 58vtkRenderer ren1 59 ren1 SetBackground 0.4 0.4 0.5 60vtkRenderer ren2 61 ren2 SetBackground 0.8 0.8 0.8 62 63vtkRenderWindow renWin 64 renWin AddRenderer ren1 65 renWin AddRenderer ren2 66 renWin SetSize 800 400 67 68ren1 SetViewport 0 0 0.5 1 69ren2 SetViewport 0.5 0 1 1 70 71# Create a vtkImagePlaneWidget to slice through the data. 72# 73vtkImagePlaneWidget ipw 74 ipw DisplayTextOn 75 ipw TextureInterpolateOff 76 ipw UserControlledLookupTableOff 77 ipw SetInputConnection [ v16 GetOutputPort ] 78 ipw SetResliceInterpolateToNearestNeighbour 79 ipw KeyPressActivationOff 80 [ ipw GetPlaneProperty ] SetColor 1 0 0 81 set xmode [ ipw GetResliceInterpolate ] 82 set ymode [ ipw GetResliceInterpolate ] 83 set zmode [ ipw GetResliceInterpolate ] 84 ipw SetPlaneOrientationToXAxes 85 ipw SetSliceIndex 32 86 ipw AddObserver InteractionEvent UpdateIPW 87 88# Create a vtkSplineWidget to interactively probe the data. 89# 90vtkSplineWidget spline 91 spline SetInputConnection [ v16 GetOutputPort ] 92 spline PlaceWidget 93 spline SetPriority 1.0 94 spline KeyPressActivationOff 95 spline ProjectToPlaneOn 96 spline SetProjectionNormal 0 97 spline SetProjectionPosition 102.4 98 spline SetNumberOfHandles 5 99 spline SetResolution 500 100 spline AddObserver InteractionEvent UpdateSW 101 102# A vtkPolyData will be continuously updated from the spline 103# during interaction. 104# 105vtkPolyData poly 106 spline GetPolyData poly 107 108# The filter to probe the image data. 109# 110vtkProbeFilter probe 111 probe SetInputData poly 112 probe SetSourceConnection [ v16 GetOutputPort ] 113 114# The plot of the profile data. 115# 116vtkXYPlotActor profile 117 profile AddDataSetInputConnection [ probe GetOutputPort ] 118 [ profile GetPositionCoordinate ] SetValue 0.05 0.05 0 119 [ profile GetPosition2Coordinate ] SetValue 0.95 0.95 0 120 profile SetXValuesToNormalizedArcLength 121 profile SetNumberOfXLabels 6 122 profile SetTitle "Profile Data " 123 profile SetXTitle "s" 124 profile SetYTitle "I(s)" 125 profile SetXRange 0 1 126 set range [[v16 GetOutput] GetScalarRange] 127 profile SetYRange [lindex $range 0] [lindex $range 1] 128 [ profile GetProperty ] SetColor 0 0 0 129 [ profile GetProperty ] SetLineWidth 2 130 profile SetLabelFormat "%g" 131 [ profile GetTitleTextProperty ] SetColor 0.02 0.06 0.62 132 [ profile GetTitleTextProperty ] SetFontFamilyToArial 133 profile SetAxisTitleTextProperty [ profile GetTitleTextProperty ] 134 profile SetAxisLabelTextProperty [ profile GetTitleTextProperty ] 135 profile SetTitleTextProperty [ profile GetTitleTextProperty ] 136 137# Create a composite orientation marker using 138# vtkAnnotatedCubeActor and vtkAxesActor. 139# 140vtkAnnotatedCubeActor cube 141 cube SetXPlusFaceText "R" 142 cube SetXMinusFaceText "L" 143 cube SetYPlusFaceText "A" 144 cube SetYMinusFaceText "P" 145 cube SetZPlusFaceText "I" 146 cube SetZMinusFaceText "S" 147 cube SetXFaceTextRotation 180 148 cube SetYFaceTextRotation 180 149 cube SetZFaceTextRotation -90 150 cube SetFaceTextScale 0.65 151 set property [ cube GetCubeProperty ] 152 $property SetColor 0.5 1 1 153 set property [ cube GetTextEdgesProperty ] 154 $property SetLineWidth 1 155 $property SetDiffuse 0 156 $property SetAmbient 1 157 $property SetColor 0.18 0.28 0.23 158 set property [ cube GetXPlusFaceProperty ] 159 $property SetColor 0 0 1 160 $property SetInterpolationToFlat 161 set property [ cube GetXMinusFaceProperty ] 162 $property SetColor 0 0 1 163 $property SetInterpolationToFlat 164 set property [ cube GetYPlusFaceProperty ] 165 $property SetColor 0 1 0 166 $property SetInterpolationToFlat 167 set property [ cube GetYMinusFaceProperty ] 168 $property SetColor 0 1 0 169 $property SetInterpolationToFlat 170 set property [ cube GetZPlusFaceProperty ] 171 $property SetColor 1 0 0 172 $property SetInterpolationToFlat 173 set property [ cube GetZMinusFaceProperty ] 174 $property SetColor 1 0 0 175 $property SetInterpolationToFlat 176 177vtkAxesActor axes 178 axes SetShaftTypeToCylinder 179 axes SetXAxisLabelText "x" 180 axes SetYAxisLabelText "y" 181 axes SetZAxisLabelText "z" 182 axes SetTotalLength 1.5 1.5 1.5 183 vtkTextProperty tprop 184 tprop ItalicOn 185 tprop ShadowOn 186 tprop SetFontFamilyToTimes 187 [ axes GetXAxisCaptionActor2D ] SetCaptionTextProperty tprop 188 vtkTextProperty tprop2 189 tprop2 ShallowCopy tprop 190 [ axes GetYAxisCaptionActor2D ] SetCaptionTextProperty tprop2 191 vtkTextProperty tprop3 192 tprop3 ShallowCopy tprop 193 [ axes GetZAxisCaptionActor2D ] SetCaptionTextProperty tprop3 194 195# Combine the two actors into one with vtkPropAssembly ... 196# 197 vtkPropAssembly assembly 198 assembly AddPart axes 199 assembly AddPart cube 200 201# Add the composite marker to the widget. The widget 202# should be kept in non-interactive mode and the aspect 203# ratio of the render window taken into account explicitly, 204# since the widget currently does not take this into 205# account in a multi-renderer environment. 206# 207 vtkOrientationMarkerWidget marker 208 marker SetOutlineColor 0.93 0.57 0.13 209 marker SetOrientationMarker assembly 210 marker SetViewport 0.0 0.0 0.15 0.3 211# Add the actors. 212# 213 ren1 AddActor outlineActor 214 ren2 AddActor2D profile 215 216# Prevent the tk window from showing up then start the event loop. 217 wm withdraw . 218 219# Build a tcl GUI. 220# 221 222toplevel .top 223wm title .top "Probe With vtkSplineWidget Example" 224wm protocol .top WM_DELETE_WINDOW ::vtk::cb_exit 225 226set popm [menu .top.mm -tearoff 0] 227set interpmode 0 228$popm add radiobutton -label "nearest" -variable interpmode -value 0 \ 229 -command SetInterpolation 230$popm add radiobutton -label "linear" -variable interpmode -value 1 \ 231 -command SetInterpolation 232$popm add radiobutton -label "cubic" -variable interpmode -value 2 \ 233 -command SetInterpolation 234 235set display_frame [frame .top.f1] 236 237set ctrl_buttons [frame .top.btns] 238 239pack $display_frame $ctrl_buttons \ 240 -side top -anchor n \ 241 -fill both -expand f 242 243set quit_button [button $ctrl_buttons.btn1 \ 244 -text "Quit" \ 245 -command ::vtk::cb_exit] 246 247set x_button [button $ctrl_buttons.btn2 \ 248 -text "x" \ 249 -command AlignXaxis] 250 251set y_button [button $ctrl_buttons.btn3 \ 252 -text "y" \ 253 -command AlignYaxis] 254 255set z_button [button $ctrl_buttons.btn4 \ 256 -text "z" \ 257 -command AlignZaxis] 258 259set last_btn -1 260bind $x_button <Button-3> "set last_btn 0; ConfigMenu; $popm post %X %Y" 261bind $y_button <Button-3> "set last_btn 1; ConfigMenu; $popm post %X %Y" 262bind $z_button <Button-3> "set last_btn 2; ConfigMenu; $popm post %X %Y" 263 264# Share the popup menu among buttons, keeping 265# track of associated plane's interpolation mode 266# 267proc ConfigMenu { } { 268 global last_btn popm interpmode xmode ymode zmode 269 if { $last_btn == 0 } { 270 set interpmode $xmode 271 } elseif { $last_btn == 1 } { 272 set interpmode $ymode 273 } else { 274 set interpmode $zmode 275 } 276 $popm entryconfigure $last_btn -variable interpmode 277} 278 279pack $quit_button $x_button $y_button $z_button \ 280 -side left \ 281 -expand t -fill both 282 283# Create the render widget 284# 285set renderer_frame [frame $display_frame.rFm] 286 287pack $renderer_frame \ 288 -padx 3 -pady 3 \ 289 -side left -anchor n \ 290 -fill both -expand f 291 292set render_widget [vtkTkRenderWidget $renderer_frame.r \ 293 -width 800 \ 294 -height 400 \ 295 -rw renWin] 296 297pack $render_widget $display_frame \ 298 -side top -anchor n \ 299 -fill both -expand f 300 301# Add a slice scale to browse the current slice stack 302# 303 304set slice_number [ipw GetSliceIndex] 305 306scale .top.slice \ 307 -from $xMin \ 308 -to $xMax \ 309 -orient horizontal \ 310 -command SetSlice \ 311 -variable slice_number \ 312 -label "Slice" 313 314pack .top.slice \ 315 -fill x -expand f 316 317proc SetSlice {slice} { 318 ipw SetSliceIndex $slice 319 UpdateIPW 320 renWin Render 321} 322 323::vtk::bind_tk_render_widget $render_widget 324# Set the interactor for the widgets 325# 326set iact [[$render_widget GetRenderWindow] GetInteractor] 327vtkInteractorStyleTrackballCamera style 328$iact SetInteractorStyle style 329 330ipw SetInteractor $iact 331ipw On 332 333spline SetInteractor $iact 334spline SetPlaneSource [ ipw GetPolyDataAlgorithm ] 335spline SetProjectionNormal 3 336spline On 337 338# The marker must be linked to the interactor after the $render_widget is mapped 339 340bind $render_widget <Map> [string map "%IA %iact" { 341 marker SetInteractor $iact 342 marker SetEnabled 1 343 marker InteractiveOff 344}] 345 346# Create an initial interesting view 347# 348set cam1 [ren1 GetActiveCamera] 349$cam1 Elevation 110 350$cam1 SetViewUp 0 0 -1 351$cam1 Azimuth 45 352ren1 ResetCamera 353 354# Render it 355# 356$render_widget Render 357 358# Supporting procedures 359# 360 361# Align the camera so that it faces the desired widget 362# 363proc AlignCamera { } { 364 global ox oy oz sx sy sz xMax xMin yMax yMin zMax zMin slice_number 365 set cx [expr $ox + (0.5*($xMax - $xMin))*$sx] 366 set cy [expr $oy + (0.5*($yMax - $yMin))*$sy] 367 set cz [expr $oy + (0.5*($zMax - $zMin))*$sz] 368 set vx 0 369 set vy 0 370 set vz 0 371 set nx 0 372 set ny 0 373 set nz 0 374 set iaxis [ipw GetPlaneOrientation] 375 if { $iaxis == 0 } { 376 set vz -1 377 set nx [expr $ox + $xMax*$sx] 378 set cx [expr $ox + $slice_number*$sx] 379 } elseif { $iaxis == 1 } { 380 set vz -1 381 set ny [expr $oy + $yMax*$sy] 382 set cy [expr $oy + $slice_number*$sy] 383 } else { 384 set vy 1 385 set nz [expr $oz + $zMax*$sz] 386 set cz [expr $oz + $slice_number*$sz] 387 } 388 set px [expr $cx + $nx*2] 389 set py [expr $cy + $ny*2] 390 set pz [expr $cz + $nz*3] 391 392 set camera [ ren1 GetActiveCamera ] 393 $camera SetViewUp $vx $vy $vz 394 $camera SetFocalPoint $cx $cy $cz 395 $camera SetPosition $px $py $pz 396 $camera OrthogonalizeViewUp 397 ren1 ResetCamera 398 renWin Render 399} 400 401# Align the widget back into orthonormal position, 402# set the slider to reflect the widget's position, 403# call AlignCamera to set the camera facing the widget 404# 405proc AlignXaxis { } { 406 global xMax xMin slice_number interpmode xmode 407 set ori [ ipw GetPlaneOrientation ] 408 if { $ori != 0 } { 409 ipw SetPlaneOrientationToXAxes 410 set slice_number [expr ($xMax - $xMin)/2] 411 ipw SetSliceIndex $slice_number 412 } else { 413 set slice_number [ipw GetSliceIndex] 414 } 415 .top.slice config -from $xMin -to $xMax 416 .top.slice set $slice_number 417 UpdateSplinePosition 418 AlignCamera 419 set interpmode $xmode 420 SetInterpolation 421} 422 423proc AlignYaxis { } { 424 global yMin yMax slice_number interpmode ymode 425 426 set po [ ipw GetPlaneOrientation ] 427 set ori [ ipw GetPlaneOrientation ] 428 if { $ori != 1 } { 429 ipw SetPlaneOrientationToYAxes 430 set slice_number [expr ($yMax - $yMin)/2] 431 ipw SetSliceIndex $slice_number 432 } else { 433 set slice_number [ipw GetSliceIndex] 434 } 435 .top.slice config -from $yMin -to $yMax 436 .top.slice set $slice_number 437 UpdateSplinePosition 438 AlignCamera 439 set interpmode $ymode 440 SetInterpolation 441} 442 443proc AlignZaxis { } { 444 global zMin zMax slice_number interpmode zmode 445 set ori [ ipw GetPlaneOrientation ] 446 if { $ori != 2 } { 447 ipw SetPlaneOrientationToZAxes 448 set slice_number [expr ($zMax - $zMin)/2] 449 ipw SetSliceIndex $slice_number 450 } else { 451 set slice_number [ipw GetSliceIndex] 452 } 453 .top.slice config -from $zMin -to $zMax 454 .top.slice set $slice_number 455 UpdateSplinePosition 456 AlignCamera 457 set interpmode $zmode 458 SetInterpolation 459} 460 461proc UpdateSplinePosition { } { 462 set ori [ ipw GetPlaneOrientation ] 463 spline ProjectToPlaneOff 464 spline PlaceWidget 465 spline ProjectToPlaneOn 466 spline SetProjectionNormal $ori 467 spline SetProjectionNormal 3 468 UpdateIPW 469} 470 471# Set the vtkImagePlaneWidget's reslice interpolation mode 472# to the corresponding popup menu choice and store 473# it for subsequent orientation changes. 474# 475proc SetInterpolation { } { 476 global interpmode xmode ymode zmode 477 if { $interpmode == 0 } { 478 ipw TextureInterpolateOff 479 } else { 480 ipw TextureInterpolateOn 481 } 482 ipw SetResliceInterpolate $interpmode 483 set ori [ipw GetPlaneOrientation] 484 if { $ori == 0 } { 485 set xmode $interpmode 486 } elseif { $ori == 1 } { 487 set ymode $interpmode 488 } else { 489 set zmode $interpmode 490 } 491 renWin Render 492} 493 494# Procedure to update the placement of the vtkSplineWidget on the 495# plane defined by the vtkImagePlaneWidget. 496# 497proc UpdateIPW { } { 498 set ori [ ipw GetPlaneOrientation ] 499 500 if { $ori == 3 } { 501 spline SetProjectionPosition 0 502 } else { 503 set pos [ ipw GetSlicePosition ] 504 spline SetProjectionPosition $pos 505 } 506 507 UpdateSW 508} 509 510# Procedure to update the spline geometry fed into the probe filter. 511# 512proc UpdateSW { } { 513 spline GetPolyData poly 514} 515 516