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.
516 lines
14 KiB
516 lines
14 KiB
2 years ago
|
package require vtk
|
||
|
package require vtkinteraction
|
||
|
|
||
|
# This example demonstrates how to use the vtkImagePlaneWidget
|
||
|
# and a vtkSplineWidger to do profile probing of a 3D image
|
||
|
# dataset. The use of vtkAnnotatedCubeActor, vtkAxesActor and
|
||
|
# vtkOrientationMarkerWidget is also demostrated.
|
||
|
#
|
||
|
# GUI controls are provided as follows:
|
||
|
# a) x,y,z buttons set the widgets to orthonormal
|
||
|
# positioning, set the horizontal slider to move the
|
||
|
# widgets along their common plane normal, and set the
|
||
|
# camera to face the widgets
|
||
|
# b) right clicking on x,y,z buttons pops up a menu to set
|
||
|
# the widget's reslice interpolation mode
|
||
|
# c) when in axes aligned, orthogonal orientation, the slider
|
||
|
# will move the widget by slice index within the appropriate range
|
||
|
#
|
||
|
|
||
|
# Start by loading some data.
|
||
|
#
|
||
|
vtkVolume16Reader v16
|
||
|
v16 SetDataDimensions 64 64
|
||
|
v16 SetDataByteOrderToLittleEndian
|
||
|
v16 SetImageRange 1 93
|
||
|
v16 SetDataSpacing 3.2 3.2 1.5
|
||
|
v16 SetFilePrefix "$VTK_DATA_ROOT/Data/headsq/quarter"
|
||
|
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]
|
||
|
|
||
|
# Create an outline of the 3D image data bounds.
|
||
|
#
|
||
|
vtkOutlineFilter outline
|
||
|
outline SetInput [ v16 GetOutput ]
|
||
|
|
||
|
vtkPolyDataMapper outlineMapper
|
||
|
outlineMapper SetInput [ outline GetOutput ]
|
||
|
|
||
|
vtkActor outlineActor
|
||
|
outlineActor SetMapper outlineMapper
|
||
|
|
||
|
# Set up two renderers in one render window: one for the
|
||
|
# vtkImagePlaneWidget, vtkSplineWidget, and outline, and
|
||
|
# one for the profile plot.
|
||
|
#
|
||
|
vtkRenderer ren1
|
||
|
ren1 SetBackground 0.4 0.4 0.5
|
||
|
vtkRenderer ren2
|
||
|
ren2 SetBackground 0.8 0.8 0.8
|
||
|
|
||
|
vtkRenderWindow renWin
|
||
|
renWin AddRenderer ren1
|
||
|
renWin AddRenderer ren2
|
||
|
renWin SetSize 800 400
|
||
|
|
||
|
ren1 SetViewport 0 0 0.5 1
|
||
|
ren2 SetViewport 0.5 0 1 1
|
||
|
|
||
|
# Create a vtkImagePlaneWidget to slice through the data.
|
||
|
#
|
||
|
vtkImagePlaneWidget ipw
|
||
|
ipw DisplayTextOn
|
||
|
ipw TextureInterpolateOff
|
||
|
ipw UserControlledLookupTableOff
|
||
|
ipw SetInput [ v16 GetOutput ]
|
||
|
ipw SetResliceInterpolateToNearestNeighbour
|
||
|
ipw KeyPressActivationOff
|
||
|
[ ipw GetPlaneProperty ] SetColor 1 0 0
|
||
|
set xmode [ ipw GetResliceInterpolate ]
|
||
|
set ymode [ ipw GetResliceInterpolate ]
|
||
|
set zmode [ ipw GetResliceInterpolate ]
|
||
|
ipw SetPlaneOrientationToXAxes
|
||
|
ipw SetSliceIndex 32
|
||
|
ipw AddObserver InteractionEvent UpdateIPW
|
||
|
|
||
|
# Create a vtkSplineWidget to interactively probe the data.
|
||
|
#
|
||
|
vtkSplineWidget spline
|
||
|
spline SetInput [ v16 GetOutput ]
|
||
|
spline PlaceWidget
|
||
|
spline SetPriority 1.0
|
||
|
spline KeyPressActivationOff
|
||
|
spline ProjectToPlaneOn
|
||
|
spline SetProjectionNormal 0
|
||
|
spline SetProjectionPosition 102.4
|
||
|
spline SetNumberOfHandles 5
|
||
|
spline SetResolution 500
|
||
|
spline AddObserver InteractionEvent UpdateSW
|
||
|
|
||
|
# A vtkPolyData will be continuously updated from the spline
|
||
|
# during interaction.
|
||
|
#
|
||
|
vtkPolyData poly
|
||
|
spline GetPolyData poly
|
||
|
|
||
|
# The filter to probe the image data.
|
||
|
#
|
||
|
vtkProbeFilter probe
|
||
|
probe SetInput poly
|
||
|
probe SetSource [ v16 GetOutput ]
|
||
|
|
||
|
# The plot of the profile data.
|
||
|
#
|
||
|
vtkXYPlotActor profile
|
||
|
profile AddInput [ probe GetOutput ]
|
||
|
[ profile GetPositionCoordinate ] SetValue 0.05 0.05 0
|
||
|
[ profile GetPosition2Coordinate ] SetValue 0.95 0.95 0
|
||
|
profile SetXValuesToNormalizedArcLength
|
||
|
profile SetNumberOfXLabels 6
|
||
|
profile SetTitle "Profile Data "
|
||
|
profile SetXTitle "s"
|
||
|
profile SetYTitle "I(s)"
|
||
|
profile SetXRange 0 1
|
||
|
set range [[v16 GetOutput] GetScalarRange]
|
||
|
profile SetYRange [lindex $range 0] [lindex $range 1]
|
||
|
[ profile GetProperty ] SetColor 0 0 0
|
||
|
[ profile GetProperty ] SetLineWidth 2
|
||
|
profile SetLabelFormat "%g"
|
||
|
[ profile GetTitleTextProperty ] SetColor 0.02 0.06 0.62
|
||
|
[ profile GetTitleTextProperty ] SetFontFamilyToArial
|
||
|
profile SetAxisTitleTextProperty [ profile GetTitleTextProperty ]
|
||
|
profile SetAxisLabelTextProperty [ profile GetTitleTextProperty ]
|
||
|
profile SetTitleTextProperty [ profile GetTitleTextProperty ]
|
||
|
|
||
|
# Create a composite orientation marker using
|
||
|
# vtkAnnotatedCubeActor and vtkAxesActor.
|
||
|
#
|
||
|
vtkAnnotatedCubeActor cube
|
||
|
cube SetXPlusFaceText "R"
|
||
|
cube SetXMinusFaceText "L"
|
||
|
cube SetYPlusFaceText "A"
|
||
|
cube SetYMinusFaceText "P"
|
||
|
cube SetZPlusFaceText "I"
|
||
|
cube SetZMinusFaceText "S"
|
||
|
cube SetXFaceTextRotation 180
|
||
|
cube SetYFaceTextRotation 180
|
||
|
cube SetZFaceTextRotation -90
|
||
|
cube SetFaceTextScale 0.65
|
||
|
set property [ cube GetCubeProperty ]
|
||
|
$property SetColor 0.5 1 1
|
||
|
set property [ cube GetTextEdgesProperty ]
|
||
|
$property SetLineWidth 1
|
||
|
$property SetDiffuse 0
|
||
|
$property SetAmbient 1
|
||
|
$property SetColor 0.18 0.28 0.23
|
||
|
cube TextEdgesOn
|
||
|
cube CubeOn
|
||
|
cube FaceTextOn
|
||
|
set property [ cube GetXPlusFaceProperty ]
|
||
|
$property SetColor 0 0 1
|
||
|
$property SetInterpolationToFlat
|
||
|
set property [ cube GetXMinusFaceProperty ]
|
||
|
$property SetColor 0 0 1
|
||
|
$property SetInterpolationToFlat
|
||
|
set property [ cube GetYPlusFaceProperty ]
|
||
|
$property SetColor 0 1 0
|
||
|
$property SetInterpolationToFlat
|
||
|
set property [ cube GetYMinusFaceProperty ]
|
||
|
$property SetColor 0 1 0
|
||
|
$property SetInterpolationToFlat
|
||
|
set property [ cube GetZPlusFaceProperty ]
|
||
|
$property SetColor 1 0 0
|
||
|
$property SetInterpolationToFlat
|
||
|
set property [ cube GetZMinusFaceProperty ]
|
||
|
$property SetColor 1 0 0
|
||
|
$property SetInterpolationToFlat
|
||
|
|
||
|
vtkAxesActor axes
|
||
|
axes SetShaftTypeToCylinder
|
||
|
axes SetXAxisLabelText "x"
|
||
|
axes SetYAxisLabelText "y"
|
||
|
axes SetZAxisLabelText "z"
|
||
|
axes SetTotalLength 1.5 1.5 1.5
|
||
|
vtkTextProperty tprop
|
||
|
tprop ItalicOn
|
||
|
tprop ShadowOn
|
||
|
tprop SetFontFamilyToTimes
|
||
|
[ axes GetXAxisCaptionActor2D ] SetCaptionTextProperty tprop
|
||
|
vtkTextProperty tprop2
|
||
|
tprop2 ShallowCopy tprop
|
||
|
[ axes GetYAxisCaptionActor2D ] SetCaptionTextProperty tprop2
|
||
|
vtkTextProperty tprop3
|
||
|
tprop3 ShallowCopy tprop
|
||
|
[ axes GetZAxisCaptionActor2D ] SetCaptionTextProperty tprop3
|
||
|
|
||
|
# Combine the two actors into one with vtkPropAssembly ...
|
||
|
#
|
||
|
vtkPropAssembly assembly
|
||
|
assembly AddPart axes
|
||
|
assembly AddPart cube
|
||
|
|
||
|
# Add the composite marker to the widget. The widget
|
||
|
# should be kept in non-interactive mode and the aspect
|
||
|
# ratio of the render window taken into account explicitly,
|
||
|
# since the widget currently does not take this into
|
||
|
# account in a multi-renderer environment.
|
||
|
#
|
||
|
vtkOrientationMarkerWidget marker
|
||
|
marker SetOutlineColor 0.93 0.57 0.13
|
||
|
marker SetOrientationMarker assembly
|
||
|
marker SetViewport 0.0 0.0 0.15 0.3
|
||
|
|
||
|
# Add the actors.
|
||
|
#
|
||
|
ren1 AddActor outlineActor
|
||
|
ren2 AddActor2D profile
|
||
|
|
||
|
# Prevent the tk window from showing up then start the event loop.
|
||
|
wm withdraw .
|
||
|
|
||
|
# Build a tcl GUI.
|
||
|
#
|
||
|
|
||
|
toplevel .top
|
||
|
wm title .top "Probe With vtkSplineWidget Example"
|
||
|
wm protocol .top WM_DELETE_WINDOW ::vtk::cb_exit
|
||
|
|
||
|
set popm [menu .top.mm -tearoff 0]
|
||
|
set interpmode 0
|
||
|
$popm add radiobutton -label "nearest" -variable interpmode -value 0 \
|
||
|
-command SetInterpolation
|
||
|
$popm add radiobutton -label "linear" -variable interpmode -value 1 \
|
||
|
-command SetInterpolation
|
||
|
$popm add radiobutton -label "cubic" -variable interpmode -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 x_button [button $ctrl_buttons.btn2 \
|
||
|
-text "x" \
|
||
|
-command AlignXaxis]
|
||
|
|
||
|
set y_button [button $ctrl_buttons.btn3 \
|
||
|
-text "y" \
|
||
|
-command AlignYaxis]
|
||
|
|
||
|
set z_button [button $ctrl_buttons.btn4 \
|
||
|
-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 plane's interpolation mode
|
||
|
#
|
||
|
proc ConfigMenu { } {
|
||
|
global last_btn popm interpmode xmode ymode zmode
|
||
|
if { $last_btn == 0 } {
|
||
|
set interpmode $xmode
|
||
|
} elseif { $last_btn == 1 } {
|
||
|
set interpmode $ymode
|
||
|
} else {
|
||
|
set interpmode $zmode
|
||
|
}
|
||
|
$popm entryconfigure $last_btn -variable interpmode
|
||
|
}
|
||
|
|
||
|
pack $quit_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 800 \
|
||
|
-height 400 \
|
||
|
-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 [ipw GetSliceIndex]
|
||
|
|
||
|
scale .top.slice \
|
||
|
-from $xMin \
|
||
|
-to $xMax \
|
||
|
-orient horizontal \
|
||
|
-command SetSlice \
|
||
|
-variable slice_number \
|
||
|
-label "Slice"
|
||
|
|
||
|
pack .top.slice \
|
||
|
-fill x -expand f
|
||
|
|
||
|
proc SetSlice {slice} {
|
||
|
ipw SetSliceIndex $slice
|
||
|
UpdateIPW
|
||
|
renWin Render
|
||
|
}
|
||
|
|
||
|
::vtk::bind_tk_render_widget $render_widget
|
||
|
# Set the interactor for the widgets
|
||
|
#
|
||
|
set iact [[$render_widget GetRenderWindow] GetInteractor]
|
||
|
vtkInteractorStyleTrackballCamera style
|
||
|
$iact SetInteractorStyle style
|
||
|
|
||
|
ipw SetInteractor $iact
|
||
|
ipw On
|
||
|
|
||
|
spline SetInteractor $iact
|
||
|
spline SetPlaneSource [ ipw GetPolyDataAlgorithm ]
|
||
|
spline SetProjectionNormal 3
|
||
|
spline On
|
||
|
|
||
|
marker SetInteractor $iact
|
||
|
marker SetEnabled 1
|
||
|
marker InteractiveOff
|
||
|
|
||
|
# Create an initial interesting view
|
||
|
#
|
||
|
set cam1 [ren1 GetActiveCamera]
|
||
|
$cam1 Elevation 110
|
||
|
$cam1 SetViewUp 0 0 -1
|
||
|
$cam1 Azimuth 45
|
||
|
ren1 ResetCamera
|
||
|
|
||
|
# 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
|
||
|
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 [ipw 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 ResetCamera
|
||
|
renWin Render
|
||
|
}
|
||
|
|
||
|
# 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 slice_number interpmode xmode
|
||
|
set ori [ ipw GetPlaneOrientation ]
|
||
|
if { $ori != 0 } {
|
||
|
ipw SetPlaneOrientationToXAxes
|
||
|
set slice_number [expr ($xMax - $xMin)/2]
|
||
|
ipw SetSliceIndex $slice_number
|
||
|
} else {
|
||
|
set slice_number [ipw GetSliceIndex]
|
||
|
}
|
||
|
.top.slice config -from $xMin -to $xMax
|
||
|
.top.slice set $slice_number
|
||
|
UpdateSplinePosition
|
||
|
AlignCamera
|
||
|
set interpmode $xmode
|
||
|
SetInterpolation
|
||
|
}
|
||
|
|
||
|
proc AlignYaxis { } {
|
||
|
global yMin yMax slice_number interpmode ymode
|
||
|
|
||
|
set po [ ipw GetPlaneOrientation ]
|
||
|
set ori [ ipw GetPlaneOrientation ]
|
||
|
if { $ori != 1 } {
|
||
|
ipw SetPlaneOrientationToYAxes
|
||
|
set slice_number [expr ($yMax - $yMin)/2]
|
||
|
ipw SetSliceIndex $slice_number
|
||
|
} else {
|
||
|
set slice_number [ipw GetSliceIndex]
|
||
|
}
|
||
|
.top.slice config -from $yMin -to $yMax
|
||
|
.top.slice set $slice_number
|
||
|
UpdateSplinePosition
|
||
|
AlignCamera
|
||
|
set interpmode $ymode
|
||
|
SetInterpolation
|
||
|
}
|
||
|
|
||
|
proc AlignZaxis { } {
|
||
|
global zMin zMax slice_number interpmode zmode
|
||
|
set ori [ ipw GetPlaneOrientation ]
|
||
|
if { $ori != 2 } {
|
||
|
ipw SetPlaneOrientationToZAxes
|
||
|
set slice_number [expr ($zMax - $zMin)/2]
|
||
|
ipw SetSliceIndex $slice_number
|
||
|
} else {
|
||
|
set slice_number [ipw GetSliceIndex]
|
||
|
}
|
||
|
.top.slice config -from $zMin -to $zMax
|
||
|
.top.slice set $slice_number
|
||
|
UpdateSplinePosition
|
||
|
AlignCamera
|
||
|
set interpmode $zmode
|
||
|
SetInterpolation
|
||
|
}
|
||
|
|
||
|
proc UpdateSplinePosition { } {
|
||
|
set ori [ ipw GetPlaneOrientation ]
|
||
|
spline ProjectToPlaneOff
|
||
|
spline PlaceWidget
|
||
|
spline ProjectToPlaneOn
|
||
|
spline SetProjectionNormal $ori
|
||
|
spline SetProjectionNormal 3
|
||
|
UpdateIPW
|
||
|
}
|
||
|
|
||
|
# Set the vtkImagePlaneWidget's reslice interpolation mode
|
||
|
# to the corresponding popup menu choice and store
|
||
|
# it for subsequent orientation changes.
|
||
|
#
|
||
|
proc SetInterpolation { } {
|
||
|
global interpmode xmode ymode zmode
|
||
|
if { $interpmode == 0 } {
|
||
|
ipw TextureInterpolateOff
|
||
|
} else {
|
||
|
ipw TextureInterpolateOn
|
||
|
}
|
||
|
ipw SetResliceInterpolate $interpmode
|
||
|
set ori [ipw GetPlaneOrientation]
|
||
|
if { $ori == 0 } {
|
||
|
set xmode $interpmode
|
||
|
} elseif { $ori == 1 } {
|
||
|
set ymode $interpmode
|
||
|
} else {
|
||
|
set zmode $interpmode
|
||
|
}
|
||
|
renWin Render
|
||
|
}
|
||
|
|
||
|
# Procedure to update the placement of the vtkSplineWidget on the
|
||
|
# plane defined by the vtkImagePlaneWidget.
|
||
|
#
|
||
|
proc UpdateIPW { } {
|
||
|
set ori [ ipw GetPlaneOrientation ]
|
||
|
|
||
|
if { $ori == 3 } {
|
||
|
spline SetProjectionPosition 0
|
||
|
} else {
|
||
|
set pos [ ipw GetSlicePosition ]
|
||
|
spline SetProjectionPosition $pos
|
||
|
}
|
||
|
|
||
|
UpdateSW
|
||
|
}
|
||
|
|
||
|
# Procedure to update the spline geometry fed into the probe filter.
|
||
|
#
|
||
|
proc UpdateSW { } {
|
||
|
spline GetPolyData poly
|
||
|
}
|
||
|
|