#
# This script uses a vtkTkRenderWidget to create a
# Tk widget that is associated with a vtkRenderWindow.
#
# First we include the VTK Tcl packages which will make available 
# all of the vtk commands to Tcl
#
package require vtk
package require vtkinteraction

set RANGE            150
set MAX_ITERATIONS_1 $RANGE
set MAX_ITERATIONS_2 $RANGE
set XRAD             200
set YRAD             200

#
# Create firt Mandelbrot viewer
#
vtkImageMandelbrotSource mandelbrot1
  mandelbrot1 SetMaximumNumberOfIterations [expr int($MAX_ITERATIONS_1)]
  mandelbrot1 SetWholeExtent [expr -$XRAD] [expr $XRAD-1] \
                             [expr -$YRAD] [expr $YRAD-1] \
                             0 0
  set sample [expr 1.3 / $XRAD]
  mandelbrot1 SetSampleCX $sample $sample $sample $sample 
  mandelbrot1 SetOriginCX -0.72 0.22  0.0 0.0
  mandelbrot1 SetProjectionAxes 0 1 2

vtkLookupTable table1
  table1 SetTableRange 0 $RANGE
  table1 SetNumberOfColors $RANGE
  table1 Build
  table1 SetTableValue [expr $RANGE - 1]  0.0 0.0 0.0 0.0

vtkImageMapToColors map1
  map1 SetInput [mandelbrot1 GetOutput]
  map1 SetOutputFormatToRGB
  map1 SetLookupTable table1

vtkImageViewer viewer
  viewer SetInput [map1 GetOutput]
  viewer SetColorWindow 255.0
  viewer SetColorLevel 127.5
  [viewer GetActor2D] SetPosition $XRAD $YRAD

#
# Create second Mandelbrot viewer
#
vtkImageMandelbrotSource mandelbrot2
  mandelbrot2 SetMaximumNumberOfIterations [expr int($MAX_ITERATIONS_2)]
  mandelbrot2 SetWholeExtent [expr -$XRAD] [expr $XRAD-1] \
                             [expr -$YRAD] [expr $YRAD-1] \
                             0 0
  set sample [expr 1.3 / $XRAD]
  mandelbrot2 SetSampleCX $sample $sample $sample $sample 
  mandelbrot2 SetOriginCX -0.72 0.22  0.0 0.0
  mandelbrot2 SetProjectionAxes 2 3 1

vtkLookupTable table2
  table2 SetTableRange 0 $RANGE
  table2 SetNumberOfColors $RANGE
  table2 Build
  table2 SetTableValue [expr $RANGE - 1]  0.0 0.0 0.0 0.0

vtkImageMapToColors map2
  map2 SetInput [mandelbrot2 GetOutput]
  map2 SetOutputFormatToRGB
  map2 SetLookupTable table2

vtkImageViewer viewer2
  viewer2 SetInput [map2 GetOutput]
  viewer2 SetColorWindow 256.0
  viewer2 SetColorLevel 127.5
  [viewer2 GetActor2D] SetPosition $XRAD $YRAD

#
# Create the GUI: two vtkTkImageViewer widgets and a quit/reset buttons
#
wm withdraw .
set top [toplevel .top] 
wm protocol .top WM_DELETE_WINDOW ::vtk::cb_exit
wm title .top "Mandelbrot Viewer"

set f1 [frame $top.f1] 

pack $f1 \
        -side bottom \
        -fill both -expand f

#
# Create the image viewer widget for set 1
#
set manFrame [frame $f1.man]
set julFrame [frame $f1.jul]

pack $manFrame $julFrame \
        -side left \
        -padx 3 -pady 3 \
        -fill both -expand f

set manView [vtkTkImageViewerWidget $manFrame.view \
        -iv viewer \
        -width [expr $XRAD*2] \
        -height [expr $YRAD*2]]

set manRange [label $manFrame.range \
        -text "Mandelbrot Range: 0 - $RANGE"]

set quit [button $manFrame.quit  \
        -text "Quit" \
        -command ::vtk::cb_exit]

#
# Create the image viewer widget for set 2
#
pack $manView $manRange $quit \
        -side top \
        -padx 2 -pady 2 \
        -fill both -expand f

set julView [vtkTkImageViewerWidget $julFrame.view \
        -iv viewer2 \
        -width [expr $XRAD*2] \
        -height [expr $YRAD*2]]

set julRange [label $julFrame.range \
        -text "Julia Range: 0 - $RANGE"]

set reset [button $julFrame.reset  \
        -text "Reset" \
        -command Reset]

pack $julView $julRange $reset \
        -side top \
        -padx 2 -pady 2 \
        -fill both -expand f
#
# The equation label
#
set equation [label $top.equation \
        -text "X = X^2 + C"]

pack $equation \
        -side bottom \
        -fill x -expand f

#
# Create the default bindings
#
::vtk::bind_tk_imageviewer_widget $manView
::vtk::bind_tk_imageviewer_widget $julView

