
#include the necessary packages
package require vtk
package require vtkinteraction
#Create a sphere
vtkSphereSource sphere
sphere SetThetaResolution
8
sphere SetPhiResolution
8
#Create a new polydata mapper and
#set the input to the sphere
vtkPolyDataMapper sphereMapper
sphereMapper SetInput
[sphere GetOutput]
#Create a new actor to reference the sphere
vtkActor sphereActor
sphereActor SetMapper
sphereMapper
#Create a new cube
vtkCubeSource cube
#Set the cube position and size
cube SetCenter
1 1 1
cube SetXLength
1
cube SetYLength
1
cube SetZLength
2
#Create a new poly data mapper and set
#it to the cube
vtkPolyDataMapper cubeMapper
cubeMapper SetInput
[cube GetOutput]
#Create a new actor to reference the cube
vtkActor cubeActor
cubeActor SetMapper
cubeMapper
# Create a new renderer and render window
vtkRenderer ren1
vtkRenderWindow renWin
renWin AddRenderer
ren1
ren1 SetBackground
.5 0 .5
#add the actors to the scene
ren1 AddActor sphereActor
ren1 AddActor cubeActor
#Create a vtk Render Widget. This is an
#object which provides a mechanism allowing
#tcl/tk to interact with the renderwindow
set vtkw [vtkTkRenderWidget
.ren \
-width 300 \
-height 300 \
-rw renWin]
#Because we are using the tcl/tk RenderWidget
#we can't use the standart vtkRenderWindowInteractor
#instead we use BindTkRenderWidget to provide the
#standard functionality that RenderWindowInteractor
#would otherwise do for us.
BindTkRenderWidget $vtkw
#bind the x key to the ToggleWireframe function
bind $vtkw <KeyPress-x>
{ToggleWireframe}
#flag to set whether wireframe is on or off
set wf 0
proc ToggleWireframe {} {
global wf
#get a reference to all the actors
in the
#current render
set actors
[ren1 GetActors]
#Loop through all the actors and
set the new
#visualization mode
$actors InitTraversal
set actor
[$actors GetNextItem]
while {$actor
!= ""} {
if {$wf
== 0} {
[$actor
GetProperty] SetRepresentationToWireframe
} elseif {$wf
== 1} {
[$actor
GetProperty] SetRepresentationToPoints
} else {
[$actor
GetProperty] SetRepresentationToSurface
}
set actor
[$actors GetNextItem]
}
#Set the visualization mode flag
if {$wf
== 0} {
set wf
1
} elseif {$wf
== 1} {
set wf
2
} else {
set wf
0
}
#redraw the scene
renWin Render
}
#bind the c key to toggle the cube on or off
bind $vtkw <KeyPress-c>
{ToggleCube}
set cb 0
proc ToggleCube {} {
global cb
#if the cube is currently in the
scene
#remove it otherwise add it
if {$cb
== 0} {
ren1 RemoveActor
cubeActor
set cb
1
} else {
ren1 AddActor
cubeActor
set cb
0
}
renWin Render
}
#bind the v key to toggle the sphere on or off
bind $vtkw <KeyPress-v>
{ToggleSphere}
set sp 0
proc ToggleSphere {} {
global sp
if {$sp
== 0} {
ren1 RemoveActor
sphereActor
set sp
1
} else {
ren1 AddActor
sphereActor
set sp
0
}
renWin Render
}
#bind the b key to set the SetActor function
bind $vtkw <KeyPress-b>
{SetActor}
vtkActor CurrentActor
set CurrentActor cubeActor
set aId 0
#Toggle which actor the CurrentActor is pointing
to
proc SetActor {} {
global CurrentActor
global aId
if {$aId == 0} {
set CurrentActor
cubeActor
set aId
1
puts "Current
Actor: Cube"
} else {
set CurrentActor
sphereActor
set aId
0
puts "Current
Actor: Sphere"
}
}
#bind the y key to the CycleColor procedure
bind $vtkw <KeyPress-y>
{CycleColor}
set c 0
#Cycle the color of the current actor
proc CycleColor {} {
global c
global CurrentActor
if {$c
== 0} {
[$CurrentActor
GetProperty] SetColor
255 0 0
set c
1
} elseif {$c
== 1} {
[$CurrentActor
GetProperty] SetColor
0 255 0
set c
2
} else {
[$CurrentActor
GetProperty] SetColor
0 0 255
set c
0
}
renWin Render
}
#The following set of bindings and procedures
#changes the size of the cube actor
bind $vtkw <KeyPress-h>
{GrowY}
proc GrowY {} {
set y
[cube GetYLength]
set y
[expr $y + 1]
cube SetYLength
$y
renWin Render
}
bind $vtkw <KeyPress-n> {ShrinkY}
proc ShrinkY {} {
set y
[cube GetYLength]
set y
[expr $y - 1]
if {$y
< 1} {set y 1}
cube SetYLength
$y
renWin Render
}
bind $vtkw <KeyPress-j> {GrowZ}
proc GrowZ {} {
set z
[cube GetZLength]
set z
[expr $z + 1]
cube SetZLength
$z
renWin Render
}
bind $vtkw <KeyPress-m> {ShrinkZ}
proc ShrinkZ {} {
set z
[cube GetZLength]
set z
[expr $z - 1]
if {$z
< 1} {set z 1}
cube SetZLength
$z
renWin Render
}
bind $vtkw <KeyPress-k> {GrowX}
proc GrowX {} {
set x
[cube GetXLength]
set x
[expr $x + 1]
cube SetXLength
$x
renWin Render
}
bind $vtkw <KeyPress-l> {ShrinkX}
proc ShrinkX {} {
set x
[cube GetXLength]
set x
[expr $x - 1]
if {$x
< 1} {set x 1}
cube SetXLength
$x
renWin Render
}
#put the window in the frame and display it
frame .params
pack $vtkw .params
-side top -fill both -expand yes
wm protocol . WM_DELETE_WINDOW bye
proc bye {} {
vtkCommand DeleteAllObjects
exit
}
# You only need this line if you run this script from
a Tcl shell
# (tclsh) instead of a Tk shell (wish)
tkwait window .
TCL/TK Part 4: Creating Interactive Visualizations with VTK
http://www.tcl.tk/advocacy/primer.html
http://cslu.cse.ogi.edu/toolkit/old/old/documentation/cslurp/wincslurp/node17.html
I also recommend that you download and install the TCL Tutor written by Clif Flynt. You can download it here: Instl2b4.exe
Note: The TCL Tutor is written in TCL/TK, and thus requires TCL/TK to be installed to run. Also, as it is executed by TCL it must be installed to a location that does NOT include spaces in the filename for the same reason's described in tutorial 1.
Creating visualizations with VTK and TCL/TK is easy, however sometimes you want to be able to manipulate the visualization on the fly. VTK provides a mechanism for interacting with your rendering called the vtkRenderWindowInteractor. This mechanism, however, is complicated to use. Luckily, because we are using TCL/TK we have a built in mechanism for interacting with windows by using the bind keyword. The bind keyword has the following syntax:
bind window-name event action
window-name is the name of the window for which tcl/tk will listen for the given event
event is the event that will fire the given action. Events can be mouse actions, key presses, window actions, etc. For keyboard actions they take the form of: <KeyPress-x>.
action is the action to take when the event is fired. You'll commonly use a function callback.
One of the main problems you are likely to encounter upon working with TCL/TK and VTK is the fact that TCL scripts are very hard to read. This is due to the fact that the syntax doesn't look like most other languages. In most languages you would distinguish functional parameters by enclosing them in () and seperating them with commas. TCL doesn't do this, you merely place the function name a space and then list the parameters delimited by spaces. This makes it hard to read. As such I have color coded the following code to help distinguish what is going on.
Green text are comments
Red text are objects/variables
Bold text are vtk key words
Blue text are TCL/TK key words
The following code shows how to create user interaction with tcl/tk and vtk:
You can also download the code here
Homework Assignment:
Take the file interact.tcl (the one in the tutorial) and add some code to be able to dynamically resize the sphere. Example: j to make it larger and h to make it smaller.