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

  Program:   Visualization Toolkit
  Module:    vtkLineRepresentation.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.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 "vtkLineRepresentation.h"
#include "vtkPointHandleRepresentation3D.h"
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkConeSource.h"
#include "vtkLineSource.h"
#include "vtkSphereSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkPolyData.h"
#include "vtkCallbackCommand.h"
#include "vtkBox.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkInteractorObserver.h"
#include "vtkMath.h"
#include "vtkLine.h"
#include "vtkWindow.h"
#include "vtkObjectFactory.h"
#include "vtkVectorText.h"
#include "vtkFollower.h"
#include "vtkCellPicker.h"
#include "vtkPolyDataMapper.h"
#include "vtkVector.h"
#include "vtkVectorOperators.h"

vtkStandardNewMacro(vtkLineRepresentation);

vtkCxxSetObjectMacro(vtkLineRepresentation,HandleRepresentation,vtkPointHandleRepresentation3D);

//----------------------------------------------------------------------------
vtkLineRepresentation::vtkLineRepresentation()
{
  // Handle size is in pixels for this widget
  this->HandleSize = 5.0;

  // By default, use one of these handles
  this->HandleRepresentation  = vtkPointHandleRepresentation3D::New();
  this->HandleRepresentation->AllOff();
  this->HandleRepresentation->SetHotSpotSize(1.0);
  this->HandleRepresentation->SetPlaceFactor(1.0);
  this->HandleRepresentation->TranslationModeOn();
  this->Point1Representation = nullptr;
  this->Point2Representation = nullptr;
  this->LineHandleRepresentation = nullptr;
  this->InstantiateHandleRepresentation();

  // Miscellaneous parameters
  this->Tolerance = 5;
  this->Placed = 0;

  // Represent the line
  this->LineSource = vtkLineSource::New();
  this->LineSource->SetResolution(5);
  this->LineMapper = vtkPolyDataMapper::New();
  this->LineMapper->SetInputConnection(
    this->LineSource->GetOutputPort());
  this->LineActor = vtkActor::New();
  this->LineActor->SetMapper(this->LineMapper);

  this->DirectionalLine = false;

  // Create the handles
  this->Handle = new vtkActor* [2];
  this->HandleMapper = new vtkPolyDataMapper* [2];
  this->HandleGeometry = new vtkPolyDataAlgorithm* [2];
  for (int i=0; i<2; i++)
  {
    vtkSphereSource *sphere = vtkSphereSource::New();
    sphere->SetThetaResolution(16);
    sphere->SetPhiResolution(8);

    this->HandleGeometry[i] = sphere;
    this->HandleMapper[i] = vtkPolyDataMapper::New();
    this->HandleMapper[i]->SetInputConnection(
      this->HandleGeometry[i]->GetOutputPort());
    this->Handle[i] = vtkActor::New();
    this->Handle[i]->SetMapper(this->HandleMapper[i]);
  }

  // Set up the initial properties
  this->CreateDefaultProperties();

  // Pass the initial properties to the actors.
  this->Handle[0]->SetProperty(this->EndPointProperty);
  this->Point1Representation->SetProperty(this->EndPointProperty);
  this->Handle[1]->SetProperty(this->EndPoint2Property);
  this->Point2Representation->SetProperty(this->EndPoint2Property);
  this->LineHandleRepresentation->SetProperty(this->EndPointProperty);
  this->LineActor->SetProperty(this->LineProperty);

  // Define the point coordinates
  double bounds[6];
  bounds[0] = -0.5;
  bounds[1] = 0.5;
  bounds[2] = -0.5;
  bounds[3] = 0.5;
  bounds[4] = -0.5;
  bounds[5] = 0.5;
  this->PlaceFactor = 1.0; //overload parent's value

  // The distance text annotation
  this->DistanceAnnotationVisibility = 0;
  this->Distance = 0.0;
  this->DistanceAnnotationFormat = new char[8];
  snprintf(this->DistanceAnnotationFormat,8,"%s","%-#6.3g");
  this->TextInput = vtkVectorText::New();
  this->TextInput->SetText( "0" );
  this->TextMapper = vtkPolyDataMapper::New();
  this->TextMapper->SetInputConnection(
    this->TextInput->GetOutputPort());
  this->TextActor = vtkFollower::New();
  this->TextActor->SetMapper(this->TextMapper);
  this->TextActor->GetProperty()->SetColor( 1.0, 0.1, 0.0 );

  // This needs to be initialized before PlaceWidget is called.
  this->InitializedDisplayPosition = 0;

  this->ClampToBounds = 0;

  // The bounding box
  this->BoundingBox = vtkBox::New();

  this->LinePicker = vtkCellPicker::New();
  this->LinePicker->SetTolerance(0.005); //need some fluff
  this->LinePicker->AddPickList( this->LineActor );
  this->LinePicker->PickFromListOn();

  this->RepresentationState = vtkLineRepresentation::Outside;
  this->AnnotationTextScaleInitialized = false;

  this->RestrictFlag = RestrictNone;

  // Initial creation of the widget, serves to initialize it.
  // Call PlaceWidget() LAST in the constructor, as this method depends on ivar
  // values.
  this->PlaceWidget(bounds);

}

