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 "set last_btn 0; configMenu; $popm post %X %Y" bind $y_button "set last_btn 1; configMenu; $popm post %X %Y" bind $z_button "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 }