/usr/local/CPAN/Graphics-VTK/Graphics/VTK/Tk/vtkInteractor.pm


# This file converted to perltk using the tcl2perl script and much hand-editing.
#   jc 12/23/01
#


package Graphics::VTK::Tk::vtkInteractor;

use Tk qw( Ev );

use Math::Trig; # Needed for tan, etc
use Graphics::VTK;
use Graphics::VTK::Tk;

use AutoLoader;
use Carp;
use strict;
use vars( qw/   $RendererFound  $CurrentRenderWindow $TkInteractor_StartRenderMethod $TkInteractor_EndRenderMethod
	      $CurrentRenderer  $TkInteractor_StillUpdateRate $TkInteractor_InteractiveUpdateRate
	        / );


use base qw(Tk::Widget);

Construct Tk::Widget 'vtkInteractor';  

bootstrap Graphics::VTK::Tk::vtkInteractor;

sub Tk_cmd { \&Tk::vtkinteractor };

sub Tk::Widget::ScrlvtkInteractor { shift->Scrolled('vtkInteractor' => @_) }

Tk::Methods("render", "Render", "cget", "configure", "GetRenderWindow");

#
# Remove from hash %$args any configure-like
# options which only apply at create time (e.g. -rw )
sub CreateArgs
{
  my ($package,$parent,$args) = @_;

  # Call inherited CreateArgs First:
  my @args = $package->SUPER::CreateArgs($parent,$args);
  
  if( defined( $args->{-rw} )){ # -rw defined in args, make sure args array includes it
  	my $value = delete $args->{-rw};
	push @args, '-rw', $value;
  }  
  return @args;
}

#
$TkInteractor_StartRenderMethod = undef;
$TkInteractor_EndRenderMethod = undef;
$TkInteractor_InteractiveUpdateRate = 15.0;
$TkInteractor_StillUpdateRate = 0.1;
#
#
sub ClassInit
{
 my ($class,$widget) = @_;
 my $focus;
  
 
 $widget->bind($class, '<Any-ButtonPress>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->StartMotion($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<Any-ButtonRelease>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->EndMotion($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<B1-Motion>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Rotate($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<B2-Motion>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Pan($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<B3-Motion>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Zoom($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<Shift-B1-Motion>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Pan($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<Shift-B3-Motion>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->RubberZoom($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<KeyPress-r>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Reset($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<KeyPress-u>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    # To-Do: Figure out how to make vtkInt a proper widget
    # $MW->{'.vtkInteract'}->MainWindow->deiconify;
   }
 );
 $widget->bind($class, '<KeyPress-w>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Wireframe();
   }
 );
 $widget->bind($class, '<KeyPress-s>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Surface();
   }
 );
 $widget->bind($class, '<KeyPress-p>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->PickActor($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<Enter>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Enter($Ev->x,$Ev->y);
   }
 );
 $widget->bind($class, '<Leave>',
  sub
   {
    my $w = shift;
    $w->{oldFocus} = $w->focusCurrent;
   }
 );
 $widget->bind($class, '<Expose>',
  sub
   {
    my $w = shift;
    my $Ev = $w->XEvent;
    $w->Expose();
   }
 );
}