//----------------------------------------------------------------------------
vtkLineRepresentation::~vtkLineRepresentation()
{
  if ( this->HandleRepresentation )
  {
    this->HandleRepresentation->Delete();
  }
  if ( this->Point1Representation )
  {
    this->Point1Representation->Delete();
  }
  if ( this->Point2Representation )
  {
    this->Point2Representation->Delete();
  }
  if ( this->LineHandleRepresentation )
  {
    this->LineHandleRepresentation->Delete();
  }

  this->LineActor->Delete();
  this->LineMapper->Delete();
  this->LineSource->Delete();

  for (int i=0; i<2; i++)
  {
    this->HandleGeometry[i]->Delete();
    this->HandleMapper[i]->Delete();
    this->Handle[i]->Delete();
  }
  delete [] this->Handle;
  delete [] this->HandleMapper;
  delete [] this->HandleGeometry;

  this->EndPointProperty->Delete();
  this->SelectedEndPointProperty->Delete();
  this->EndPoint2Property->Delete();
  this->SelectedEndPoint2Property->Delete();
  this->LineProperty->Delete();
  this->SelectedLineProperty->Delete();

  this->BoundingBox->Delete();

  delete [] this->DistanceAnnotationFormat;
  this->DistanceAnnotationFormat = nullptr;

  this->TextInput->Delete();
  this->TextMapper->Delete();
  this->TextActor->Delete();
  this->LinePicker->Delete();
}

//----------------------------------------------------------------------
void vtkLineRepresentation::SetDirectionalLine(bool val)
{
  if (this->DirectionalLine == val)
  {
    return;
  }

  this->DirectionalLine = val;
  this->Modified();

  if (this->DirectionalLine)
  {
    vtkConeSource *cone = vtkConeSource::New();
    cone->SetResolution(16);
    this->HandleGeometry[1]->Delete();
    this->HandleGeometry[1] = cone;
  }
  else
  {
    vtkSphereSource *sphere = vtkSphereSource::New();
    sphere->SetThetaResolution(16);
    sphere->SetPhiResolution(8);
    this->HandleGeometry[1]->Delete();
    this->HandleGeometry[1] = sphere;
  }
  this->HandleMapper[1]->SetInputConnection(this->HandleGeometry[1]->GetOutputPort());
}

//----------------------------------------------------------------------
double vtkLineRepresentation::GetDistance()
{
  return this->Distance;
}

//----------------------------------------------------------------------
void vtkLineRepresentation::InstantiateHandleRepresentation()
{
  if ( ! this->Point1Representation )
  {
    this->Point1Representation = this->HandleRepresentation->NewInstance();
    this->Point1Representation->ShallowCopy(this->HandleRepresentation);
  }

  if ( ! this->Point2Representation )
  {
    this->Point2Representation = this->HandleRepresentation->NewInstance();
    this->Point2Representation->ShallowCopy(this->HandleRepresentation);
  }

  if ( ! this->LineHandleRepresentation )
  {
    this->LineHandleRepresentation = this->HandleRepresentation->NewInstance();
    this->LineHandleRepresentation->ShallowCopy(this->HandleRepresentation);
  }
}


//----------------------------------------------------------------------
void vtkLineRepresentation::SetResolution(int r)
{
  this->LineSource->SetResolution(r);
}

//----------------------------------------------------------------------
int vtkLineRepresentation::GetResolution()
{
  return this->LineSource->GetResolution();
}

//----------------------------------------------------------------------
void vtkLineRepresentation::GetPolyData(vtkPolyData *pd)
{
  pd->ShallowCopy(this->LineSource->GetOutput());
}

//-- Set/Get position of the three handles -----------------------------
// Point1
//----------------------------------------------------------------------
void vtkLineRepresentation::GetPoint1WorldPosition(double pos[3])
{
  this->Point1Representation->GetWorldPosition(pos);
}

double* vtkLineRepresentation::GetPoint1WorldPosition()
{
  return this->Point1Representation->GetWorldPosition();
}

//----------------------------------------------------------------------
void vtkLineRepresentation::GetPoint1DisplayPosition(double pos[3])
{
  this->Point1Representation->GetDisplayPosition(pos);
}