#
# Override some of the bindings
#
foreach {widget master slave} [list $manView 1 2 $julView 2 1] {

    set iren [[[$widget GetImageViewer] GetRenderWindow] GetInteractor]
    set istyle [$iren GetInteractorStyle]

    # Zoom in

    $istyle RemoveObservers LeftButtonPressEvent
    $istyle AddObserver LeftButtonPressEvent \
            [list StartZoom $iren]

    $istyle RemoveObservers LeftButtonReleaseEvent
    $istyle AddObserver LeftButtonReleaseEvent \
            [list EndZoom $iren $master $slave]

    # Zoom out

    $istyle RemoveObservers RightButtonPressEvent
    $istyle AddObserver RightButtonPressEvent \
            [list ZoomOut $iren $master $slave]

    $istyle RemoveObservers RightButtonReleaseEvent
    
    # Pan
    
    $istyle RemoveObservers MiddleButtonPressEvent
    $istyle AddObserver MiddleButtonPressEvent \
            [list Pan $iren $master $slave]

    $istyle RemoveObservers MiddleButtonReleaseEvent
}

#
# Update the display
#
proc MandelbrotUpdate {} {
  global MAX_ITERATIONS_1 MAX_ITERATIONS_2 RANGE
  global manView julView manRange julRange

  mandelbrot1 SetMaximumNumberOfIterations [expr int($MAX_ITERATIONS_1)]
  mandelbrot2 SetMaximumNumberOfIterations [expr int($MAX_ITERATIONS_1)]
  
  set tmp [mandelbrot1 GetOriginCX]
  set cr [lindex $tmp 0]
  set ci [lindex $tmp 1]
  set xr [lindex $tmp 2]
  set xi [lindex $tmp 3]

  mandelbrot1 Update
  set tmp [[mandelbrot1 GetOutput] GetScalarRange]
  set min [lindex $tmp 0]
  set max [lindex $tmp 1]
  $manRange configure -text "C = $cr + i $ci,    Mandelbrot Range: $min - $max"
  eval table1 SetTableRange [expr $min - 1] $max
  set MAX_ITERATIONS_1 [expr $min + $RANGE]

  mandelbrot2 Update
  set tmp [[mandelbrot2 GetOutput] GetScalarRange]
  set min [lindex $tmp 0]
  set max [lindex $tmp 1]
  $julRange configure -text "X = $xr + i $xi,    Julia Range: $min - $max"
  eval table2 SetTableRange [expr $min - 1] $max
  set MAX_ITERATIONS_2 [expr $min + $RANGE]

  $manView Render
  $julView Render
}

#
# Reset both sets
#
proc Reset {} {
  global MAX_ITERATIONS_1 MAX_ITERATIONS_2 RANGE XRAD

  set MAX_ITERATIONS_2 $RANGE
  set MAX_ITERATIONS_1 $RANGE

  set sample [expr 1.3 / $XRAD]
  mandelbrot1 SetSampleCX $sample $sample $sample $sample 
  mandelbrot1 SetOriginCX -0.72 0.22  0.0 0.0

  set sample [expr 1.3 / $XRAD]
  mandelbrot2 SetSampleCX $sample $sample $sample $sample 
  mandelbrot2 SetOriginCX -0.72 0.22  0.0 0.0

  MandelbrotUpdate
}

#
# Zoom in
#
proc StartZoom {iren} {
  global X Y

  set pos [$iren GetEventPosition]
  set X [lindex $pos 0]
  set Y [lindex $pos 1]
}

proc EndZoom {iren master slave} {
  global X Y XRAD YRAD
  
  # Put origin in middle. 

  set pos [$iren GetEventPosition]
  set x [expr [lindex $pos 0] - $XRAD]
  set y [expr [lindex $pos 1] - $YRAD]
  set X [expr $X - $XRAD]
  set Y [expr $Y - $YRAD]

  # Sort

  if {$X < $x} {
    set tmp $X
    set X $x
    set x $tmp
  }
  if {$Y < $y} {
    set tmp $Y
    set Y $y
    set y $tmp
  }

  # Middle/radius

  set xMid [expr 0.5 * ($x + $X)]
  set yMid [expr 0.5 * ($y + $Y)]
  set xDim [expr ($X - $x)]
  set yDim [expr ($Y - $y)]

  # Determine scale

  if { $xDim <= 4 && $yDim <= 4} {
    # Box too small.  Zoom into point.
    set scale 0.5
  } else {
    # Relative to window dimensions
    set xDim [expr 1.0 * $xDim / (2*$XRAD)]
    set yDim [expr 1.0 * $yDim / (2*$YRAD)]
    # Take the largest
    if {$xDim > $yDim} {
      set scale $xDim
    } else {
      set scale $yDim
    }
  }

  mandelbrot$master Pan $xMid $yMid 0.0
  mandelbrot$master Zoom $scale
  mandelbrot$slave CopyOriginAndSample mandelbrot$master

  MandelbrotUpdate
}

#
# Zoom out
#
proc ZoomOut {iren master slave} {
  global XRAD YRAD
  
  # Put origin in middle. 

  set pos [$iren GetEventPosition]
  set x [expr [lindex $pos 0] - $XRAD]
  set y [expr [lindex $pos 1] - $YRAD]

  set scale 2.0

  # Compute new origin.

  mandelbrot$master Pan $x $y 0.0
  mandelbrot$master Zoom $scale
  mandelbrot$slave CopyOriginAndSample mandelbrot$master

  MandelbrotUpdate
}

#
# Pan
#
proc Pan {iren master slave} {
  global XRAD YRAD
    
  # Put origin in middle. 

  set pos [$iren GetEventPosition]
  set x [expr [lindex $pos 0] - $XRAD]
  set y [expr [lindex $pos 1] - $YRAD]

  set scale 2.0

  # Compute new origin.

  mandelbrot$master Pan $x $y 0.0
  mandelbrot$slave CopyOriginAndSample mandelbrot$master

  MandelbrotUpdate
}

MandelbrotUpdate

 