sub InitObject {
 my ($widget, $args) = @_;
 # Create member data:
 # Objects used to display rubberband
 $widget->{RubberBandPoints} = Graphics::VTK::Points->new;
 $widget->{RubberBandLines} = Graphics::VTK::CellArray->new;
 $widget->{RubberBandScalars} = Graphics::VTK::FloatArray->new;
 $widget->{RubberBandPolyData} = Graphics::VTK::PolyData->new;
 $widget->{RubberBandMapper} = Graphics::VTK::PolyDataMapper2D->new;
 $widget->{RubberBandActor} = Graphics::VTK::Actor2D->new;
 $widget->{RubberBandColors} = Graphics::VTK::LookupTable->new;
 #
 $widget->{RubberBandPolyData}->SetPoints($widget->{RubberBandPoints});
 $widget->{RubberBandPolyData}->SetLines($widget->{RubberBandLines});
 $widget->{RubberBandMapper}->SetInput($widget->{RubberBandPolyData});
 $widget->{RubberBandMapper}->SetLookupTable($widget->{RubberBandColors});
 $widget->{RubberBandActor}->SetMapper($widget->{RubberBandMapper});
 #
 $widget->{RubberBandColors}->SetNumberOfTableValues(2);
 $widget->{RubberBandColors}->SetNumberOfColors(2);
 $widget->{RubberBandColors}->SetTableValue(0,1.0,0.0,0.0,1.0);
 $widget->{RubberBandColors}->SetTableValue(1,1.0,1.0,1.0,1.0);
 #
 $widget->{RubberBandPolyData}->GetPointData->SetScalars($widget->{RubberBandScalars});
 #
 $widget->{RubberBandMapper}->SetScalarRange(0,1);
 #
 $widget->{RubberBandPoints}->InsertPoint(0,0,0,0);
 $widget->{RubberBandPoints}->InsertPoint(1,0,10,0);
 $widget->{RubberBandPoints}->InsertPoint(2,10,10,0);
 $widget->{RubberBandPoints}->InsertPoint(3,10,0,0);
 #
 $widget->{RubberBandLines}->InsertNextCell(5);
 $widget->{RubberBandLines}->InsertCellPoint(0);
 $widget->{RubberBandLines}->InsertCellPoint(1);
 $widget->{RubberBandLines}->InsertCellPoint(2);
 $widget->{RubberBandLines}->InsertCellPoint(3);
 $widget->{RubberBandLines}->InsertCellPoint(0);
 #
 $widget->{RubberBandScalars}->InsertNextValue(0);
 $widget->{RubberBandScalars}->InsertNextValue(1);
 $widget->{RubberBandScalars}->InsertNextValue(0);
 $widget->{RubberBandScalars}->InsertNextValue(1);
 #
 $widget->{RubberBandMapper}->ScalarVisibilityOn;
 
 # Used to support picking operations
 #
 $widget->{PickedAssembly} = undef;
 $widget->{ActorPicker} = Graphics::VTK::CellPicker->new;
 $widget->{PickedProperty} = Graphics::VTK::Property->new;
 $widget->{PickedProperty}->SetColor(1,0,0);
 $widget->{PrePickedProperty} = undef;

 # Flags:
 $widget->{'InExpose'} = 0;

};


