You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
373 lines
9.5 KiB
373 lines
9.5 KiB
package require vtk
|
|
package require vtkinteraction
|
|
|
|
# This example demonstrates how to use the vtkImagePlaneWidget
|
|
# to probe a 3D image dataset with three orthogonal planes.
|
|
# Buttons are provided to:
|
|
# a) capture the render window display to a tiff file
|
|
# b) x,y,z buttons reset the widget to orthonormal
|
|
# positioning, set the horizontal slider to move the
|
|
# associated widget along its normal, and set the
|
|
# camera to face the widget
|
|
# c) right clicking on x,y,z buttons pops up a menu to set
|
|
# the associated widget's reslice interpolation mode
|
|
#
|
|
|
|
# Start by loading some data.
|
|
#
|
|
vtkVolume16Reader v16
|
|
v16 SetDataDimensions 64 64
|
|
v16 SetDataByteOrderToLittleEndian
|
|
v16 SetFilePrefix "$VTK_DATA_ROOT/Data/headsq/quarter"
|
|
v16 SetImageRange 1 93
|
|
v16 SetDataSpacing 3.2 3.2 1.5
|
|
v16 Update
|
|
|
|
scan [[v16 GetOutput] GetWholeExtent] "%d %d %d %d %d %d" \
|
|
xMin xMax yMin yMax zMin zMax
|
|
|
|
set spacing [[v16 GetOutput] GetSpacing]
|
|
set sx [lindex $spacing 0]
|
|
set sy [lindex $spacing 1]
|
|
set sz [lindex $spacing 2]
|
|
|
|
set origin [[v16 GetOutput] GetOrigin]
|
|
set ox [lindex $origin 0]
|
|
set oy [lindex $origin 1]
|
|
set oz [lindex $origin 2]
|
|
|
|
# An outline is shown for context.
|
|
#
|
|
vtkOutlineFilter outline
|
|
outline SetInputConnection [v16 GetOutputPort]
|
|
|
|
vtkPolyDataMapper outlineMapper
|
|
outlineMapper SetInputConnection [outline GetOutputPort]
|
|
|
|
vtkActor outlineActor
|
|
outlineActor SetMapper outlineMapper
|
|
|
|
# The shared picker enables us to use 3 planes at one time
|
|
# and gets the picking order right
|
|
#
|
|
vtkCellPicker picker
|
|
picker SetTolerance 0.005
|
|
|
|
# The 3 image plane widgets are used to probe the dataset.
|
|
#
|
|
vtkImagePlaneWidget planeWidgetX
|
|
planeWidgetX DisplayTextOn
|
|
planeWidgetX SetInput [v16 GetOutput]
|
|
planeWidgetX SetPlaneOrientationToXAxes
|
|
planeWidgetX SetSliceIndex 32
|
|
planeWidgetX SetPicker picker
|
|
planeWidgetX SetKeyPressActivationValue "x"
|
|
set prop1 [planeWidgetX GetPlaneProperty]
|
|
$prop1 SetColor 1 0 0
|
|
|
|
vtkImagePlaneWidget planeWidgetY
|
|
planeWidgetY DisplayTextOn
|
|
planeWidgetY SetInput [v16 GetOutput]
|
|
planeWidgetY SetPlaneOrientationToYAxes
|
|
planeWidgetY SetSliceIndex 32
|
|
planeWidgetY SetPicker picker
|
|
planeWidgetY SetKeyPressActivationValue "y"
|
|
set prop2 [planeWidgetY GetPlaneProperty]
|
|
$prop2 SetColor 1 1 0
|
|
planeWidgetY SetLookupTable [planeWidgetX GetLookupTable]
|
|
|
|
# for the z-slice, turn off texture interpolation:
|
|
# interpolation is now nearest neighbour, to demonstrate
|
|
# cross-hair cursor snapping to pixel centers
|
|
#
|
|
vtkImagePlaneWidget planeWidgetZ
|
|
planeWidgetZ DisplayTextOn
|
|
planeWidgetZ SetInput [v16 GetOutput]
|
|
planeWidgetZ SetPlaneOrientationToZAxes
|
|
planeWidgetZ SetSliceIndex 46
|
|
planeWidgetZ SetPicker picker
|
|
planeWidgetZ SetKeyPressActivationValue "z"
|
|
set prop3 [planeWidgetZ GetPlaneProperty]
|
|
$prop3 SetColor 0 0 1
|
|
planeWidgetZ SetLookupTable [planeWidgetX GetLookupTable]
|
|
|
|
set current_widget planeWidgetZ
|
|
set mode_widget planeWidgetZ
|
|
|
|
# Create the RenderWindow and Renderer
|
|
#
|
|
vtkRenderer ren1
|
|
vtkRenderWindow renWin
|
|
renWin AddRenderer ren1
|
|
|
|
# Add the outline actor to the renderer, set the background color and size
|
|
#
|
|
ren1 AddActor outlineActor
|
|
renWin SetSize 600 600
|
|
ren1 SetBackground 0.1 0.1 0.2
|
|
|
|
|
|
# Create the GUI
|
|
#
|
|
wm withdraw .
|
|
toplevel .top
|
|
wm title .top "vtkImagePlaneWidget Example"
|
|
wm protocol .top WM_DELETE_WINDOW ::vtk::cb_exit
|
|
|
|
set popm [menu .top.mm -tearoff 0]
|
|
set mode 1
|
|
$popm add radiobutton -label "nearest" -variable mode -value 0 \
|
|
-command SetInterpolation
|
|
$popm add radiobutton -label "linear" -variable mode -value 1 \
|
|
-command SetInterpolation
|
|
$popm add radiobutton -label "cubic" -variable mode -value 2 \
|
|
-command SetInterpolation
|
|
|
|
set display_frame [frame .top.f1]
|
|
|
|
set ctrl_buttons [frame .top.btns]
|
|
|
|
pack $display_frame $ctrl_buttons \
|
|
-side top -anchor n \
|
|
-fill both -expand f
|
|
|
|
set quit_button [button $ctrl_buttons.btn1 \
|
|
-text "Quit" \
|
|
-command ::vtk::cb_exit]
|
|
|
|
set capture_button [button $ctrl_buttons.btn2 \
|
|
-text "Tif" \
|
|
-command CaptureImage]
|
|
|
|
set x_button [button $ctrl_buttons.btn3 \
|
|
-text "x" \
|
|
-command AlignXaxis]
|
|
|
|
set y_button [button $ctrl_buttons.btn4 \
|
|
-text "y" \
|
|
-command AlignYaxis]
|
|
|
|
set z_button [button $ctrl_buttons.btn5 \
|
|
-text "z" \
|
|
-command AlignZaxis]
|
|
|
|
set last_btn -1
|
|
bind $x_button <Button-3> "set last_btn 0; configMenu; $popm post %X %Y"
|
|
bind $y_button <Button-3> "set last_btn 1; configMenu; $popm post %X %Y"
|
|
bind $z_button <Button-3> "set last_btn 2; configMenu; $popm post %X %Y"
|
|
|
|
# Share the popup menu among buttons, keeping
|
|
# track of associated widget's interpolation mode
|
|
#
|
|
proc configMenu { } {
|
|
global last_btn popm mode mode_widget
|
|
if { $last_btn == 0 } {
|
|
set mode_widget planeWidgetX
|
|
} elseif { $last_btn == 1 } {
|
|
set mode_widget planeWidgetY
|
|
} else {
|
|
set mode_widget planeWidgetZ
|
|
}
|
|
set mode [$mode_widget GetResliceInterpolate]
|
|
$popm entryconfigure $last_btn -variable mode
|
|
}
|
|
|
|
pack $quit_button $capture_button $x_button $y_button $z_button \
|
|
-side left \
|
|
-expand t -fill both
|
|
|
|
# Create the render widget
|
|
#
|
|
set renderer_frame [frame $display_frame.rFm]
|
|
|
|
pack $renderer_frame \
|
|
-padx 3 -pady 3 \
|
|
-side left -anchor n \
|
|
-fill both -expand f
|
|
|
|
set render_widget [vtkTkRenderWidget $renderer_frame.r \
|
|
-width 600 \
|
|
-height 600 \
|
|
-rw renWin]
|
|
|
|
pack $render_widget $display_frame \
|
|
-side top -anchor n \
|
|
-fill both -expand f
|
|
|
|
# Add a slice scale to browse the current slice stack
|
|
#
|
|
|
|
set slice_number [$current_widget GetSliceIndex]
|
|
|
|
scale .top.slice \
|
|
-from $zMin \
|
|
-to $zMax \
|
|
-orient horizontal \
|
|
-command SetSlice \
|
|
-variable slice_number \
|
|
-label "Slice"
|
|
|
|
pack .top.slice \
|
|
-fill x -expand f
|
|
|
|
proc SetSlice {slice} {
|
|
global current_widget
|
|
$current_widget SetSliceIndex $slice
|
|
ren1 ResetCameraClippingRange
|
|
renWin Render
|
|
}
|
|
|
|
::vtk::bind_tk_render_widget $render_widget
|
|
# Set the interactor for the widgets
|
|
#
|
|
set iact [[$render_widget GetRenderWindow] GetInteractor]
|
|
planeWidgetX SetInteractor $iact
|
|
planeWidgetX On
|
|
planeWidgetY SetInteractor $iact
|
|
planeWidgetY On
|
|
planeWidgetZ SetInteractor $iact
|
|
planeWidgetZ On
|
|
|
|
# Create an initial interesting view
|
|
#
|
|
set cam1 [ren1 GetActiveCamera]
|
|
$cam1 Elevation 110
|
|
$cam1 SetViewUp 0 0 -1
|
|
$cam1 Azimuth 45
|
|
ren1 ResetCameraClippingRange
|
|
|
|
# Render it
|
|
#
|
|
$render_widget Render
|
|
|
|
# Supporting procedures
|
|
#
|
|
|
|
# Align the camera so that it faces the desired widget
|
|
#
|
|
proc AlignCamera { } {
|
|
global ox oy oz sx sy sz xMax xMin yMax yMin zMax zMin slice_number
|
|
global current_widget
|
|
set cx [expr $ox + (0.5*($xMax - $xMin))*$sx]
|
|
set cy [expr $oy + (0.5*($yMax - $yMin))*$sy]
|
|
set cz [expr $oy + (0.5*($zMax - $zMin))*$sz]
|
|
set vx 0
|
|
set vy 0
|
|
set vz 0
|
|
set nx 0
|
|
set ny 0
|
|
set nz 0
|
|
set iaxis [$current_widget GetPlaneOrientation]
|
|
if { $iaxis == 0 } {
|
|
set vz -1
|
|
set nx [expr $ox + $xMax*$sx]
|
|
set cx [expr $ox + $slice_number*$sx]
|
|
} elseif { $iaxis == 1 } {
|
|
set vz -1
|
|
set ny [expr $oy + $yMax*$sy]
|
|
set cy [expr $oy + $slice_number*$sy]
|
|
} else {
|
|
set vy 1
|
|
set nz [expr $oz + $zMax*$sz]
|
|
set cz [expr $oz + $slice_number*$sz]
|
|
}
|
|
set px [expr $cx + $nx*2]
|
|
set py [expr $cy + $ny*2]
|
|
set pz [expr $cz + $nz*3]
|
|
|
|
set camera [ ren1 GetActiveCamera ]
|
|
$camera SetViewUp $vx $vy $vz
|
|
$camera SetFocalPoint $cx $cy $cz
|
|
$camera SetPosition $px $py $pz
|
|
$camera OrthogonalizeViewUp
|
|
ren1 ResetCameraClippingRange
|
|
renWin Render
|
|
}
|
|
|
|
# Capture the display and place in a tiff
|
|
#
|
|
proc CaptureImage { } {
|
|
vtkWindowToImageFilter w2i
|
|
vtkTIFFWriter writer
|
|
|
|
w2i SetInput renWin
|
|
w2i Update
|
|
writer SetInputConnection [w2i GetOutputPort]
|
|
writer SetFileName image.tif
|
|
renWin Render
|
|
writer Write
|
|
|
|
writer Delete
|
|
w2i Delete
|
|
}
|
|
|
|
# Align the widget back into orthonormal position,
|
|
# set the slider to reflect the widget's position,
|
|
# call AlignCamera to set the camera facing the widget
|
|
#
|
|
proc AlignXaxis { } {
|
|
global xMax xMin current_widget slice_number
|
|
set po [ planeWidgetX GetPlaneOrientation ]
|
|
if { $po == 3 } {
|
|
planeWidgetX SetPlaneOrientationToXAxes
|
|
set slice_number [expr ($xMax - $xMin)/2]
|
|
planeWidgetX SetSliceIndex $slice_number
|
|
} else {
|
|
set slice_number [planeWidgetX GetSliceIndex]
|
|
}
|
|
set current_widget planeWidgetX
|
|
.top.slice config -from $xMin -to $xMax
|
|
.top.slice set $slice_number
|
|
AlignCamera
|
|
}
|
|
|
|
proc AlignYaxis { } {
|
|
global yMin yMax current_widget slice_number
|
|
set po [ planeWidgetY GetPlaneOrientation ]
|
|
if { $po == 3 } {
|
|
planeWidgetY SetPlaneOrientationToYAxes
|
|
set slice_number [expr ($yMax - $yMin)/2]
|
|
planeWidgetY SetSliceIndex $slice_number
|
|
} else {
|
|
set slice_number [planeWidgetY GetSliceIndex]
|
|
}
|
|
set current_widget planeWidgetY
|
|
.top.slice config -from $yMin -to $yMax
|
|
.top.slice set $slice_number
|
|
AlignCamera
|
|
}
|
|
|
|
proc AlignZaxis { } {
|
|
global zMin zMax current_widget slice_number
|
|
set po [ planeWidgetZ GetPlaneOrientation ]
|
|
if { $po == 3 } {
|
|
planeWidgetZ SetPlaneOrientationToZAxes
|
|
set slice_number [expr ($zMax - $zMin)/2]
|
|
planeWidgetZ SetSliceIndex $slice_number
|
|
} else {
|
|
set slice_number [planeWidgetZ GetSliceIndex]
|
|
}
|
|
set current_widget planeWidgetZ
|
|
.top.slice config -from $zMin -to $zMax
|
|
.top.slice set $slice_number
|
|
AlignCamera
|
|
}
|
|
|
|
# Set the widget's reslice interpolation mode
|
|
# to the corresponding popup menu choice
|
|
#
|
|
proc SetInterpolation { } {
|
|
global mode_widget mode
|
|
if { $mode == 0 } {
|
|
$mode_widget TextureInterpolateOff
|
|
} else {
|
|
$mode_widget TextureInterpolateOn
|
|
}
|
|
$mode_widget SetResliceInterpolate $mode
|
|
renWin Render
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|