double* vtkLineRepresentation::GetPoint1DisplayPosition()
{
  return this->Point1Representation->GetDisplayPosition();
}

//----------------------------------------------------------------------
void vtkLineRepresentation::SetPoint1WorldPosition(double x[3])
{
  this->Point1Representation->SetWorldPosition(x);
  this->LineSource->SetPoint1(x);
  //double p[3];
  //this->Point1Representation->GetDisplayPosition(p);
  //this->Point1Representation->SetDisplayPosition(p);
}

//----------------------------------------------------------------------
void vtkLineRepresentation::SetPoint1DisplayPosition(double x[3])
{
  this->Point1Representation->SetDisplayPosition(x);
  double p[3];
  this->Point1Representation->GetWorldPosition(p);
  this->Point1Representation->SetWorldPosition(p);
}


// Point2
//----------------------------------------------------------------------
void vtkLineRepresentation::GetPoint2WorldPosition(double pos[3])
{
  this->Point2Representation->GetWorldPosition(pos);
}

double* vtkLineRepresentation::GetPoint2WorldPosition()
{
  return this->Point2Representation->GetWorldPosition();
}

//----------------------------------------------------------------------
void vtkLineRepresentation::GetPoint2DisplayPosition(double pos[3])
{
  this->Point2Representation->GetDisplayPosition(pos);
}

double* vtkLineRepresentation::GetPoint2DisplayPosition()
{
  return this->Point2Representation->GetDisplayPosition();
}

//----------------------------------------------------------------------
void vtkLineRepresentation::SetPoint2WorldPosition(double x[3])
{
  this->Point2Representation->SetWorldPosition(x);
  this->LineSource->SetPoint2(x);
  //double p[3];
  //this->Point2Representation->GetDisplayPosition(p);
  //this->Point2Representation->SetDisplayPosition(p);
}

//----------------------------------------------------------------------
void vtkLineRepresentation::SetPoint2DisplayPosition(double x[3])
{
  this->Point2Representation->SetDisplayPosition(x);
  double p[3];
  this->Point2Representation->GetWorldPosition(p);
  this->Point2Representation->SetWorldPosition(p);
}

//----------------------------------------------------------------------
void vtkLineRepresentation::SetRenderer(vtkRenderer* ren)
{
  this->HandleRepresentation->SetRenderer(ren);
  this->Point1Representation->SetRenderer(ren);
  this->Point2Representation->SetRenderer(ren);
  this->LineHandleRepresentation->SetRenderer(ren);
  this->Superclass::SetRenderer(ren);
}

//----------------------------------------------------------------------
void vtkLineRepresentation::StartWidgetInteraction(double e[2])
{
  // Store the start position
  this->StartEventPosition[0] = e[0];
  this->StartEventPosition[1] = e[1];
  this->StartEventPosition[2] = 0.0;

  // Store the start position
  this->LastEventPosition[0] = e[0];
  this->LastEventPosition[1] = e[1];
  this->LastEventPosition[2] = 0.0;

  // Get the coordinates of the three handles
  this->Point1Representation->GetWorldPosition(this->StartP1);
  this->Point2Representation->GetWorldPosition(this->StartP2);
  this->LineHandleRepresentation->GetWorldPosition(this->StartLineHandle);

  if ( this->InteractionState == vtkLineRepresentation::Scaling )
  {
    double dp1[3], dp2[3];
    this->Point1Representation->GetDisplayPosition(dp1);
    this->Point2Representation->GetDisplayPosition(dp2);
    this->Length = sqrt((dp1[0]-dp2[0])*(dp1[0]-dp2[0]) + (dp1[1]-dp2[1])*(dp1[1]-dp2[1]));
  }
}