#
# a litle more complex than just "bind $widget <Expose> {%W Render}"
# we have to handle all pending expose events otherwise they que up.
#
sub Expose
{
 my $widget = shift;
 # Global Variables Declared for this function: TkInteractor_StillUpdateRate
 return if ( $widget->{InExpose} && $widget->{'InExpose'} == 1);
 $widget->{'InExpose'} = 1;
 $widget->GetRenderWindow->SetDesiredUpdateRate($TkInteractor_StillUpdateRate);
 $widget->update;
 $widget->GetRenderWindow->Render;
 $widget->{'InExpose'} = 0;
}
#
# Global variable keeps track of whether active renderer was found
$RendererFound = 0;
#
# Create event bindings
#
#
sub _Render
{
 my $widget = shift;
 # Global Variables Declared for this function: CurrentCamera, CurrentLight
 # Global Variables Declared for this function: TkInteractor_StartRenderMethod
 # Global Variables Declared for this function: TkInteractor_EndRenderMethod
 #
 if( $TkInteractor_StartRenderMethod){
	&$TkInteractor_StartRenderMethod();
 }
 #
 $widget->{CurrentLight}->SetPosition($widget->{CurrentCamera}->GetPosition);
 $widget->{CurrentLight}->SetFocalPoint($widget->{CurrentCamera}->GetFocalPoint);
 #
 $widget->Render;
 #
 if( $TkInteractor_EndRenderMethod){
	&$TkInteractor_EndRenderMethod();
 }
}
#
#
sub UpdateRenderer
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 my $WindowX;
 my $WindowY;
 my $break;
 my $i;
 my $lights;
 my $numRenderers;
 my $renderers;
 my @viewport;
 my $vpxmax;
 my $vpxmin;
 my $vpymax;
 my $vpymin;
 my $vx;
 my $vy;
 # Global Variables Declared for this function: CurrentCamera, CurrentLight
 # Global Variables Declared for this function: CurrentRenderWindow, CurrentRenderer
 # Global Variables Declared for this function: RendererFound, LastX, LastY
 # Global Variables Declared for this function: WindowCenterX, WindowCenterY
 #
 # Get the renderer window dimensions
 $WindowX = $widget->cget('-width');
 $WindowY = $widget->cget('-height');
 #
 # Find which renderer event has occurred in
 $CurrentRenderWindow = $widget->GetRenderWindow;
 $renderers = $CurrentRenderWindow->GetRenderers;
 $numRenderers = $renderers->GetNumberOfItems;
 #
 $renderers->InitTraversal;
 $RendererFound = 0;
 for ($i = 0; $i < $numRenderers; $i += 1)
  {
   $CurrentRenderer = $renderers->GetNextItem;
   $vx = ($x) / $WindowX;
   $vy = ($WindowY - ($y)) / $WindowY;
   @viewport = $CurrentRenderer->GetViewport;
   $vpxmin = $viewport[0];
   $vpymin = $viewport[1];
   $vpxmax = $viewport[2];
   $vpymax = $viewport[3];
   if ($vx >= $vpxmin && $vx <= $vpxmax && $vy >= $vpymin && $vy <= $vpymax)
    {
     $RendererFound = 1;
     $widget->{WindowCenterX} = ($WindowX) * (($vpxmax - $vpxmin) / 2.0 + $vpxmin);
     $widget->{WindowCenterY} = ($WindowY) * (($vpymax - $vpymin) / 2.0 + $vpymin);
     last;
    }
  }
 #
 $widget->{CurrentCamera} = $CurrentRenderer->GetActiveCamera;
 $lights = $CurrentRenderer->GetLights;
 $lights->InitTraversal;
 $widget->{CurrentLight} = $lights->GetNextItem;
 #
 $widget->{LastX} = $x;
 $widget->{LastY} = $y;
}
#
#
sub Enter
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 #
 $widget->{oldFocus} = $widget->focusCurrent();
 $widget->focus;
 $widget->UpdateRenderer($x,$y);
}
#
#
sub StartMotion
{ 
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 # Global Variables Declared for this function: CurrentCamera, CurrentLight
 # Global Variables Declared for this function: CurrentRenderWindow, CurrentRenderer
 # Global Variables Declared for this function: LastX, LastY
 # Global Variables Declared for this function: RendererFound
 # Global Variables Declared for this function: TkInteractor_InteractiveUpdateRate
 # Global Variables Declared for this function: RubberZoomPerformed
 #
 $widget->UpdateRenderer($x,$y);
 return unless ($RendererFound);
 #
 $widget->{RubberZoomPerformed} = 0;
 #
 $CurrentRenderWindow->SetDesiredUpdateRate($TkInteractor_InteractiveUpdateRate);
}
#
#
sub EndMotion
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 #
 return unless ($RendererFound);
 $CurrentRenderWindow->SetDesiredUpdateRate($TkInteractor_StillUpdateRate);
 #
 #
 if ($widget->{RubberZoomPerformed})
  {
   $CurrentRenderer->RemoveProp($widget->{RubberBandActor});
   $widget->DoRubberZoom();
  }
 #
 $widget->_Render;
}
#
#
# Called when the mouse button is release - do the zoom
#
sub DoRubberZoom
{
 my $widget = shift;
 my @DPoint;
 my @FPoint;
 my $FPoint0;
 my $FPoint1;
 my $FPoint2;
 my @PPoint;
 my $PPoint0;
 my $PPoint1;
 my $PPoint2;
 my $WindowY;
 my $angle;
 my $centerX;
 my $centerY;
 my $d;
 my $factor;
 my $focalDepth;
 my @focalEdge;
 my $focalEdge0;
 my $focalEdge1;
 my $focalEdge2;
 my $focalEdge3;
 my @nearFocalPoint;
 my $nearFocalPoint0;
 my $nearFocalPoint1;
 my $nearFocalPoint2;
 my $nearFocalPoint3;
 my $nearplane;
 my @newFocalPoint;
 my $newFocalPoint0;
 my $newFocalPoint1;
 my $newFocalPoint2;
 my $newFocalPoint3;
 my @newPosition;
 my $newPosition0;
 my $newPosition1;
 my $newPosition2;
 my $newPosition3;
 my $newScale;
 my $positionDepth;
 my @range;
 my $ydiff;
 my $ydist;
 # Global Variables Declared for this function: RendererFound
 #
 # Return if there is no renderer, or the rubber band is less
 # that 5 pixels in either direction
 return unless ($RendererFound);
 return if ($widget->{StartRubberZoomX} - $widget->{EndRubberZoomX} < 5 && $widget->{StartRubberZoomX} - $widget->{EndRubberZoomX} > -5);
 return if ($widget->{StartRubberZoomY} - $widget->{EndRubberZoomY} < 5 && $widget->{StartRubberZoomY} - $widget->{EndRubberZoomY} > -5);
 #
 # We'll need the window height later
 $WindowY = $widget->cget('-height');
 #
 # What is the center of the rubber band box in pixels?
 $centerX = ($widget->{StartRubberZoomX} + $widget->{EndRubberZoomX}) / 2.0;
 $centerY = ($widget->{StartRubberZoomY} + $widget->{EndRubberZoomY}) / 2.0;
 #
 # Convert the focal point to a display coordinate in order to get the
 # depth of the focal point in display units
 @FPoint = $widget->{CurrentCamera}->GetFocalPoint;
 $FPoint0 = $FPoint[0];
 $FPoint1 = $FPoint[1];
 $FPoint2 = $FPoint[2];
 $CurrentRenderer->SetWorldPoint($FPoint0,$FPoint1,$FPoint2,1.0);
 $CurrentRenderer->WorldToDisplay;
 @DPoint = $CurrentRenderer->GetDisplayPoint;
 $focalDepth = $DPoint[2];
 #
 # Convert the position of the camera to a display coordinate in order
 # to get the depth of the camera in display coordinates. Note this is
 # a negative number (behind the near clipping plane of 0) but it works
 # ok anyway
 @PPoint = $widget->{CurrentCamera}->GetPosition;
 $PPoint0 = $PPoint[0];
 $PPoint1 = $PPoint[1];
 $PPoint2 = $PPoint[2];
 $CurrentRenderer->SetWorldPoint($PPoint0,$PPoint1,$PPoint2,1.0);
 $CurrentRenderer->WorldToDisplay;
 @DPoint = $CurrentRenderer->GetDisplayPoint;
 $positionDepth = $DPoint[2];
 #
 # Find out the world position of where our new focal point should
 # be - it will be at the center of the box, back at the same focal depth
 # Don't actually set it now - we need to do all our computations before
 # we modify the camera
 $CurrentRenderer->SetDisplayPoint($centerX,$centerY,$focalDepth);
 $CurrentRenderer->DisplayToWorld;
 @newFocalPoint = $CurrentRenderer->GetWorldPoint;
 $newFocalPoint0 = $newFocalPoint[0];
 $newFocalPoint1 = $newFocalPoint[1];
 $newFocalPoint2 = $newFocalPoint[2];
 $newFocalPoint3 = $newFocalPoint[3];
 if ($newFocalPoint3 != 0.0)
  {
   $newFocalPoint0 = $newFocalPoint0 / $newFocalPoint3;
   $newFocalPoint1 = $newFocalPoint1 / $newFocalPoint3;
   $newFocalPoint2 = $newFocalPoint2 / $newFocalPoint3;
  }
 #
 # Find out where the new camera position will be - at the center of
 # the rubber band box at the position depth. Don't set it yet...
 $CurrentRenderer->SetDisplayPoint($centerX,$centerY,$positionDepth);
 $CurrentRenderer->DisplayToWorld;
 @newPosition = $CurrentRenderer->GetWorldPoint;
 $newPosition0 = $newPosition[0];
 $newPosition1 = $newPosition[1];
 $newPosition2 = $newPosition[2];
 $newPosition3 = $newPosition[3];
 if ($newPosition3 != 0.0)
  {
   $newPosition0 = $newPosition0 / $newPosition3;
   $newPosition1 = $newPosition1 / $newPosition3;
   $newPosition2 = $newPosition2 / $newPosition3;
  }
 #
 # We figured out how to position the camera to be centered, now we
 # need to "zoom". In parallel, this is simple since we only need to
 # change our parallel scale to encompass the entire y range of the
 # rubber band box. In perspective, we assume the box is drawn on the
 # near plane - this means that it is not possible that someone can
 # draw a rubber band box around a nearby object and dolly past it. It 
 # also means that you won't get very close to distance objects - but that
 # seems better than getting lost.
 if ($widget->{CurrentCamera}->GetParallelProjection)
  {
   # the new scale is just based on the y size of the rubber band box
   # compared to the y size of the window
   $ydiff = $widget->{StartRubberZoomX} - $widget->{EndRubberZoomX};
   $ydiff = $ydiff * -1.0 if ($ydiff < 0.0);
   $newScale = $widget->{CurrentCamera}->GetParallelScale;
   $newScale = $newScale * $ydiff / $WindowY;
   #
   # now we can actually modify the camera
   $widget->{CurrentCamera}->SetFocalPoint($newFocalPoint0,$newFocalPoint1,$newFocalPoint2);
   $widget->{CurrentCamera}->SetPosition($newPosition0,$newPosition1,$newPosition2);
   $widget->{CurrentCamera}->SetParallelScale($newScale);
   #
  }
 else
  {
   # find out the center of the rubber band box on the near plane
   $CurrentRenderer->SetDisplayPoint($centerX,$centerY,0.0);
   $CurrentRenderer->DisplayToWorld;
   @nearFocalPoint = $CurrentRenderer->GetWorldPoint;
   $nearFocalPoint0 = $nearFocalPoint[0];
   $nearFocalPoint1 = $nearFocalPoint[1];
   $nearFocalPoint2 = $nearFocalPoint[2];
   $nearFocalPoint3 = $nearFocalPoint[3];
   if ($nearFocalPoint3 != 0.0)
    {
     $nearFocalPoint0 = $nearFocalPoint0 / $nearFocalPoint3;
     $nearFocalPoint1 = $nearFocalPoint1 / $nearFocalPoint3;
     $nearFocalPoint2 = $nearFocalPoint2 / $nearFocalPoint3;
    }
   #
   # find the world coordinates of the point centered on the rubber band box
   # in x, on the border in y, and at the near plane depth.
   $CurrentRenderer->SetDisplayPoint($centerX,$widget->{StartRubberZoomY},0.0);
   $CurrentRenderer->DisplayToWorld;
   @focalEdge = $CurrentRenderer->GetWorldPoint;
   $focalEdge0 = $focalEdge[0];
   $focalEdge1 = $focalEdge[1];
   $focalEdge2 = $focalEdge[2];
   $focalEdge3 = $focalEdge[3];
   if ($focalEdge3 != 0.0)
    {
     $focalEdge0 = $focalEdge0 / $focalEdge3;
     $focalEdge1 = $focalEdge1 / $focalEdge3;
     $focalEdge2 = $focalEdge2 / $focalEdge3;
    }
   #
   # how far is this "rubberband edge point" from the focal point?
   $ydist = sqrt(($nearFocalPoint0 - $focalEdge0) * ($nearFocalPoint0 - $focalEdge0) + ($nearFocalPoint1 - $focalEdge1) * ($nearFocalPoint1 - $focalEdge1) + ($nearFocalPoint2 - $focalEdge2) * ($nearFocalPoint2 - $focalEdge2));
   #
   # We need to know how far back we must be so that when we view the scene
   # with the current view angle, we see all of the y range of the rubber
   # band box. Use a simple tangent equation - opposite / adjacent = tan theta
   # where opposite is half the y height of the rubber band box on the near
   # plane, adjacent is the distance we are solving for, and theta is half
   # the viewing angle. This distance that we solve for is the new distance
   # to the near plane - to find the new distance to the focal plane we
   # must take the old distance to the focal plane, subtract the near plane
   # distance, and add in the distance we solved for.
   $angle = 0.5 * 3.141592 / 180.0 * $widget->{CurrentCamera}->GetViewAngle;
   $d = $ydist / tan($angle);
   @range = $widget->{CurrentCamera}->GetClippingRange;
   $nearplane = $range[0];
   $factor = $widget->{CurrentCamera}->GetDistance / ($widget->{CurrentCamera}->GetDistance - $nearplane + $d);
   #
   # now we can actually modify the camera
   $widget->{CurrentCamera}->SetFocalPoint($newFocalPoint0,$newFocalPoint1,$newFocalPoint2);
   $widget->{CurrentCamera}->SetPosition($newPosition0,$newPosition1,$newPosition2);
   $widget->{CurrentCamera}->Dolly($factor);
   $CurrentRenderer->ResetCameraClippingRange;
  }
}
#
#
sub Rotate
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 # Global Variables Declared for this function: RendererFound
 #
 return unless ($RendererFound);
 #
 $widget->{CurrentCamera}->Azimuth($widget->{LastX} - $x);
 $widget->{CurrentCamera}->Elevation($y - $widget->{LastY});
 $widget->{CurrentCamera}->OrthogonalizeViewUp;
 #
 $widget->{LastX} = $x;
 $widget->{LastY} = $y;
 #
 $widget->_Render();
}
#
#
sub RubberZoom
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 my $WindowY;
 # Global Variables Declared for this function: RendererFound
 # Global Variables Declared for this function: CurrentRenderer
 #
 return unless ($RendererFound);
 #
 $WindowY = $widget->cget('-height');
 #
 unless ($widget->{RubberZoomPerformed})
  {
   $CurrentRenderer->AddProp($widget->{RubberBandActor});
   #
   $widget->{StartRubberZoomX} = $x;
   $widget->{StartRubberZoomY} = $WindowY - $y - 1;
   #
   $widget->{RubberZoomPerformed} = 1;
  }
 #
 $widget->{EndRubberZoomX} = $x;
 $widget->{EndRubberZoomY} = $WindowY - $y - 1;
 #
 $widget->{RubberBandPoints}->SetPoint(0,$widget->{StartRubberZoomX},$widget->{StartRubberZoomY},0);
 $widget->{RubberBandPoints}->SetPoint(1,$widget->{StartRubberZoomX},$widget->{EndRubberZoomY},0);
 $widget->{RubberBandPoints}->SetPoint(2,$widget->{EndRubberZoomX},$widget->{EndRubberZoomY},0);
 $widget->{RubberBandPoints}->SetPoint(3,$widget->{EndRubberZoomX},$widget->{StartRubberZoomY},0);
 #
 $widget->_Render();
}
#
#
#
sub Pan
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 my $APoint0;
 my $APoint1;
 my @DPoint;
 my @FPoint;
 my $FPoint0;
 my $FPoint1;
 my $FPoint2;
 my @PPoint;
 my $PPoint0;
 my $PPoint1;
 my $PPoint2;
 my @RPoint;
 my $RPoint0;
 my $RPoint1;
 my $RPoint2;
 my $RPoint3;
 my $Render;
 my $focalDepth;
 my $return;
 # Global Variables Declared for this function: CurrentRenderer, CurrentCamera
 # Global Variables Declared for this function: RendererFound
 #
 return unless ($RendererFound);
 #
 @FPoint = $widget->{CurrentCamera}->GetFocalPoint;
 $FPoint0 = $FPoint[0];
 $FPoint1 = $FPoint[1];
 $FPoint2 = $FPoint[2];
 #
 @PPoint = $widget->{CurrentCamera}->GetPosition;
 $PPoint0 = $PPoint[0];
 $PPoint1 = $PPoint[1];
 $PPoint2 = $PPoint[2];
 #
 $CurrentRenderer->SetWorldPoint($FPoint0,$FPoint1,$FPoint2,1.0);
 $CurrentRenderer->WorldToDisplay;
 @DPoint = $CurrentRenderer->GetDisplayPoint;
 $focalDepth = $DPoint[2];
 #
 $APoint0 = $widget->{WindowCenterX} + ($x - $widget->{LastX});
 $APoint1 = $widget->{WindowCenterY} - ($y - $widget->{LastY});
 #
 $CurrentRenderer->SetDisplayPoint($APoint0,$APoint1,$focalDepth);
 $CurrentRenderer->DisplayToWorld;
 @RPoint = $CurrentRenderer->GetWorldPoint;
 $RPoint0 = $RPoint[0];
 $RPoint1 = $RPoint[1];
 $RPoint2 = $RPoint[2];
 $RPoint3 = $RPoint[3];
 if ($RPoint3 != 0.0)
  {
   $RPoint0 = $RPoint0 / $RPoint3;
   $RPoint1 = $RPoint1 / $RPoint3;
   $RPoint2 = $RPoint2 / $RPoint3;
  }
 #
 $widget->{CurrentCamera}->SetFocalPoint(($FPoint0 - $RPoint0) / 2.0 + $FPoint0,($FPoint1 - $RPoint1) / 2.0 + $FPoint1,($FPoint2 - $RPoint2) / 2.0 + $FPoint2);
 #
 $widget->{CurrentCamera}->SetPosition(($FPoint0 - $RPoint0) / 2.0 + $PPoint0,($FPoint1 - $RPoint1) / 2.0 + $PPoint1,($FPoint2 - $RPoint2) / 2.0 + $PPoint2);
 #
 $widget->{LastX} = $x;
 $widget->{LastY} = $y;
 #
 $widget->_Render;
}
#
#
sub Zoom
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 my $Render;
 my $parallelScale;
 my $return;
 my $zoomFactor;
 # Global Variables Declared for this function: CurrentCamera, CurrentRenderer
 # Global Variables Declared for this function: LastX, LastY
 # Global Variables Declared for this function: RendererFound
 #
 return unless ($RendererFound);
 #
 $zoomFactor = 1.02 ** (0.5 * ($y - $widget->{LastY}));
 #
 if ($widget->{CurrentCamera}->GetParallelProjection)
  {
   $parallelScale = $widget->{CurrentCamera}->GetParallelScale * $zoomFactor;
   $widget->{CurrentCamera}->SetParallelScale($parallelScale);
  }
 else
  {
   $widget->{CurrentCamera}->Dolly($zoomFactor);
   $CurrentRenderer->ResetCameraClippingRange;
  }
 #
 $widget->{LastX} = $x;
 $widget->{LastY} = $y;
 #
 $widget->_Render;
}
#
#
sub Reset
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 my $WindowX;
 my $WindowY;
 my $i;
 my $numRenderers;
 my $renderers;
 my @viewport;
 my $vpxmax;
 my $vpxmin;
 my $vpymax;
 my $vpymin;
 my $vx;
 my $vy;
 # Global Variables Declared for this function: CurrentRenderWindow
 # Global Variables Declared for this function: RendererFound
 # Global Variables Declared for this function: CurrentRenderer
 #
 # Get the renderer window dimensions
 $WindowX = $widget->cget('-width');
 $WindowY = $widget->cget('-height');
 #
 # Find which renderer event has occurred in
 $CurrentRenderWindow = $widget->GetRenderWindow;
 $renderers = $CurrentRenderWindow->GetRenderers;
 $numRenderers = $renderers->GetNumberOfItems;
 #
 $renderers->InitTraversal;
 $RendererFound = 0;
 for ($i = 0; $i < $numRenderers; $i += 1)
  {
   $CurrentRenderer = $renderers->GetNextItem;
   $vx = ($x) / $WindowX;
   $vy = ($WindowY - ($y)) / $WindowY;
   #
   @viewport = $CurrentRenderer->GetViewport;
   $vpxmin = $viewport[0];
   $vpymin = $viewport[1];
   $vpxmax = $viewport[2];
   $vpymax = $viewport[3];
   if ($vx >= $vpxmin && $vx <= $vpxmax && $vy >= $vpymin && $vy <= $vpymax)
    {
     $RendererFound = 1;
     last;
    }
  }
 #
 $CurrentRenderer->ResetCamera if ($RendererFound);
 #
 $widget->_Render();
}
#
#
sub Wireframe
{
 my $widget = shift;
 my $actor;
 my $actors;
 # Global Variables Declared for this function: CurrentRenderer
 #
 $actors = $CurrentRenderer->GetActors;
 #
 $actors->InitTraversal;
 $actor = $actors->GetNextItem;
 while( defined($actor)){
        $actor->GetProperty->SetRepresentationToWireframe;
        $actor = $actors->GetNextItem;
 };
 #
 $widget->_Render();
}
#
#
sub Surface
{
 my $widget = shift;
 my $actor;
 my $actors;
 # Global Variables Declared for this function: CurrentRenderer
 #
 $actors = $CurrentRenderer->GetActors;
 #
 $actors->InitTraversal;
 $actor = $actors->GetNextItem;
 while( defined($actor)){
        $actor->GetProperty->SetRepresentationToSurface;
        $actor = $actors->GetNextItem;
 };
 #
 $widget->_Render();
}
#
#
#
sub PickActor   
{
 my $widget = shift;
 my $x = shift;
 my $y = shift;
 my $assembly;
 # Global Variables Declared for this function: CurrentRenderer, RendererFound
 # Global Variables Declared for this function: PickedAssembly, PrePickedProperty
 #
 my $WindowY = $widget->cget('-height');
 #
 return unless ($RendererFound);
 $widget->{ActorPicker}->Pick($x,$WindowY - $y - 1,0.0,$CurrentRenderer);
 $assembly = $widget->{ActorPicker}->GetAssembly;
 #
 if ($widget->{PickedAssembly} && $widget->{PrePickedProperty} )
  {
   $widget->{PickedAssembly}->SetProperty($widget->{PrePickedProperty});
   # release hold on the property
   $widget->{PrePickedProperty}->UnRegister($widget->{PrePickedProperty});
   $widget->{PrePickedProperty} = undef;
  }
 #
 if ($assembly )
  {
   $widget->{PickedAssembly} = $assembly;
   $widget->{PrePickedProperty} = $widget->{PickedAssembly}->GetProperty;
   # hold onto the property
   $widget->{PrePickedProperty}->Register($widget->{PrePickedProperty});
   $widget->{PickedAssembly}->SetProperty($widget->{PickedProperty});
  }
 #
 $widget->_Render;
}


1;
__END__