# This example shows how to use the InteractorStyleImage and add your own
# event handling.  The InteractorStyleImage is a special interactor designed
# to be used with vtkImageActor in a rendering window context. It forces the
# camera to stay perpendicular to the x-y plane. 

package require vtk
package require vtkinteraction

# Create the image
#
vtkPNGReader reader
  reader SetDataSpacing 0.8 0.8 1.5
  reader SetFileName "$VTK_DATA_ROOT/Data/fullhead15.png"

vtkImageShiftScale shiftScale
  shiftScale SetInputConnection [reader GetOutputPort]
  shiftScale SetShift 0
  shiftScale SetScale 0.07
  shiftScale SetOutputScalarTypeToUnsignedChar

vtkImageActor ia
  [ia GetMapper] SetInputConnection [shiftScale GetOutputPort]

# Create the RenderWindow, Renderer and both Actors
vtkRenderer ren1
vtkRenderWindow renWin
    renWin AddRenderer ren1
vtkRenderWindowInteractor iren
    iren SetRenderWindow renWin

# Create an image interactor style and associate it with the 
# interactive renderer. Then assign some callbacks with the
# appropriate events. THe callbacks are implemented as Tcl procs.
vtkInteractorStyleImage interactor
  iren SetInteractorStyle interactor
  interactor AddObserver LeftButtonPressEvent {StartZoom}
  interactor AddObserver MouseMoveEvent {MouseMove}
  interactor AddObserver LeftButtonReleaseEvent {EndZoom}

# Add the actors to the renderer, set the background and size
ren1 AddActor ia
ren1 SetBackground 0.1 0.2 0.4
renWin SetSize 400 400

# render the image
iren AddObserver UserEvent {wm deiconify .vtkInteract}
renWin Render

set cam1 [ren1 GetActiveCamera]

ren1 ResetCameraClippingRange
renWin Render

# prevent the tk window from showing up then start the event loop
wm withdraw .

### Supporting data for callbacks
vtkPoints pts
  pts SetNumberOfPoints 4
vtkCellArray lines
  lines InsertNextCell 5
  lines InsertCellPoint 0
  lines InsertCellPoint 1
  lines InsertCellPoint 2
  lines InsertCellPoint 3
  lines InsertCellPoint 0
vtkPolyData pd
  pd SetPoints pts
  pd SetLines lines
vtkPolyDataMapper2D bboxMapper
  bboxMapper SetInputData pd
vtkActor2D bboxActor
  bboxActor SetMapper bboxMapper
  [bboxActor GetProperty] SetColor 1 0 0
ren1 AddViewProp bboxActor

### Procedures for callbacks---------------------
set X 0
set Y 0
set bboxEnabled 0

proc StartZoom {} {
  global X Y bboxEnabled

  set xy [iren GetEventPosition]
  set X [lindex $xy 0]
  set Y [lindex $xy 1]

  pts SetPoint 0 $X $Y 0
  pts SetPoint 1 $X $Y 0
  pts SetPoint 2 $X $Y 0
  pts SetPoint 3 $X $Y 0

  set bboxEnabled 1
  bboxActor VisibilityOn
}

proc MouseMove {} {
  global X Y bboxEnabled

  if { $bboxEnabled } {
    set xy [iren GetEventPosition]
    set x [lindex $xy 0]
    set y [lindex $xy 1]

    pts SetPoint 1 $x $Y 0
    pts SetPoint 2 $x $y 0
    pts SetPoint 3 $X $y 0

    renWin Render
    }
}

#Do the hard stuff: pan and dolly
proc EndZoom {} {
  global bboxEnabled

  set p1 [pts GetPoint 0]
  set p2 [pts GetPoint 2]
  set x1 [lindex $p1 0]
  set y1 [lindex $p1 1]
  set x2 [lindex $p2 0]
  set y2 [lindex $p2 1]

  ren1 SetDisplayPoint $x1 $y1 0
  ren1 DisplayToWorld
  set p1 [ren1 GetWorldPoint]
  ren1 SetDisplayPoint $x2 $y2 0
  ren1 DisplayToWorld
  set p2 [ren1 GetWorldPoint]

  set p1X [lindex $p1 0]
  set p1Y [lindex $p1 1]
  set p1Z [lindex $p1 2]

  set p2X [lindex $p2 0]
  set p2Y [lindex $p2 1]
  set p2Z [lindex $p2 2]

  set camera [ren1 GetActiveCamera]
  set focalPt [$camera GetFocalPoint]
  set focalX [lindex $focalPt 0]
  set focalY [lindex $focalPt 1]
  set focalZ [lindex $focalPt 2]
  set position [$camera GetPosition]
  set positionX [lindex $position 0]
  set positionY [lindex $position 1]
  set positionZ [lindex $position 2]
  
  set deltaX [expr $focalX - ($p1X + $p2X)/2.0]
  set deltaY [expr $focalY - ($p1Y + $p2Y)/2.0]

  #Set camera focal point to the center of the box
  $camera SetFocalPoint [expr ($p1X + $p2X)/2.0] \
          [expr ($p1Y + $p2Y)/2.0] $focalZ
  $camera SetPosition [expr $positionX - $deltaX] \
          [expr $positionY - $deltaY] $positionZ

  #Now dolly the camera to fill the box
  #This is a half-assed hack for demonstration purposes
  if { $p1X > $p2X } {
      set deltaX [expr $p1X - $p2X]
  } else {
      set deltaX [expr $p2X - $p1X]
  }
  if { $p1Y > $p2Y } {
      set deltaY [expr $p1Y - $p2Y]
  } else {
      set deltaY [expr $p2Y - $p1Y]
  }

  set winSize [renWin GetSize]
  set winX [lindex $winSize 0]
  set winY [lindex $winSize 1]

  set sx [expr $deltaX / $winX]
  set sy [expr $deltaY / $winY]

  if { $sx > $sy } {
      set dolly [expr 1.0 + 1.0/(2.0*$sx)]
  } else {
      set dolly [expr 1.0 + 1.0/(2.0*$sy)]
  }
  $camera Dolly $dolly
  ren1 ResetCameraClippingRange

  set bboxEnabled 0
  bboxActor VisibilityOff
  renWin Render
}