//----------------------------------------------------------------------
void vtkLineRepresentation::WidgetInteraction(double e[2])
{
  // Process the motion
  if ( this->InteractionState == vtkLineRepresentation::OnP1 )
  {
    if (this->RestrictFlag)
    {
      double x[3];
      this->Point1Representation->GetWorldPosition(x);
      for (int i = 0; i < 3; ++i)
      {
        x[i] = (this->RestrictFlag == (i + 1)) ? x[i] : this->StartP1[i];
      }
      this->Point1Representation->SetWorldPosition(x);
    }
  }
  else if ( this->InteractionState == vtkLineRepresentation::OnP2 )
  {
    if (this->RestrictFlag)
    {
      double x[3];
      this->Point2Representation->GetWorldPosition(x);
      for (int i = 0; i < 3; ++i)
      {
        x[i] = (this->RestrictFlag == (i + 1)) ? x[i] : this->StartP2[i];
      }
      this->Point2Representation->SetWorldPosition(x);
    }
  }
  else if ( this->InteractionState == vtkLineRepresentation::OnLine )
  {
    double x[3], p1[3], p2[3], delta[3];

    // Get the new position
    this->LineHandleRepresentation->GetWorldPosition(x);

    // Compute the delta from the previous position
    delta[0] = x[0] - this->StartLineHandle[0];
    delta[1] = x[1] - this->StartLineHandle[1];
    delta[2] = x[2] - this->StartLineHandle[2];

    for (int i=0; i<3; i++)
    {
      double d = (!this->RestrictFlag || (this->RestrictFlag == (i + 1))) ?
                 delta[i] : 0.0;
      p1[i] = this->StartP1[i] + d;
      p2[i] = this->StartP2[i] + d;
    }

    this->Point1Representation->SetWorldPosition(p1);
    this->Point2Representation->SetWorldPosition(p2);
  }

  else if ( this->InteractionState == vtkLineRepresentation::Scaling )
  {//scale about the center of the widget
    double p1[3], p2[3], center[3];

    this->Point1Representation->GetWorldPosition(p1);
    this->Point2Representation->GetWorldPosition(p2);

    double delta = sqrt((this->StartEventPosition[0]-e[0])*(this->StartEventPosition[0]-e[0])+
                        (this->StartEventPosition[1]-e[1])*(this->StartEventPosition[1]-e[1]));

    double sf=1.0;
    if ( this->Length != 0.0 )
    {
      sf = 1.0 + delta/this->Length;
    }
    if ( (e[1]-this->LastEventPosition[1]) < 0.0 )
    {
      sf = 1/sf;
    }

    for (int i=0; i<3; i++)
    {
      center[i] = (p1[i]+p2[i]) / 2.0;
      p1[i] = center[i] + (p1[i]-center[i])*sf;
      p2[i] = center[i] + (p2[i]-center[i])*sf;
    }
    this->Point1Representation->SetWorldPosition(p1);
    this->Point2Representation->SetWorldPosition(p2);
  }

  else if ( this->InteractionState == vtkLineRepresentation::TranslatingP1 )
  {
    double x[3], p2[3];
    // Get the new position
    this->Point1Representation->GetWorldPosition(x);
    for (int i=0; i<3; i++)
    {
      p2[i] = this->StartP2[i] + (x[i] - this->StartP1[i]);
    }
    this->Point2Representation->SetWorldPosition(p2);
  }

  else if ( this->InteractionState == vtkLineRepresentation::TranslatingP2 )
  {
    double x[3], p1[3];
    // Get the new position
    this->Point2Representation->GetWorldPosition(x);
    for (int i=0; i<3; i++)
    {
      p1[i] = this->StartP1[i] + (x[i] - this->StartP2[i]);
    }
    this->Point1Representation->SetWorldPosition(p1);
  }

  // Store the start position
  this->LastEventPosition[0] = e[0];
  this->LastEventPosition[1] = e[1];
  this->LastEventPosition[2] = 0.0;
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::PlaceWidget(double bds[6])
{
  int i;
  double bounds[6], center[3];

  double placeFactor = this->PlaceFactor;
  this->PlaceFactor = 1.0;
  this->AdjustBounds(bds, bounds, center);
  this->PlaceFactor = placeFactor;

  for (i=0; i<6; i++)
  {
    this->InitialBounds[i] = bounds[i];
  }
  this->InitialLength = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
                             (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
                             (bounds[5]-bounds[4])*(bounds[5]-bounds[4]));

  // When PlaceWidget() is invoked, the widget orientation is preserved, but it
  // is allowed to translate and scale. This means it is centered in the
  // bounding box, and the representation scales itself to intersect the sides
  // of the bounding box. Thus we have to determine where Point1 and Point2
  // intersect the bounding box.
  double p1[3], p2[3], r[3], o[3], t, placedP1[3], placedP2[3];
  this->LineSource->GetPoint1(p1);
  this->LineSource->GetPoint2(p2);

  // Okay, this looks really weird, we are shooting rays from OUTSIDE
  // the bounding box back towards it. This is because the IntersectBox()
  // method computes intersections only if the ray originates outside the
  // bounding box.
  r[0] = this->InitialLength * (p1[0] - p2[0]);
  r[1] = this->InitialLength * (p1[1] - p2[1]);
  r[2] = this->InitialLength * (p1[2] - p2[2]);
  o[0] = center[0] - r[0];
  o[1] = center[1] - r[1];
  o[2] = center[2] - r[2];
  vtkBox::IntersectBox(bounds,o,r,placedP1,t);
  this->SetPoint1WorldPosition(placedP1);

  r[0] = this->InitialLength * (p2[0] - p1[0]);
  r[1] = this->InitialLength * (p2[1] - p1[1]);
  r[2] = this->InitialLength * (p2[2] - p1[2]);
  o[0] = center[0] - r[0];
  o[1] = center[1] - r[1];
  o[2] = center[2] - r[2];
  vtkBox::IntersectBox(bounds,o,r,placedP2,t);
  this->SetPoint2WorldPosition(placedP2);

  // Initialize the center point
  this->LineHandleRepresentation->SetWorldPosition(center);

  // Position the handles at the end of the lines
  this->Placed = 1;
  this->ValidPick = 1;
  this->BuildRepresentation();
}


//----------------------------------------------------------------------------
int vtkLineRepresentation::ComputeInteractionState(int X, int Y, int vtkNotUsed(modify))
{
  // Check if we are on end points. Use the handles to determine this.
  int p1State = this->Point1Representation->ComputeInteractionState(X,Y,0);
  int p2State = this->Point2Representation->ComputeInteractionState(X,Y,0);
  if ( p1State == vtkHandleRepresentation::Nearby )
  {
    this->InteractionState = vtkLineRepresentation::OnP1;
    this->SetRepresentationState(vtkLineRepresentation::OnP1);
  }
  else if ( p2State == vtkHandleRepresentation::Nearby )
  {
    this->InteractionState = vtkLineRepresentation::OnP2;
    this->SetRepresentationState(vtkLineRepresentation::OnP2);
  }
  else
  {
    this->InteractionState = vtkLineRepresentation::Outside;
  }

  // Okay if we're near a handle return, otherwise test the line
  if ( this->InteractionState != vtkLineRepresentation::Outside )
  {
    return this->InteractionState;
  }

  // Check if we are on edges
  double pos1[3], pos2[3];
  this->GetPoint1DisplayPosition(pos1);
  this->GetPoint2DisplayPosition(pos2);

  double p1[3], p2[3], xyz[3];
  double t, closest[3];
  xyz[0] = static_cast<double>(X);
  xyz[1] = static_cast<double>(Y);
  p1[0] = static_cast<double>(pos1[0]);
  p1[1] = static_cast<double>(pos1[1]);
  p2[0] = static_cast<double>(pos2[0]);
  p2[1] = static_cast<double>(pos2[1]);
  xyz[2] = p1[2] = p2[2] = 0.0;

  double tol2 = this->Tolerance*this->Tolerance;

  int onLine = (vtkLine::DistanceToLine(xyz,p1,p2,t,closest) <= tol2);
  if ( onLine && t < 1.0 && t > 0.0 )
  {
    this->InteractionState = vtkLineRepresentation::OnLine;
    this->SetRepresentationState(vtkLineRepresentation::OnLine);
    this->GetPoint1WorldPosition(pos1);
    this->GetPoint2WorldPosition(pos2);

    this->LinePicker->Pick(X,Y,0.0,this->Renderer);
    this->LinePicker->GetPickPosition(closest);
    this->LineHandleRepresentation->SetWorldPosition(closest);
  }
  else
  {
    this->InteractionState = vtkLineRepresentation::Outside;
    this->SetRepresentationState(vtkLineRepresentation::Outside);
  }

  return this->InteractionState;
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::SetRepresentationState(int state)
{
  if (this->RepresentationState == state)
  {
    return;
  }

  state = (state < vtkLineRepresentation::Outside ?
           vtkLineRepresentation::Outside :
           (state > vtkLineRepresentation::Scaling ?
            vtkLineRepresentation::Scaling : state));

  this->RepresentationState = state;
  this->Modified();

  if ( state == vtkLineRepresentation::Outside )
  {
    this->HighlightPoint(0,0);
    this->HighlightPoint(1,0);
    this->HighlightLine(0);
  }
  else if ( state == vtkLineRepresentation::OnP1 )
  {
    this->HighlightPoint(0,1);
    this->HighlightPoint(1,0);
    this->HighlightLine(0);
  }
  else if ( state == vtkLineRepresentation::OnP2 )
  {
    this->HighlightPoint(0,0);
    this->HighlightPoint(1,1);
    this->HighlightLine(0);
  }
  else if ( state == vtkLineRepresentation::OnLine )
  {
    this->HighlightPoint(0,0);
    this->HighlightPoint(1,0);
    this->HighlightLine(1);
  }
  else
  {
    this->HighlightPoint(0,1);
    this->HighlightPoint(1,1);
    this->HighlightLine(1);
  }
}

//----------------------------------------------------------------------
double *vtkLineRepresentation::GetBounds()
{
  this->BuildRepresentation();
  this->BoundingBox->SetBounds(this->LineActor->GetBounds());
  this->BoundingBox->AddBounds(this->Handle[0]->GetBounds());
  this->BoundingBox->AddBounds(this->Handle[1]->GetBounds());

  return this->BoundingBox->GetBounds();
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::CreateDefaultProperties()
{
  // Endpoint properties
  this->EndPointProperty = vtkProperty::New();
  this->EndPointProperty->SetColor(1,1,1);

  this->SelectedEndPointProperty = vtkProperty::New();
  this->SelectedEndPointProperty->SetColor(0,1,0);

  this->EndPoint2Property = vtkProperty::New();
  this->EndPoint2Property->SetColor(1,1,1);

  this->SelectedEndPoint2Property = vtkProperty::New();
  this->SelectedEndPoint2Property->SetColor(0,1,0);

  // Line properties
  this->LineProperty = vtkProperty::New();
  this->LineProperty->SetAmbient(1.0);
  this->LineProperty->SetAmbientColor(1.0,1.0,1.0);
  this->LineProperty->SetLineWidth(2.0);

  this->SelectedLineProperty = vtkProperty::New();
  this->SelectedLineProperty->SetAmbient(1.0);
  this->SelectedLineProperty->SetAmbientColor(0.0,1.0,0.0);
  this->SelectedLineProperty->SetLineWidth(2.0);
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::SizeHandles()
{
  // The SizeHandles() method depends on the LastPickPosition data member.
  double radius = this->vtkWidgetRepresentation::SizeHandlesInPixels(1.35,this->LineSource->GetPoint1());
  static_cast<vtkSphereSource*>(this->HandleGeometry[0])->SetRadius(radius);

  radius = this->vtkWidgetRepresentation::SizeHandlesInPixels(1.35,this->LineSource->GetPoint2());
  if (this->DirectionalLine)
  {
    static_cast<vtkConeSource*>(this->HandleGeometry[1])->SetRadius(radius);
    static_cast<vtkConeSource*>(this->HandleGeometry[1])->SetHeight(2.8 * radius);
  }
  else
  {
    static_cast<vtkSphereSource*>(this->HandleGeometry[1])->SetRadius(radius);
  }
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::BuildRepresentation()
{
  // Rebuild only if necessary
  if ( this->GetMTime() > this->BuildTime ||
       this->Point1Representation->GetMTime() > this->BuildTime ||
       this->Point2Representation->GetMTime() > this->BuildTime ||
       this->LineHandleRepresentation->GetMTime() > this->BuildTime ||
       (this->Renderer && this->Renderer->GetVTKWindow() &&
        (this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime ||
        this->Renderer->GetActiveCamera()->GetMTime() > this->BuildTime)) )
  {
    if ( ! this->InitializedDisplayPosition && this->Renderer )
    {
      this->SetPoint1WorldPosition(this->LineSource->GetPoint1());
      this->SetPoint2WorldPosition(this->LineSource->GetPoint2());
      this->ValidPick = 1;
      this->InitializedDisplayPosition = 1;
    }

    // Make sure that tolerance is consistent between handles and this representation
    this->Point1Representation->SetTolerance(this->Tolerance);
    this->Point2Representation->SetTolerance(this->Tolerance);
    this->LineHandleRepresentation->SetTolerance(this->Tolerance);

    // Retrieve end point information
    double x1[3], x2[3];
    this->GetPoint1WorldPosition(x1);

    this->LineSource->SetPoint1(x1);
    static_cast<vtkSphereSource*>(this->HandleGeometry[0])->SetCenter(x1);

    this->GetPoint2WorldPosition(x2);
    this->LineSource->SetPoint2(x2);
    if (this->DirectionalLine)
    {
      static_cast<vtkConeSource*>(this->HandleGeometry[1])->SetCenter(x2);
      vtkVector3d dir(x2);
      dir = dir - vtkVector3d(x1);
      static_cast<vtkConeSource*>(this->HandleGeometry[1])->SetDirection(dir.GetData());
    }
    else
    {
      static_cast<vtkSphereSource*>(this->HandleGeometry[1])->SetCenter(x2);
    }

    this->Distance = sqrt(vtkMath::Distance2BetweenPoints( x1, x2 ));

    // Place the DistanceAnnotation right in between the two points.
    double x[3] = { (x1[0] + x2[0])/2.0,
                    (x1[1] + x2[1])/2.0,
                    (x1[2] + x2[2])/2.0 };
    char string[512];
    snprintf(string, sizeof(string), this->DistanceAnnotationFormat, this->Distance);
    this->TextInput->SetText( string );
    this->TextActor->SetPosition( x );
    if (this->Renderer)
    {
      this->TextActor->SetCamera( this->Renderer->GetActiveCamera() );
    }

    if (!this->AnnotationTextScaleInitialized)
    {
      // If a font size hasn't been specified by the user, scale the text
      // (font size) according to the length of the line widget.
      this->TextActor->SetScale(
          this->Distance/10.0, this->Distance/10.0, this->Distance/10.0 );
    }

    this->SizeHandles();
    this->BuildTime.Modified();
  }
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::HighlightPoint(int ptId, int highlight)
{
  if ( ptId == 0 )
  {
    if ( highlight )
    {
      this->Handle[0]->SetProperty(this->SelectedEndPointProperty);
      this->Point1Representation->SetSelectedProperty(this->SelectedEndPointProperty);
    }
    else
    {
      this->Handle[0]->SetProperty(this->EndPointProperty);
      this->Point1Representation->SetProperty(this->EndPointProperty);
    }
  }
  else if ( ptId == 1 )
  {
    if ( highlight )
    {
      this->Handle[1]->SetProperty(this->SelectedEndPoint2Property);
      this->Point2Representation->SetSelectedProperty(this->SelectedEndPoint2Property);
    }
    else
    {
      this->Handle[1]->SetProperty(this->EndPoint2Property);
      this->Point2Representation->SetProperty(this->EndPoint2Property);
    }
  }
  else //if ( ptId == 2 )
  {
    if ( highlight )
    {
      this->LineHandleRepresentation->SetSelectedProperty(this->SelectedEndPointProperty);
    }
    else
    {
      this->LineHandleRepresentation->SetProperty(this->EndPointProperty);
    }
  }
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::HighlightLine(int highlight)
{
  if ( highlight )
  {
    this->LineActor->SetProperty(this->SelectedLineProperty);
  }
  else
  {
    this->LineActor->SetProperty(this->LineProperty);
  }
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::SetLineColor(double r, double g, double b)
{
  if(this->GetLineProperty())
  {
    this->GetLineProperty()->SetColor(r, g, b);
  }
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::ClampPosition(double x[3])
{
  for (int i=0; i<3; i++)
  {
    if ( x[i] < this->InitialBounds[2*i] )
    {
      x[i] = this->InitialBounds[2*i];
    }
    if ( x[i] > this->InitialBounds[2*i+1] )
    {
      x[i] = this->InitialBounds[2*i+1];
    }
  }
}

//----------------------------------------------------------------------------
int vtkLineRepresentation::InBounds(double x[3])
{
  for (int i=0; i<3; i++)
  {
    if ( x[i] < this->InitialBounds[2*i] ||
         x[i] > this->InitialBounds[2*i+1] )
    {
      return 0;
    }
  }
  return 1;
}

//----------------------------------------------------------------------
void vtkLineRepresentation::GetActors(vtkPropCollection *pc)
{
  this->LineActor->GetActors(pc);
  this->Handle[0]->GetActors(pc);
  this->Handle[1]->GetActors(pc);
  this->TextActor->GetActors(pc);
}

//----------------------------------------------------------------------------
void vtkLineRepresentation::ReleaseGraphicsResources(vtkWindow *w)
{
  this->LineActor->ReleaseGraphicsResources(w);
  this->Handle[0]->ReleaseGraphicsResources(w);
  this->Handle[1]->ReleaseGraphicsResources(w);
  this->TextActor->ReleaseGraphicsResources(w);
}

//----------------------------------------------------------------------------
int vtkLineRepresentation::RenderOpaqueGeometry(vtkViewport *v)
{
  int count=0;
  this->BuildRepresentation();
  count += this->LineActor->RenderOpaqueGeometry(v);
  count += this->Handle[0]->RenderOpaqueGeometry(v);
  count += this->Handle[1]->RenderOpaqueGeometry(v);
  if (this->DistanceAnnotationVisibility)
  {
    count += this->TextActor->RenderOpaqueGeometry(v);
  }

  return count;
}

//----------------------------------------------------------------------------
int vtkLineRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport *v)
{
  int count=0;
  this->BuildRepresentation();
  count += this->LineActor->RenderTranslucentPolygonalGeometry(v);
  count += this->Handle[0]->RenderTranslucentPolygonalGeometry(v);
  count += this->Handle[1]->RenderTranslucentPolygonalGeometry(v);
  if (this->DistanceAnnotationVisibility)
  {
    count += this->TextActor->RenderTranslucentPolygonalGeometry(v);
  }

  return count;
}

//----------------------------------------------------------------------------
int vtkLineRepresentation::HasTranslucentPolygonalGeometry()
{
  int result=0;
  this->BuildRepresentation();
  result |= this->LineActor->HasTranslucentPolygonalGeometry();
  result |= this->Handle[0]->HasTranslucentPolygonalGeometry();
  result |= this->Handle[1]->HasTranslucentPolygonalGeometry();
  if (this->DistanceAnnotationVisibility)
  {
    result |= this->TextActor->HasTranslucentPolygonalGeometry();
  }

  return result;
}

//----------------------------------------------------------------------------
vtkMTimeType vtkLineRepresentation::GetMTime()
{
  vtkMTimeType mTime=this->Superclass::GetMTime();
  vtkMTimeType mTime2=this->Point1Representation->GetMTime();
  mTime = ( mTime2 > mTime ? mTime2 : mTime );
  mTime2=this->Point2Representation->GetMTime();
  mTime = ( mTime2 > mTime ? mTime2 : mTime );
  mTime2=this->LineHandleRepresentation->GetMTime();
  mTime = ( mTime2 > mTime ? mTime2 : mTime );

  return mTime;
}

//----------------------------------------------------------------------
void vtkLineRepresentation::SetDistanceAnnotationScale( double scale[3] )
{
  this->TextActor->SetScale( scale );
  this->AnnotationTextScaleInitialized = true;
}

//----------------------------------------------------------------------
double * vtkLineRepresentation::GetDistanceAnnotationScale()
{
  return this->TextActor->GetScale();
}

//----------------------------------------------------------------------------
vtkProperty * vtkLineRepresentation::GetDistanceAnnotationProperty()
{
  return this->TextActor->GetProperty();
}

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

  if ( this->LineProperty )
  {
    os << indent << "Line Property: " << this->LineProperty << "\n";
  }
  else
  {
    os << indent << "Line Property: (none)\n";
  }
  if ( this->SelectedLineProperty )
  {
    os << indent << "Selected Line Property: "
       << this->SelectedLineProperty << "\n";
  }
  else
  {
    os << indent << "Selected Line Property: (none)\n";
  }

  if ( this->EndPointProperty )
  {
    os << indent << "End Point Property: " << this->EndPointProperty << "\n";
  }
  else
  {
    os << indent << "End Point Property: (none)\n";
  }
  if ( this->SelectedEndPointProperty )
  {
    os << indent << "Selected End Point Property: " << this->SelectedEndPointProperty << "\n";
  }
  else
  {
    os << indent << "Selected End Point Property: (none)\n";
  }

  if ( this->EndPoint2Property )
  {
    os << indent << "End Point Property: " << this->EndPoint2Property << "\n";
  }
  else
  {
    os << indent << "End Point Property: (none)\n";
  }
  if ( this->SelectedEndPoint2Property )
  {
    os << indent << "Selected End Point Property: " << this->SelectedEndPoint2Property << "\n";
  }
  else
  {
    os << indent << "Selected End Point Property: (none)\n";
  }

  os << indent << "Tolerance: " << this->Tolerance << "\n";

  os << indent << "Constrain To Bounds: "
     << (this->ClampToBounds ? "On\n" : "Off\n");

  int res = this->LineSource->GetResolution();
  double *pt1 = this->LineSource->GetPoint1();
  double *pt2 = this->LineSource->GetPoint2();

  os << indent << "Resolution: " << res << "\n";
  os << indent << "Point 1: (" << pt1[0] << ", "
                               << pt1[1] << ", "
                               << pt1[2] << ")\n";
  os << indent << "Point 2: (" << pt2[0] << ", "
                               << pt2[1] << ", "
                               << pt2[2] << ")\n";

  os << indent << "Point1 Representation: ";
  this->Point1Representation->PrintSelf(os,indent.GetNextIndent());

  os << indent << "Point2 Representation: ";
  this->Point2Representation->PrintSelf(os,indent.GetNextIndent());

  os << indent << "Line Handle Representation: ";
  this->LineHandleRepresentation->PrintSelf(os,indent.GetNextIndent());

  os << indent << "Representation State: " << this->RepresentationState << "\n";
  os << indent << "Directional Line: " << this->DirectionalLine << "\n";
  os << indent << "Restring flag: ";
  switch (this->RestrictFlag)
  {
    case RestrictNone:
      os << "RestrictNone";
      break;
    case RestrictToX:
      os << "RestrictToX";
      break;
    case RestrictToY:
      os << "RestrictToY";
      break;
    case RestrictToZ:
      os << "RestrictToZ";
      break;
    default:
      os << "unexpected value: " << this->RestrictFlag;
      break;
  }
  os << "\n";

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

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

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

  // this->InteractionState is printed in superclass
  // this is commented to avoid PrintSelf errors
}



