/*=========================================================================

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkSplineSurfaceWidget.h"

#include "vtkActor.h"
#include "vtkAssemblyNode.h"
#include "vtkAssemblyPath.h"
#include "vtkCallbackCommand.h"
#include "vtkCamera.h"
#include "vtkCardinalSpline.h"
#include "vtkCellArray.h"
#include "vtkCellPicker.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPlaneSource.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkCylinderSource.h"
#include "vtkCardinalSplinePatch.h"
#include "vtkTransform.h"

vtkCxxRevisionMacro(vtkSplineSurfaceWidget, "$Revision: 1.3 $");
vtkStandardNewMacro(vtkSplineSurfaceWidget);

vtkCxxSetObjectMacro(vtkSplineSurfaceWidget, HandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkSplineSurfaceWidget, SelectedHandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkSplineSurfaceWidget, SurfaceProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkSplineSurfaceWidget, SelectedSurfaceProperty, vtkProperty);

vtkSplineSurfaceWidget::vtkSplineSurfaceWidget()
{
  this->State = vtkSplineSurfaceWidget::Start;
  this->EventCallbackCommand->SetCallback(vtkSplineSurfaceWidget::ProcessEvents);
  this->PlaneSource = NULL;
  this->RemoteMode = 0; // by default running in local mode

  this->NumberOfHandles = 0;

  this->HandleMapper   = vtkPolyDataMapper::New();
  this->HandleGeometry = vtkCylinderSource::New();
  this->HandleGeometry->SetResolution(9);
  this->HandleGeometry->Update();
  this->HandleMapper->SetInput(this->HandleGeometry->GetOutput());
 
  this->SurfaceData = vtkPolyData::New();

  this->SurfaceMapper = vtkPolyDataMapper::New();
  this->SurfaceMapper->SetInput( this->SurfaceData ) ;
  this->SurfaceMapper->ImmediateModeRenderingOn();
  this->SurfaceMapper->SetResolveCoincidentTopologyToPolygonOffset();

  this->SurfaceActor = vtkActor::New();
  this->SurfaceActor->SetMapper( this->SurfaceMapper);

  // Initial creation of the widget, serves to initialize it
  // and generates its surface representation
  this->PlaceFactor = 1.0;

  // Manage the picking stuff
  this->HandlePicker = vtkCellPicker::New();
  this->HandlePicker->SetTolerance(0.005);
  for (int hi=0; hi<this->NumberOfHandles; hi++)
    {
    this->HandlePicker->AddPickList(this->Handle[hi]);
    }
  this->HandlePicker->PickFromListOn();

  this->SurfacePicker = vtkCellPicker::New();
  this->SurfacePicker->SetTolerance(0.01);
  this->SurfacePicker->AddPickList(this->SurfaceActor);
  this->SurfacePicker->PickFromListOn();

  this->CurrentHandle = NULL;
  this->CurrentHandleIndex = -1;

  this->Transform = vtkTransform::New();

  // Set up the initial properties
  this->HandleProperty = NULL;
  this->SelectedHandleProperty = NULL;
  this->SurfaceProperty = NULL;
  this->SelectedSurfaceProperty = NULL;
  this->CreateDefaultProperties();

}

vtkSplineSurfaceWidget::~vtkSplineSurfaceWidget()
{
  // first disable the widget
  if( this->GetEnabled() )
    {
    this->SetEnabled(0);
    }

  // then release all the resources
  
  if( this->SurfaceActor )
    {
    this->SurfaceActor->Delete();
    this->SurfaceActor = NULL;
    }

  if( this->SurfaceMapper )
    {
    this->SurfaceMapper->Delete();
    this->SurfaceMapper = NULL;
    }

  if( this->SurfaceData )
    {
    this->SurfaceData->Delete();
    this->SurfaceData = NULL;
    }

  if( this->HandleGeometry )
    {
    this->HandleGeometry->Delete();
    this->HandleGeometry = NULL;
    }

  if( this->HandleMapper )
    {
    this->HandleMapper->Delete();
    this->HandleMapper = NULL;
    }

  if( this->Handle )
    {
    for (int i=0; i<this->NumberOfHandles; i++)
      {
      this->Handle[i]->Delete();
      }
    delete [] this->Handle;
    this->Handle = NULL;
    }

  if( this->HandlePicker )
    {
    this->HandlePicker->Delete();
    this->HandlePicker = NULL;
    }

  if( this->SurfacePicker )
    {
    this->SurfacePicker->Delete();
    this->SurfacePicker = NULL;
    }

  if( this->HandleProperty )
    {
    this->HandleProperty->Delete();
    this->HandleProperty = NULL;
    }
  
  if ( this->SelectedHandleProperty )
    {
    this->SelectedHandleProperty->Delete();
    this->SelectedHandleProperty = NULL;
    }
  
  if ( this->SurfaceProperty )
    {
    this->SurfaceProperty->Delete();
    this->SurfaceProperty = NULL;
    }
  
  if ( this->SelectedSurfaceProperty )
    {
    this->SelectedSurfaceProperty->Delete();
    this->SelectedSurfaceProperty = NULL;
    }

  if( this->Transform )
    {
    this->Transform->Delete();
    this->Transform = NULL;
    }
}

void vtkSplineSurfaceWidget::SetHandlePosition(int handle, double x, 
                                        double y, double z)
{
  if(handle < 0 || handle >= this->NumberOfHandles)
    {
    vtkErrorMacro(<<"vtkSplineSurfaceWidget: handle index out of range = "<< handle);
    return;
    }
  this->Handle[handle]->SetPosition(x,y,z);
  this->BuildRepresentation();
}

void vtkSplineSurfaceWidget::SetHandlePosition(int handle, double xyz[3])
{
  this->SetHandlePosition(handle,xyz[0],xyz[1],xyz[2]);
}

void vtkSplineSurfaceWidget::GetHandlePosition(int handle, double xyz[3])
{
  if(handle < 0 || handle >= this->NumberOfHandles)
    {
    vtkErrorMacro(<<"vtkSplineSurfaceWidget: handle index out of range = "<< handle);
    return;
    }

  this->Handle[handle]->GetPosition(xyz);
}

double* vtkSplineSurfaceWidget::GetHandlePosition(int handle)
{
  if(handle < 0 || handle >= this->NumberOfHandles)
    {
    vtkErrorMacro(<<"vtkSplineSurfaceWidget: handle index out of range = "<< handle);
    return NULL;
    }

  return this->Handle[handle]->GetPosition();
}

void vtkSplineSurfaceWidget::SetHandlePositions(float * xyz) 
{
  for(vtkIdType handle=0; handle < this->NumberOfHandles; handle++)
    {
    const vtkIdType base = handle * 3;
    const double x = xyz[base  ];
    const double y = xyz[base+1];
    const double z = xyz[base+2];
    this->Handle[handle]->SetPosition(x,y,z);
    }
  this->BuildRepresentation();
}

int vtkSplineSurfaceWidget::GetHandlePositions(float * xyz) 
{
  for(vtkIdType handle=0; handle < this->NumberOfHandles; handle++)
    {
    const vtkIdType base = handle * 3;
    double * hxyz = this->GetHandlePosition(handle);
    xyz[base  ] = hxyz[0];
    xyz[base+1] = hxyz[1];
    xyz[base+2] = hxyz[2];
    }
  return this->NumberOfHandles;
}


void vtkSplineSurfaceWidget::SetEnabled(int enabling)
{
  if ( ! this->Interactor )
    {
    vtkErrorMacro(<<"The interactor must be set prior to enabling/disabling widget");
    return;
    }

  if ( enabling ) //------------------------------------------------------------
    {
    vtkDebugMacro(<<"Enabling line widget");

    if ( this->Enabled ) //already enabled, just return
      {
      return;
      }

    if ( ! this->CurrentRenderer )
      {
      this->SetCurrentRenderer(this->Interactor->FindPokedRenderer(
        this->Interactor->GetLastEventPosition()[0],
        this->Interactor->GetLastEventPosition()[1]));
      if (this->CurrentRenderer == NULL)
        {
        return;
        }
      }

    this->Enabled = 1;
    this->ValidPick = 1;

    // Listen for the following events
    this->CurrentRenderer->AddObserver(vtkCommand::StartEvent, 
                                       this->EventCallbackCommand, 
                                       this->Priority);

    vtkRenderWindowInteractor *i = this->Interactor;
    i->AddObserver(vtkCommand::MouseMoveEvent, this->EventCallbackCommand,
                   this->Priority);
    i->AddObserver(vtkCommand::LeftButtonPressEvent, this->EventCallbackCommand,
                   this->Priority);
    i->AddObserver(vtkCommand::LeftButtonReleaseEvent, this->EventCallbackCommand,
                   this->Priority);
    i->AddObserver(vtkCommand::MiddleButtonPressEvent, this->EventCallbackCommand,
                   this->Priority);
    i->AddObserver(vtkCommand::MiddleButtonReleaseEvent, this->EventCallbackCommand,
                   this->Priority);
    i->AddObserver(vtkCommand::RightButtonPressEvent, this->EventCallbackCommand,
                   this->Priority);
    i->AddObserver(vtkCommand::RightButtonReleaseEvent, this->EventCallbackCommand,
                   this->Priority);

    // Add the surface
    this->CurrentRenderer->AddActor(this->SurfaceActor);
    this->SurfaceActor->SetProperty(this->SurfaceProperty);

    // Turn on the handles
    for (int j=0; j<this->NumberOfHandles; j++)
      {
      this->CurrentRenderer->AddActor(this->Handle[j]);
      this->Handle[j]->SetProperty(this->HandleProperty);
      }
    this->BuildRepresentation();

    this->InvokeEvent(vtkCommand::EnableEvent,NULL);
    }

  else //disabling----------------------------------------------------------
    {
    vtkDebugMacro(<<"Disabling line widget");

    if ( ! this->Enabled ) //already disabled, just return
      {
      return;
      }

    this->Enabled = 0;
    this->ValidPick = 0;

    // Don't listen for events any more
    this->Interactor->RemoveObserver(this->EventCallbackCommand);

    // Don't listen to the renderer any more
    this->CurrentRenderer->RemoveObserver(this->EventCallbackCommand); 

    // Turn off the surface
    this->CurrentRenderer->RemoveActor(this->SurfaceActor);

    // Turn off the handles
    for (int i=0; i<this->NumberOfHandles; i++)
      {
      this->CurrentRenderer->RemoveActor(this->Handle[i]);
      }

    this->CurrentHandle = NULL;
    this->InvokeEvent(vtkCommand::DisableEvent,NULL);
    this->SetCurrentRenderer(NULL);
    }

}

void vtkSplineSurfaceWidget::ProcessEvents(vtkObject* vtkNotUsed(object),
                                  unsigned long event,
                                  void* clientdata,
                                  void* vtkNotUsed(calldata))
{
  vtkSplineSurfaceWidget* self = reinterpret_cast<vtkSplineSurfaceWidget *>( clientdata );

  // Okay, let's do the right thing
  switch(event)
    {
    case vtkCommand::StartEvent:
      self->OnStartRender();
      break;
    case vtkCommand::LeftButtonPressEvent:
      self->OnLeftButtonDown();
      break;
    case vtkCommand::LeftButtonReleaseEvent:
      self->OnLeftButtonUp();
      break;
    case vtkCommand::MiddleButtonPressEvent:
      self->OnMiddleButtonDown();
      break;
    case vtkCommand::MiddleButtonReleaseEvent:
      self->OnMiddleButtonUp();
      break;
    case vtkCommand::RightButtonPressEvent:
      self->OnRightButtonDown();
      break;
    case vtkCommand::RightButtonReleaseEvent:
      self->OnRightButtonUp();
      break;
    case vtkCommand::MouseMoveEvent:
      self->OnMouseMove();
      break;
    }
}

void vtkSplineSurfaceWidget::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  if ( this->HandleProperty )
    {
    os << indent << "Handle Property: " << this->HandleProperty << "\n";
    }
  else
    {
    os << indent << "Handle Property: (none)\n";
    }

  os << indent << "NumberOfHandles: " << this->NumberOfHandles << "\n";
  os << indent << "RemoteMode: " << this->RemoteMode << "\n";

  if ( this->SelectedHandleProperty )
    {
    os << indent << "Selected Handle Property: "
       << this->SelectedHandleProperty << "\n";
    }
  else
    {
    os << indent << "Selected Handle Property: (none)\n";
    }
  if ( this->SurfaceProperty )
    {
    os << indent << "Surface Property: " << this->SurfaceProperty << "\n";
    }
  else
    {
    os << indent << "Surface Property: (none)\n";
    }
  if ( this->SelectedSurfaceProperty )
    {
    os << indent << "Selected Surface Property: "
       << this->SelectedSurfaceProperty << "\n";
    }
  else
    {
    os << indent << "Selected Surface Property: (none)\n";
    }

}

void vtkSplineSurfaceWidget::BuildRepresentation()
{
  vtkWarningMacro("vtkSplineSurfaceWidget::BuildRepresentation() method must be overloaded in subclasses");
}

int vtkSplineSurfaceWidget::HighlightHandle(vtkProp *prop)
{
  // First unhighlight anything picked
  if ( this->CurrentHandle )
    {
    this->CurrentHandle->SetProperty(this->HandleProperty);
    }

  this->CurrentHandle = (vtkActor *)prop;

  if ( this->CurrentHandle )
    {
    for (int i=0; i<this->NumberOfHandles; i++) // find handle
      {
      if ( this->CurrentHandle == this->Handle[i] )
        {
        this->ValidPick = 1;
        this->HandlePicker->GetPickPosition(this->LastPickPosition);
        this->CurrentHandle->SetProperty(this->SelectedHandleProperty);
        return i;
        }
      }
    }
  return -1;
}

void vtkSplineSurfaceWidget::HighlightSurface(int highlight)
{
  if ( highlight )
    {
    this->ValidPick = 1;
    this->SurfacePicker->GetPickPosition(this->LastPickPosition);
    this->SurfaceActor->SetProperty(this->SelectedSurfaceProperty);
    }
  else
    {
    this->SurfaceActor->SetProperty(this->SurfaceProperty);
    }
}

//----------------------------------------------------------------------------
void vtkSplineSurfaceWidget::OnStartRender()
{
  double scale = 1.0;

  if (this->CurrentRenderer)
    {
    int i, j;
    for (i = 0; i < this->NumberOfHandles; ++i)
      {
      double *pos = this->Handle[i]->GetPosition();
    
      // what radius do we need for the resulting size
      double center[4];
      double NewPickPoint[4];
      // project the center to the display
      center[0] = pos[0];
      center[1] = pos[1];
      center[2] = pos[2];
      center[3] = 1.0;
      this->ComputeWorldToDisplay(center[0], center[1], center[2], 
                                  NewPickPoint);
      // then move one pixel away from the center and compute the world coords
      this->ComputeDisplayToWorld(NewPickPoint[0]+1.0, 
                                  NewPickPoint[1], NewPickPoint[2],
                                  NewPickPoint);
      // what is the radius hat results in one pixel difference
      double dist = sqrt(vtkMath::Distance2BetweenPoints(center,NewPickPoint));
      // make x and z scale to cover 5 pixels then y scale to be 1 percent of
      // the clipping range
      vtkCamera *camera = this->CurrentRenderer->GetActiveCamera();

      double *clippingRange = camera->GetClippingRange();

      this->Handle[i]->SetScale(10.0*dist/scale,
                                0.01*(clippingRange[1] - clippingRange[0]),
                                10.0*dist/scale);
      
      
      // we must orient the handle to face the camera
      double Rx[3], Rz[3];
      double *cpos = camera->GetPosition();
      
      if (camera->GetParallelProjection())
        {
        camera->GetDirectionOfProjection(Rz);
        Rz[0] = -Rz[0];
        Rz[1] = -Rz[1];
        Rz[2] = -Rz[2];
        }
      else
        {
        double distance = sqrt(
          (cpos[0] - pos[0])*(cpos[0] - pos[0]) +
          (cpos[1] - pos[1])*(cpos[1] - pos[1]) +
          (cpos[2] - pos[2])*(cpos[2] - pos[2]));
        for (j = 0; j < 3; j++)
          {
          Rz[j] = (cpos[j] - pos[j])/distance;
          }
        }
      
      this->Handle[i]->SetOrientation(0,0,0);

      double yaxis[3];
      yaxis[0] = 0;
      yaxis[1] = 1;
      yaxis[2] = 0;
      vtkMath::Cross(yaxis,Rz,Rx);
      vtkMath::Normalize(Rx);

      this->Handle[i]->RotateWXYZ(
        180.0*acos(vtkMath::Dot(yaxis,Rz))/3.1415926, 
        Rx[0], Rx[1], Rx[2]);
      this->Handle[i]->ComputeMatrix();
      }
    }
}

void vtkSplineSurfaceWidget::OnLeftButtonDown()
{
  int X = this->Interactor->GetEventPosition()[0];
  int Y = this->Interactor->GetEventPosition()[1];

  // Okay, make sure that the pick is in the current renderer
  if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y))
    {
    this->State = vtkSplineSurfaceWidget::Outside;
    return;
    }

  this->State = vtkSplineSurfaceWidget::Moving;
  
  // Okay, we can process this. Try to pick handles first;
  // if no handles picked, then try to pick the line.
  vtkAssemblyPath *path;
  this->HandlePicker->Pick(X,Y,0.0,this->CurrentRenderer);
  path = this->HandlePicker->GetPath();
  if ( path != NULL )
    {
    this->CurrentHandleIndex = this->HighlightHandle(path->GetFirstNode()->GetViewProp());
    }
  else
    {
    this->SurfacePicker->Pick(X,Y,0.0,this->CurrentRenderer);
    path = this->SurfacePicker->GetPath();
    if ( path != NULL )
      {
      this->HighlightSurface(1);
      }
    else
      {
      this->CurrentHandleIndex = -1;
      this->State = vtkSplineSurfaceWidget::Outside;
      return;
      }
    }

  this->EventCallbackCommand->SetAbortFlag(1);
  this->StartInteraction();
  this->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
  this->Interactor->Render();
}

void vtkSplineSurfaceWidget::OnLeftButtonUp()
{
  if ( this->State == vtkSplineSurfaceWidget::Outside ||
       this->State == vtkSplineSurfaceWidget::Start )
    {
    return;
    }

  this->State = vtkSplineSurfaceWidget::Start;
  this->HighlightHandle(NULL);
  this->HighlightSurface(0);

  this->EventCallbackCommand->SetAbortFlag(1);
  this->EndInteraction();
  this->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
  this->Interactor->Render();
}

void vtkSplineSurfaceWidget::OnMiddleButtonDown()
{
  int X = this->Interactor->GetEventPosition()[0];
  int Y = this->Interactor->GetEventPosition()[1];

  // Okay, make sure that the pick is in the current renderer
  if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y))
    {
    this->State = vtkSplineSurfaceWidget::Outside;
    return;
    }

  this->State = vtkSplineSurfaceWidget::Spinning;

  this->CalculateCentroid();


  // Okay, we can process this. Try to pick handles first;
  // if no handles picked, then try to pick the line.
  vtkAssemblyPath *path;
  this->HandlePicker->Pick(X,Y,0.0,this->CurrentRenderer);
  path = this->HandlePicker->GetPath();
  if ( path == NULL )
    {
    this->SurfacePicker->Pick(X,Y,0.0,this->CurrentRenderer);
    path = this->SurfacePicker->GetPath();
    if ( path == NULL )
      {
      this->State = vtkSplineSurfaceWidget::Outside;
      this->HighlightSurface(0);
      return;
      }
    else
      {
      // we picked the surface, remember the point that we clicked on. This
      // point will be held under the mouse while spinning
      this->SurfacePicker->GetPickPosition(this->GrabbingPoint);
      this->HighlightSurface(1);
      }
    }
  else  //we picked a handle but lets make it look like the line is picked
    {
    this->HighlightSurface(1);
    }

  this->EventCallbackCommand->SetAbortFlag(1);
  this->StartInteraction();
  this->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
  this->Interactor->Render();
}

void vtkSplineSurfaceWidget::OnMiddleButtonUp()
{
  if ( this->State == vtkSplineSurfaceWidget::Outside ||
       this->State == vtkSplineSurfaceWidget::Start )
    {
    return;
    }

  this->State = vtkSplineSurfaceWidget::Start;
  this->HighlightSurface(0);

  this->EventCallbackCommand->SetAbortFlag(1);
  this->EndInteraction();
  this->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
  this->Interactor->Render();
}

void vtkSplineSurfaceWidget::OnRightButtonDown()
{
  int X = this->Interactor->GetEventPosition()[0];
  int Y = this->Interactor->GetEventPosition()[1];

  // Okay, make sure that the pick is in the current renderer
  if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y))
    {
    this->State = vtkSplineSurfaceWidget::Outside;
    return;
    }

  this->State = vtkSplineSurfaceWidget::Scaling;
  

  // Okay, we can process this. Try to pick handles first;
  // if no handles picked, then pick the bounding box.
  vtkAssemblyPath *path;
  this->HandlePicker->Pick(X,Y,0.0,this->CurrentRenderer);
  path = this->HandlePicker->GetPath();
  if ( path == NULL )
    {
    this->SurfacePicker->Pick(X,Y,0.0,this->CurrentRenderer);
    path = this->SurfacePicker->GetPath();
    if ( path == NULL )
      {
      this->State = vtkSplineSurfaceWidget::Outside;
      this->HighlightSurface(0);
      return;
      }
    else
      {
      // If the CTRL-key is pressed we interpret this as inserting a handle.
      // There is no need for further interaction, we can solve this on the spot.
      if ( this->Interactor->GetControlKey() )
        {
        this->InsertHandle();
        this->State = vtkSplineSurfaceWidget::Outside;
        this->HighlightSurface(0);
        this->EventCallbackCommand->SetAbortFlag(1);
        this->Interactor->Render();
        return;
        }
      else 
        {
        // We are Scaling, just hightlight the surface by now.
        this->HighlightSurface(1);
        }
      }
    }
  else  //we picked a handle 
    {
    this->CurrentHandleIndex = this->HighlightHandle(path->GetFirstNode()->GetViewProp());
    // If the CTRL-key is pressed we interpret this as removing a handle
    // There is no need for further interaction, we can solve this on the spot.
    if ( this->Interactor->GetControlKey() )
      {
      this->RemoveHandle();
      this->State = vtkSplineSurfaceWidget::Outside;
      this->HighlightSurface(0);
      this->EventCallbackCommand->SetAbortFlag(1);
      this->Interactor->Render();
      return;
      }
    else 
      {
      // We picked a handle, but lets make it look like the line is picked
      this->HighlightSurface(1);
      }
    }

  this->EventCallbackCommand->SetAbortFlag(1);
  this->StartInteraction();
  this->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
  this->Interactor->Render();
}

void vtkSplineSurfaceWidget::OnRightButtonUp()
{
  if ( this->State == vtkSplineSurfaceWidget::Outside ||
       this->State == vtkSplineSurfaceWidget::Start )
    {
    return;
    }

  this->State = vtkSplineSurfaceWidget::Start;
  this->HighlightSurface(0);

  this->EventCallbackCommand->SetAbortFlag(1);
  this->EndInteraction();
  this->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
  this->Interactor->Render();
}

void vtkSplineSurfaceWidget::OnMouseMove()
{
  // See whether we're active
  if ( this->State == vtkSplineSurfaceWidget::Outside ||
       this->State == vtkSplineSurfaceWidget::Start )
    {
    return;
    }

  int X = this->Interactor->GetEventPosition()[0];
  int Y = this->Interactor->GetEventPosition()[1];

  // Do different things depending on state
  // Calculations everybody does
  double focalPoint[4], pickPoint[4], prevPickPoint[4];
  double z, vpn[3];

  vtkCamera *camera = this->CurrentRenderer->GetActiveCamera();
  if ( !camera )
    {
    return;
    }

  // Compute the two points defining the motion vector
  this->ComputeWorldToDisplay(this->LastPickPosition[0], this->LastPickPosition[1],
                              this->LastPickPosition[2], focalPoint);
  
  z = focalPoint[2];
  this->ComputeDisplayToWorld(double(this->Interactor->GetLastEventPosition()[0]),
                              double(this->Interactor->GetLastEventPosition()[1]),
                              z, prevPickPoint);
  this->ComputeDisplayToWorld(double(X), double(Y), z, pickPoint);

  // Process the motion
  if ( this->State == vtkSplineSurfaceWidget::Moving )
    {
    // Okay to process
    if ( this->CurrentHandle )
      {
      this->MovePoint(prevPickPoint, pickPoint);
      }
    else // Must be moving the spline
      {
      this->Translate(prevPickPoint, pickPoint);
      }
    }
  else if ( this->State == vtkSplineSurfaceWidget::Scaling )
    {
    this->Scale(prevPickPoint, pickPoint, X, Y);
    }
  else if ( this->State == vtkSplineSurfaceWidget::Spinning )
    {
    camera->GetViewPlaneNormal(vpn);
    this->Spin(pickPoint, vpn);
    }

  if ( ! this->RemoteMode )
    {
    this->BuildRepresentation();
    }
  else
    {
    // maybe define an explicit event in the header file
    this->InvokeEvent(
      vtkSplineSurfaceWidget::SplineSurfaceHandlePositionChangedEvent,NULL);
    }

  // Interact, if desired
  this->EventCallbackCommand->SetAbortFlag(1);
  this->InvokeEvent(vtkCommand::InteractionEvent,NULL);
  this->Interactor->Render();
}

void vtkSplineSurfaceWidget::MovePoint(double *p1, double *p2)
{
  if ( this->CurrentHandleIndex < 0 || this->CurrentHandleIndex >= this->NumberOfHandles )
    {
    vtkGenericWarningMacro(<<"Spline handle index out of range = "<< this->CurrentHandleIndex);
    return;
    }
  // Get the motion vector
  double v[3];
  v[0] = p2[0] - p1[0];
  v[1] = p2[1] - p1[1];
  v[2] = p2[2] - p1[2];

  double *ctr = this->Handle[ this->CurrentHandleIndex ]->GetPosition();

  double newCtr[3];
  newCtr[0] = ctr[0] + v[0];
  newCtr[1] = ctr[1] + v[1];
  newCtr[2] = ctr[2] + v[2];

  this->Handle[this->CurrentHandleIndex]->SetPosition(newCtr);
}

void vtkSplineSurfaceWidget::Translate(double *p1, double *p2)
{
  // Get the motion vector
  double v[3];
  v[0] = p2[0] - p1[0];
  v[1] = p2[1] - p1[1];
  v[2] = p2[2] - p1[2];

  double newCtr[3];
  for (int i = 0; i< this->NumberOfHandles; i++)
    {
    double* ctr =  this->Handle[i]->GetPosition();
    for (int j=0; j<3; j++)
      {
      newCtr[j] = ctr[j] + v[j];
      }
     this->Handle[i]->SetPosition(newCtr);
    }
}

void vtkSplineSurfaceWidget::Scale(double *p1, double *p2, int vtkNotUsed(X), int Y)
{
  // Get the motion vector
  double v[3];
  v[0] = p2[0] - p1[0];
  v[1] = p2[1] - p1[1];
  v[2] = p2[2] - p1[2];

  double center[3] = {0.0,0.0,0.0};
  double avgdist = 0.0;
  double *prevctr = this->Handle[0]->GetPosition();
  double *ctr;

  center[0] += prevctr[0];
  center[1] += prevctr[1];
  center[2] += prevctr[2];

  int i;
  for (i = 1; i<this->NumberOfHandles; i++)
    {
    ctr = this->Handle[i]->GetPosition();
    center[0] += ctr[0];
    center[1] += ctr[1];
    center[2] += ctr[2];
    avgdist += sqrt(vtkMath::Distance2BetweenPoints(ctr,prevctr));
    prevctr = ctr;
    }

  avgdist /= this->NumberOfHandles;

  center[0] /= this->NumberOfHandles;
  center[1] /= this->NumberOfHandles;
  center[2] /= this->NumberOfHandles;

  // Compute the scale factor
  double sf = vtkMath::Norm(v) / avgdist;
  if ( Y > this->Interactor->GetLastEventPosition()[1] )
    {
    sf = 1.0 + sf;
    }
  else
    {
    sf = 1.0 - sf;
    }

  // Move the handle points
  double newCtr[3];
  for (i = 0; i< this->NumberOfHandles; i++)
    {
    ctr = this->Handle[i]->GetPosition();
    for (int j=0; j<3; j++)
      {
      newCtr[j] = sf * (ctr[j] - center[j]) + center[j];
      }
    this->Handle[i]->SetPosition(newCtr);
    }
}

void vtkSplineSurfaceWidget::Spin(double *pp , double *vv)
{
  double *p1 = this->GrabbingPoint;
 
  // Vector positions relative to centroid.
  double v1[3];
  v1[0] = p1[0] - this->Centroid[0];
  v1[1] = p1[1] - this->Centroid[1];
  v1[2] = p1[2] - this->Centroid[2];

  // Distance between centroid and grabbing point.
  double dv1 = vtkMath::Normalize(v1);

  // Vector positions relative to centroid of the current mouse position.
  double vpp[3];
  vpp[0] = pp[0] - this->Centroid[0];
  vpp[1] = pp[1] - this->Centroid[1];
  vpp[2] = pp[2] - this->Centroid[2];

  // Normalized copy of the vector parallel to the line of sight.
  double vvnorm = vtkMath::Norm(vv);
  double vvn[3];
  vvn[0] = vv[0] / vvnorm;
  vvn[1] = vv[1] / vvnorm;
  vvn[2] = vv[2] / vvnorm;

  // The line of sight LS is defined by the point pp and the vector vvn which
  // is the normal to the camera plane pointing towards the viewer.  We want to
  // find along this line the point that is at distance dv1=|v1| from the centroid,
  // or... if the line is too far from the centroid, we want the point in line
  // LS closest to the centroid.  

  // From the vector between the centroid and the current picked point pp we
  // compute the component perpendicular to the line LS. This is done using the
  // cross product twice.
  double vvp[3];
  double vvq[3];
  vtkMath::Cross(vvn,vpp,vvq);
  vtkMath::Cross(vvq,vvn,vvp);
  
  double distanceFromCentroidToLS = vtkMath::Norm(vvp);

  if( distanceFromCentroidToLS < 1e-5 )
    {
    // Close to the center of rotation everything becomes unstable. 
    // It is better not to move at all.
    return;
    }

  // Vector from the Centroid to the target point were p1 is going to be mapped.
  double vtarget[3];

  // Compare the distance from p1 to the centroid against the
  // distance from the centroid to the line LS
  if( distanceFromCentroidToLS > dv1 )
    {
    // The line LS is too far from the centroid. Therefore just
    // Take the point in LS closest to the centroid and use its
    // vector relative to the centroid as the final orientation.
    vtarget[0] = vvp[0] / distanceFromCentroidToLS;  
    vtarget[1] = vvp[1] / distanceFromCentroidToLS;  
    vtarget[2] = vvp[2] / distanceFromCentroidToLS;  
    }
  else
    {
    // Compute the two points "pa" and "pb" in line LS that are at distance |v1| from the
    // centroid.
    double pa[3];
    double pb[3];
    double r = sqrt( dv1*dv1 - distanceFromCentroidToLS * distanceFromCentroidToLS );
    for(unsigned int i=0; i<3; i++)
      {
      pa[i] = this->Centroid[i] + vvp[i] + r * vvn[i];
      pb[i] = this->Centroid[i] + vvp[i] - r * vvn[i];
      }

    // select from those two points in L2 the one closest to p1
    if( vtkMath::Distance2BetweenPoints(pa,p1) > 
        vtkMath::Distance2BetweenPoints(pb,p1) )
      {
      for(unsigned int i=0; i<3; i++)
        {
        vtarget[i] = pb[i] - this->Centroid[i];
        }
      }
    else
      {
      for(unsigned int i=0; i<3; i++)
        {
        vtarget[i] = pa[i] - this->Centroid[i];
        }
      }
    }

  // Create axis of rotation and angle of rotation
  double axis[3];
  vtkMath::Cross(v1,vtarget,axis);
  if ( vtkMath::Norm(axis) < 1e-5  )
    {
    // The two vectors are so close that the axis has negligeable matgnitude.
    // It is not worth to risk numerical instability. Just don't move.
    return;
    }

  double dotproduct = vtkMath::Dot(v1,vtarget) / vtkMath::Norm(vtarget);
  if( dotproduct >= 1.0 )
    {
    return;
    }
  double theta = vtkMath::DoubleRadiansToDegrees() * acos( dotproduct );

  // Manipulate the transform to reflect the rotation
  this->Transform->Identity();
  this->Transform->Translate(this->Centroid[0],this->Centroid[1],this->Centroid[2]);
  this->Transform->RotateWXYZ(theta,axis);
  this->Transform->Translate(-this->Centroid[0],-this->Centroid[1],-this->Centroid[2]);

  // Set the handle points
  double newCtr[3];
  double ctr[3];
  for (int i=0; i<this->NumberOfHandles; i++)
    {
    this->Handle[i]->GetPosition(ctr);
    this->Transform->TransformPoint(ctr,newCtr);
    this->Handle[i]->SetPosition(newCtr);
    }
  this->Transform->TransformPoint(p1,this->GrabbingPoint);
}


void vtkSplineSurfaceWidget::CreateDefaultProperties()
{
  if ( ! this->HandleProperty )
    {
    this->HandleProperty = vtkProperty::New();
    this->HandleProperty->SetColor(1,1,1);
    }
  if ( ! this->SelectedHandleProperty )
    {
    this->SelectedHandleProperty = vtkProperty::New();
    this->SelectedHandleProperty->SetColor(1,0,0);
    }

  if ( ! this->SurfaceProperty )
    {
    this->SurfaceProperty = vtkProperty::New();
    this->SurfaceProperty->SetRepresentationToSurface();
    this->SurfaceProperty->SetAmbient(0.1);
    this->SurfaceProperty->SetDiffuse(0.1);
    this->SurfaceProperty->SetSpecular(0.5);
    this->SurfaceProperty->SetColor(1.0,1.0,1.0);
    this->SurfaceProperty->SetLineWidth(1.0);
    }
  if ( ! this->SelectedSurfaceProperty )
    {
    this->SelectedSurfaceProperty = vtkProperty::New();
    this->SelectedSurfaceProperty->SetRepresentationToWireframe();
    this->SelectedSurfaceProperty->SetAmbient(1.0);
    this->SelectedSurfaceProperty->SetAmbientColor(0.0,1.0,0.0);
    this->SelectedSurfaceProperty->SetLineWidth(2.0);
    }
}

void vtkSplineSurfaceWidget::PlaceWidget(double vtkNotUsed(bds)[6])
{
  vtkWarningMacro("vtkSplineSurfaceWidget::PlaceWidget(bounds) method must be overloaded in subclasses");
}

void vtkSplineSurfaceWidget::SetPlaneSource(vtkPlaneSource* plane)
{
  if (this->PlaneSource == plane)
    {
    return;
    }
  this->PlaneSource = plane;
}

// Release resources for handles
void vtkSplineSurfaceWidget::Initialize(void)
{
  int i;
  if ( this->Interactor )
    {
    if (!this->CurrentRenderer)
      {
      this->SetCurrentRenderer(this->Interactor->FindPokedRenderer(
        this->Interactor->GetLastEventPosition()[0],
        this->Interactor->GetLastEventPosition()[1]));
      }
    if ( this->CurrentRenderer != NULL)
      {
      for (i=0; i<this->NumberOfHandles; i++)
        {
        this->CurrentRenderer->RemoveViewProp(this->Handle[i]);
        }
      }
    }

  for (i=0; i<this->NumberOfHandles; i++)
    {
    this->HandlePicker->DeletePickList(this->Handle[i]);
    this->Handle[i]->Delete();
    }

  this->NumberOfHandles = 0;

  delete [] this->Handle;

  this->Handle = NULL;
}

void vtkSplineSurfaceWidget::GenerateSurfacePoints()
{
  vtkWarningMacro("vtkSplineSurfaceWidget::GenerateSurfacePoints() method must be overloaded in subclasses");
}

vtkPolyData * vtkSplineSurfaceWidget::GetSurfaceData()
{
  return this->SurfaceData;
}

unsigned int vtkSplineSurfaceWidget::GetNumberOfSurfacePoints()
{
  return this->SurfaceData->GetNumberOfPoints();
}

void vtkSplineSurfaceWidget::GetPolyData(vtkPolyData *pd)
{
  pd->ShallowCopy(this->SurfaceData);
}

int vtkSplineSurfaceWidget::GetSurfaceVisibility()
{
  return this->SurfaceActor->GetVisibility();
}


void vtkSplineSurfaceWidget::CalculateCentroid()
{
  this->Centroid[0] = 0.0;
  this->Centroid[1] = 0.0;
  this->Centroid[2] = 0.0;

  double ctr[3];
  for (int i = 0; i<this->NumberOfHandles; i++)
    {
    this->Handle[i]->GetPosition(ctr);
    this->Centroid[0] += ctr[0];
    this->Centroid[1] += ctr[1];
    this->Centroid[2] += ctr[2];
    }

  this->Centroid[0] /= this->NumberOfHandles;
  this->Centroid[1] /= this->NumberOfHandles;
  this->Centroid[2] /= this->NumberOfHandles;
}


// Node insertion is not necesarily implemented in every type of spline
// surface. The method is defined here for convenience as null operations.
// Derived classes should provide the appropriate implementation.
void vtkSplineSurfaceWidget::InsertHandle()
{
  vtkWarningMacro("InsertHandle() method must be implemented in a derived class");
}


// Node insertion is not necesarily implemented in every type of spline
// surface. The method is defined here for convenience as null operations.
// Derived classes should provide the appropriate implementation.
void vtkSplineSurfaceWidget::InsertHandle(double[3])
{
  vtkWarningMacro("InsertHandle() method must be implemented in a derived class");
}


// Node removal is not necesarily implemented in every type of spline
// surface. The method is defined here for convenience as null operations.
// Derived classes should provide the appropriate implementation.
void vtkSplineSurfaceWidget::RemoveHandle()
{
   vtkWarningMacro("RemoveHandle() method must be implemented in a derived class");
}


// Node removal is not necesarily implemented in every type of spline
void vtkSplineSurfaceWidget::RemoveHandle(int handleIndex)
{
  if ( handleIndex < 0 || handleIndex >= this->NumberOfHandles )
    {
    vtkGenericWarningMacro(<<"Spline handle index out of range = "<< this->CurrentHandleIndex);
    return;
    }

  this->CurrentHandleIndex = handleIndex;
  this->CurrentHandle = this->Handle[this->CurrentHandleIndex];
  
  this->RemoveHandle();

  this->State = vtkSplineSurfaceWidget::Outside;
  this->HighlightSurface(0);
  this->Interactor->Render();
}


// This method is intended to be overloaded in the derived classes
void vtkSplineSurfaceWidget::SetNumberOfHandles(int nh)
{
  this->Initialize(); // releases resources for handles
  this->NumberOfHandles = nh;
  this->Handle         = new vtkActor* [this->NumberOfHandles];

  // Create the handles and setup the picking 
  for (int i=0; i<this->NumberOfHandles; i++)
    {
    this->Handle[i] = vtkActor::New();
    this->Handle[i]->SetMapper(this->HandleMapper);
    this->Handle[i]->SetProperty(this->HandleProperty);
    this->HandlePicker->AddPickList(this->Handle[i]);
    this->CurrentRenderer->AddActor(this->Handle[i]);
    }
  this->HandlePicker->PickFromListOn();

  // Re-compute the spline surface
  this->BuildRepresentation();

  // Notify observers about the change
  //
  // This first event is intended for the SplineSurface2DWidget
  this->InvokeEvent(
    vtkSplineSurfaceWidget::SplineSurfaceNumberOfHandlesChangedEvent,NULL);
  //
  // This second event is intendef for the vtkVVWindow to notify
  // to other RenderWidgets and across TeleVolView.
  this->InvokeEvent(
    vtkSplineSurfaceWidget::SplineSurfaceHandlePositionChangedEvent,NULL);
}

