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

  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 "vtkSplineSurface2DWidget.h"

#include "vtkActor.h"
#include "vtkAssemblyNode.h"
#include "vtkAssemblyPath.h"
#include "vtkCallbackCommand.h"
#include "vtkCamera.h"
#include "vtkCellArray.h"
#include "vtkCellPicker.h"
#include "vtkCylinderSource.h"
#include "vtkCutter.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPlane.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSplineSurfaceWidget.h"
#include "vtkTransform.h"

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

vtkCxxSetObjectMacro(vtkSplineSurface2DWidget, HandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkSplineSurface2DWidget, SelectedHandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkSplineSurface2DWidget, SelectedSurfaceProperty, vtkProperty);

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

  this->ImplicitPlane = vtkPlane::New();
  this->CutFilter = vtkCutter::New();

  this->CutFilter->SetCutFunction( this->ImplicitPlane );

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

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

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

  // Manage the picking stuff
  this->HandlePicker = vtkCellPicker::New();
  this->HandlePicker->SetTolerance(0.005);
  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();
}

vtkSplineSurface2DWidget::~vtkSplineSurface2DWidget()
{
  // first disable the widget
  this->SetEnabled(0);
  

  // then release all the resources
  
  if ( this->Spline)
    {
    this->Spline->UnRegister(this);
    }

  this->SurfaceActor->Delete();
  this->SurfaceMapper->Delete();

  this->HandleGeometry->Delete();
  this->HandleGeometry = NULL;
    
  this->HandleMapper->Delete();
  this->HandleMapper = NULL;

  if( ! this->Handle.empty() )
    {
    unsigned int numberOfHandles = this->Handle.size();
    for (unsigned int i=0; i<numberOfHandles; i++)
      {
      this->Handle[i]->Delete();
      }
    this->Handle.clear();
    }

  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->CutFilter )
    {
    this->CutFilter->Delete();
    this->CutFilter = NULL;
    }
  
  if ( this->ImplicitPlane )
    {
    this->ImplicitPlane->Delete();
    this->ImplicitPlane = NULL;
    }

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

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

  if ( enabling ) //------------------------------------------------------------
    {
    vtkDebugMacro(<<"Enabling SplineSurface2D 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
    unsigned int numberOfHandles = this->Handle.size();
    for (unsigned int j=0; j<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 SplineSurface2D 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 line
    this->CurrentRenderer->RemoveActor(this->SurfaceActor);

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

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

void vtkSplineSurface2DWidget::ProcessEvents(vtkObject* vtkNotUsed(object),
                                  unsigned long event,
                                  void* clientdata,
                                  void* vtkNotUsed(calldata))
{
  vtkSplineSurface2DWidget* self = reinterpret_cast<vtkSplineSurface2DWidget *>( 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;
    case vtkSplineSurface2DWidget::SplineSurfaceNumberOfHandlesChangedEvent:
      self->BuildRepresentation(); // recovers the new surface from the 3D spline.
      break;
    }
}

void vtkSplineSurface2DWidget::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 << "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";
    }

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

  os << indent << "Project To Plane: " << "\n";
  os << indent << "Projection Normal: " << this->ImplicitPlane->GetNormal() << "\n";
  os << indent << "Projection Position: " << this->ImplicitPlane->GetOrigin() << "\n";
}


void vtkSplineSurface2DWidget::SetSplineSurfaceWidget( vtkSplineSurfaceWidget * spline )
{
  if( this->Spline == spline )
    {
    return;
    }
  this->Spline = spline;
  this->Spline->Register(this);

  this->SetSurfaceProperty( spline->GetSurfaceProperty() );

  this->Spline->AddObserver(
                   vtkSplineSurface2DWidget::SplineSurfaceNumberOfHandlesChangedEvent,
                   this->EventCallbackCommand,
                   this->Priority);

  this->BuildRepresentation();
}

vtkSplineSurfaceWidget *
vtkSplineSurface2DWidget::GetSplineSurfaceWidget()
{
  return this->Spline;
}


void vtkSplineSurface2DWidget::BuildRepresentation()
{
  if( !this->Spline )
    {
    return;
    }

  vtkPolyData * surfaceData =  this->Spline->GetSurfaceData();
  if( surfaceData )
    {
    this->CutFilter->SetInput( surfaceData );
    }

  this->UpdateHandlesFromSpline();
}


void vtkSplineSurface2DWidget::UpdateHandlesFromSpline()
{
  // Handles have changed in number or in position.
  // We need to update the 2D representation.
  //
  unsigned int numberOfHandles = this->Spline->GetNumberOfHandles();
  if( numberOfHandles != this->Handle.size() )
    {
    unsigned int i=0;
    for (i=0; i<this->Handle.size(); i++)
      {
      this->HandlePicker->DeletePickList( this->Handle[i] );
      if( this->CurrentRenderer )
        {
        this->CurrentRenderer->RemoveActor(this->Handle[i]);
        }
      this->Handle[i]->Delete();
      }
    this->Handle.resize( numberOfHandles );
    for (i=0; i<numberOfHandles; i++)
      {
      this->Handle[i] = vtkActor::New();
      this->Handle[i]->SetProperty(this->HandleProperty);
      this->Handle[i]->SetMapper( this->HandleMapper );
      this->HandlePicker->AddPickList( this->Handle[i] );
      if( this->CurrentRenderer )
        {
        this->CurrentRenderer->AddActor(this->Handle[i]);
        }
      }
    }

  double ctr[3];
  for (unsigned int i=0; i<numberOfHandles; i++)
    {
    this->Spline->GetHandlePosition(i,ctr);
    this->Handle[i]->SetPosition(ctr);
    }

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

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

  this->CurrentHandle = (vtkActor *)prop;

  if ( this->CurrentHandle )
    {
    unsigned int numberOfHandles = this->Handle.size();
    for (unsigned int i=0; i<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 vtkSplineSurface2DWidget::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 vtkSplineSurface2DWidget::OnStartRender()
{
  double scale = 1.0;

  // scale the sphere if neccessary
  if (this->CurrentRenderer)
    {
    unsigned int i, j;
    unsigned int numberOfHandles = this->Handle.size();
    for (i = 0; i <numberOfHandles; ++i)
      {
      // make sure that the 2D handles are aligned with the 3D handles.
      double ctr[3];
      this->Spline->GetHandlePosition(i,ctr);
      this->Handle[i]->SetPosition(ctr);

      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 marker 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 vtkSplineSurface2DWidget::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 = vtkSplineSurface2DWidget::Outside;
    return;
    }
  
  if ( this->Interactor->GetControlKey() )
    {
    this->State = vtkSplineSurface2DWidget::Spinning;
    this->CalculateCentroid();
    }
  else
    {
    this->State = vtkSplineSurface2DWidget::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 = this->HighlightHandle(NULL);
      this->State = vtkSplineSurface2DWidget::Outside;
      return;
      }
    }

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

void vtkSplineSurface2DWidget::OnLeftButtonUp()
{
  if ( this->State == vtkSplineSurface2DWidget::Outside ||
       this->State == vtkSplineSurface2DWidget::Start )
    {
    return;
    }
  
  if( this->State == vtkSplineSurface2DWidget::Moving )
    {
    this->Spline->InvokeEvent(
      vtkSplineSurface2DWidget::SplineSurfaceHandlePositionChangedEvent,NULL);
    }

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

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

void vtkSplineSurface2DWidget::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 = vtkSplineSurface2DWidget::Outside;
    return;
    }

  this->State = vtkSplineSurface2DWidget::ApplyingForce;

  // 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 = vtkSplineSurface2DWidget::Outside;
      this->HighlightSurface(0);
      return;
      }
    else
      {
      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 vtkSplineSurface2DWidget::OnMiddleButtonUp()
{
  if ( this->State == vtkSplineSurface2DWidget::Outside ||
       this->State == vtkSplineSurface2DWidget::Start )
    {
    return;
    }

  if( this->State == vtkSplineSurface2DWidget::Spinning      ||
      this->State == vtkSplineSurface2DWidget::ApplyingForce  )
    {
    this->Spline->InvokeEvent(
      vtkSplineSurface2DWidget::SplineSurfaceHandlePositionChangedEvent,NULL);
    }

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

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

void vtkSplineSurface2DWidget::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 = vtkSplineSurface2DWidget::Outside;
    return;
    }

  this->State = vtkSplineSurface2DWidget::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 = vtkSplineSurface2DWidget::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->HighlightSurface(0);
        this->EventCallbackCommand->SetAbortFlag(1);
        this->State = vtkSplineSurface2DWidget::Outside;
        double pickPoint[3];
        this->SurfacePicker->GetPickPosition(pickPoint);
        this->Spline->InsertHandle(pickPoint); // this call triggers events and a render...
        return;
        }
      else 
        {
        // We are Scaling, just hightlight the surface by now.
        this->HighlightSurface(1);
        }
      }
    }
  else  //we picked a handle but lets make it look like the line is picked
    {
    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->HighlightSurface(0);
      this->EventCallbackCommand->SetAbortFlag(1);
      this->State = vtkSplineSurface2DWidget::Outside;
      this->Spline->RemoveHandle(this->CurrentHandleIndex); // this call triggers a 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 vtkSplineSurface2DWidget::OnRightButtonUp()
{
  if ( this->State == vtkSplineSurface2DWidget::Outside ||
       this->State == vtkSplineSurface2DWidget::Start )
    {
    return;
    }

  if( this->State == vtkSplineSurface2DWidget::Scaling ) 
    {
    this->Spline->InvokeEvent(
      vtkSplineSurface2DWidget::SplineSurfaceHandlePositionChangedEvent,NULL);
    }

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

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

void vtkSplineSurface2DWidget::OnMouseMove()
{
  // See whether we're active
  if ( this->State == vtkSplineSurface2DWidget::Outside ||
       this->State == vtkSplineSurface2DWidget::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 == vtkSplineSurface2DWidget::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 == vtkSplineSurface2DWidget::Scaling )
    {
    this->Scale(prevPickPoint, pickPoint, X, Y);
    }
  else if ( this->State == vtkSplineSurface2DWidget::Spinning )
    {
    camera->GetViewPlaneNormal(vpn);
    this->Spin(prevPickPoint, pickPoint, vpn);
    }
  else if ( this->State == vtkSplineSurface2DWidget::ApplyingForce )
    {
    this->ApplyForce(prevPickPoint, pickPoint);
    }

  if ( ! this->RemoteMode )
    {
    this->BuildRepresentation();

    // Interact, if desired
    this->InvokeEvent(vtkCommand::InteractionEvent,NULL);
    this->Interactor->Render();
    }
  else
    {
    // Transfer the Handle positions to the associated Spline
    unsigned int numberOfHandles = this->Spline->GetNumberOfHandles();
    float * xyz = new float[3*numberOfHandles];
    for(unsigned int hi=0; hi<numberOfHandles; hi++)
      {
      const double * pos = this->Handle[hi]->GetPosition();
      const unsigned int base = 3*hi;
      for(unsigned int i=0; i<3; i++)
        {
        xyz[base+i] = pos[i];
        }
      }
    this->Spline->SetHandlePositions( xyz );
    delete [] xyz;
    // Let it invoke the events as if the interactions were comming from it.
    this->Spline->InvokeEvent(
      vtkSplineSurface2DWidget::SplineSurface2DHandlePositionChangedEvent,NULL);
    }
  this->EventCallbackCommand->SetAbortFlag(1);
}

void vtkSplineSurface2DWidget::MovePoint(double *p1, double *p2)
{
  int numberOfHandles = this->Handle.size();
  if ( this->CurrentHandleIndex < 0 || this->CurrentHandleIndex >= numberOfHandles )
    {
    vtkGenericWarningMacro(<<"pline 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 vtkSplineSurface2DWidget::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];
  unsigned int numberOfHandles = this->Handle.size();
  for (unsigned int i = 0; i< 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 vtkSplineSurface2DWidget::ApplyForce(double *p1, double *p2)
{
  // Compute a Force vector based on distance to each handle
  int j=0;

  double v[3];
  for(j=0; j<3; j++)
    {
    v[j] = p2[j] - p1[j];
    }

  double newCtr[3];
  double dist[3];

  unsigned int numberOfHandles = this->Handle.size();
  for (unsigned int i = 0; i< numberOfHandles; i++)
    {
    double* ctr =  this->Handle[i]->GetPosition();
    double squaredDistance = 0.0;
    for(j=0; j<3; j++)
      {
      dist[j] = ctr[j] - p1[j];
      squaredDistance += dist[j] * dist[j];
      }
    const double sigma = 10.0; // This value should be taken somehow from the pixel spacing.
    const double squaredSigma = sigma * sigma;
    const double force = exp( - squaredDistance / squaredSigma );
    for(j=0; j<3; j++)
      {
      newCtr[j] = ctr[j] + v[j] * force;
      }
    this->Handle[i]->SetPosition(newCtr);
    }
}


void vtkSplineSurface2DWidget::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];

  unsigned int i;
  unsigned int numberOfHandles = this->Handle.size();
  for (i = 1; i<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 /= numberOfHandles;

  center[0] /= numberOfHandles;
  center[1] /= numberOfHandles;
  center[2] /= 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<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 vtkSplineSurface2DWidget::Spin(double *p1, double *p2, double *vtkNotUsed(vpn))
{
  // Mouse motion vector in world space
  double v[3];
  v[0] = p2[0] - p1[0];
  v[1] = p2[1] - p1[1];
  v[2] = p2[2] - p1[2];

  // Axis of rotation
  double axis[3] = {0.0,0.0,0.0};

  if(this->ImplicitPlane == NULL)
    {
    return;
    }

  double* normal = this->ImplicitPlane->GetNormal();
  axis[0] = normal[0];
  axis[1] = normal[1];
  axis[2] = normal[2];
  vtkMath::Normalize(axis);

  // Radius vector (from mean center to cursor position)
  double rv[3] = {p2[0] - this->Centroid[0],
                  p2[1] - this->Centroid[1],
                  p2[2] - this->Centroid[2]};

  // Distance between center and cursor location
  double rs = vtkMath::Normalize(rv);

  // Spin direction
  double ax_cross_rv[3];
  vtkMath::Cross(axis,rv,ax_cross_rv);

  // Spin angle
  double theta = 360.0 * vtkMath::Dot(v,ax_cross_rv) / rs;

  // 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];
  unsigned int numberOfHandles = this->Handle.size();
  for (unsigned int i=0; i<numberOfHandles; i++)
    {
    this->Handle[i]->GetPosition(ctr);
    this->Transform->TransformPoint(ctr,newCtr);
    this->Handle[i]->SetPosition(newCtr);
    }
}

void vtkSplineSurface2DWidget::SetSurfaceProperty( vtkProperty * property )
{
  this->SurfaceProperty = property;
  this->SurfaceActor->SetProperty(this->SurfaceProperty);
  property->Register(this);
}

void vtkSplineSurface2DWidget::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);
    }
}


// Release the resources of the Handle array
void vtkSplineSurface2DWidget::Initialize(void)
{
  if( !this->Spline )
    {
    return;
    }

  unsigned int numberOfHandles = this->Handle.size();

  unsigned 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<numberOfHandles; i++)
        {
        this->CurrentRenderer->RemoveViewProp(this->Handle[i]);
        }
      }
    }

  // HandleGeometry and
  // HandleMapper   should not be deleted here

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

  this->Handle.clear();
}


vtkPolyData * vtkSplineSurface2DWidget::GetSurfaceData()
{
  if( ! this->CutFilter )
    {
    return NULL;
    }
  return this->CutFilter->GetOutput();
}


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

void vtkSplineSurface2DWidget::PlaceWidget(double bds[6])
{
  double bounds[6], center[3];
  this->AdjustBounds(bds, bounds, center);

  this->BuildRepresentation();
}

void vtkSplineSurface2DWidget::SetNormal(double normal[3])
{
  if( this->ImplicitPlane )
    {
    this->ImplicitPlane->SetNormal( normal );
    }
}

void vtkSplineSurface2DWidget::SetOrigin(double origin[3])
{
  if( this->ImplicitPlane )
    {
    this->ImplicitPlane->SetOrigin( origin );
    }
}

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

  double ctr[3];
  unsigned int numberOfHandles = this->Handle.size();
  for (unsigned int i = 0; i<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] /= numberOfHandles;
  this->Centroid[1] /= numberOfHandles;
  this->Centroid[2] /= numberOfHandles;
}


