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

  Program:   Visualization Toolkit
  Module:    vtkLeaderActor2D.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 "vtkLeaderActor2D.h"

#include "vtkPoints.h"
#include "vtkCellArray.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper2D.h"
#include "vtkTextMapper.h"
#include "vtkTextProperty.h"
#include "vtkViewport.h"
#include "vtkWindow.h"
#include "vtkObjectFactory.h"
#include "vtkMath.h"

vtkStandardNewMacro(vtkLeaderActor2D);

vtkCxxSetObjectMacro(vtkLeaderActor2D,LabelTextProperty,vtkTextProperty);


//----------------------------------------------------------------------------
// Instantiate this object.
vtkLeaderActor2D::vtkLeaderActor2D()
{
  this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport();
  this->PositionCoordinate->SetValue(0.0, 0.0);

  this->Position2Coordinate->SetCoordinateSystemToNormalizedViewport();
  this->Position2Coordinate->SetValue(0.75, 0.75);
  this->Position2Coordinate->SetReferenceCoordinate(nullptr);

  this->Radius = 0.0;
  this->Length = 0.0;
  this->Angle = 0.0;

  this->Label = nullptr;
  this->LabelFactor = 1.0;
  this->AutoLabel = 0;
  this->LabelFormat = new char[8];
  snprintf(this->LabelFormat,8,"%s","%-#6.3g");

  this->ArrowPlacement = vtkLeaderActor2D::VTK_ARROW_BOTH;
  this->ArrowStyle = vtkLeaderActor2D::VTK_ARROW_FILLED;
  this->ArrowLength = 0.04;
  this->ArrowWidth = 0.02;
  this->MinimumArrowSize = 2;
  this->MaximumArrowSize = 25;

  this->LabelTextProperty = vtkTextProperty::New();
  this->LabelTextProperty->SetBold(1);
  this->LabelTextProperty->SetItalic(1);
  this->LabelTextProperty->SetShadow(1);
  this->LabelTextProperty->SetFontFamilyToArial();
  this->LabelTextProperty->SetJustificationToCentered();
  this->LabelTextProperty->SetVerticalJustificationToCentered();

  this->LabelMapper = vtkTextMapper::New();
  this->LabelActor = vtkActor2D::New();
  this->LabelActor->SetMapper(this->LabelMapper);

  // Points 0-3 are the side1 of the arrow; Points 4-7 are the side2 of the arrow.
  this->LeaderPoints = vtkPoints::New();

  this->LeaderLines = vtkCellArray::New();
  this->LeaderLines->EstimateSize(1,2);

  this->LeaderArrows = vtkCellArray::New();
  this->LeaderArrows->EstimateSize(2,3);

  this->Leader = vtkPolyData::New();
  this->Leader->SetPoints(this->LeaderPoints);
  this->Leader->SetLines(this->LeaderLines);
  this->Leader->SetPolys(this->LeaderArrows);

  this->LeaderMapper = vtkPolyDataMapper2D::New();
  this->LeaderMapper->SetInputData(this->Leader);
  this->LeaderActor = vtkActor2D::New();
  this->LeaderActor->SetMapper(this->LeaderMapper);

  this->LastPosition[0] = this->LastPosition[1] = 0;
  this->LastPosition2[0] = this->LastPosition2[1] = 0;
  this->LastSize[0] = this->LastSize[1] = 0;
}

//----------------------------------------------------------------------------
vtkLeaderActor2D::~vtkLeaderActor2D()
{
  this->LabelMapper->Delete();
  this->LabelActor->Delete();

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

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

  this->LeaderPoints->Delete();
  this->LeaderLines->Delete();
  this->LeaderArrows->Delete();
  this->Leader->Delete();
  this->LeaderMapper->Delete();
  this->LeaderActor->Delete();

  this->SetLabelTextProperty(nullptr);
}

//----------------------------------------------------------------------------
void vtkLeaderActor2D::BuildLeader(vtkViewport *viewport)
{
  // Check to see whether we need to rebuild-----------------------------
  int positionsHaveChanged = 0;
  if (viewport->GetMTime() > this->BuildTime ||
      (viewport->GetVTKWindow() && viewport->GetVTKWindow()->GetMTime() > this->BuildTime))
  {
    int *lastPosition = this->PositionCoordinate->GetComputedViewportValue(viewport);
    int *lastPosition2 = this->Position2Coordinate->GetComputedViewportValue(viewport);
    if (lastPosition[0] != this->LastPosition[0] ||
        lastPosition[1] != this->LastPosition[1] ||
        lastPosition2[0] != this->LastPosition2[0] ||
        lastPosition2[1] != this->LastPosition2[1] )
    {
      positionsHaveChanged = 1;
    }
  }

  int *size = viewport->GetSize();
  int viewportSizeHasChanged=0;
  // See whether fonts have to be rebuilt (font size depends on viewport size)
  if (this->LastSize[0] != size[0] || this->LastSize[1] != size[1])
  {
    viewportSizeHasChanged = 1;
    this->LastSize[0] = size[0];
    this->LastSize[1] = size[1];
  }

  if (!positionsHaveChanged && !viewportSizeHasChanged &&
      this->GetMTime() < this->BuildTime &&
      this->LabelTextProperty->GetMTime() < this->BuildTime )
  {
    return;
  }

  // Okay, we have some work to do. We build the leader in three parts:
  // 1) the line connecting the two points, 2) the text label, and 3) the
  // arrow head(s) if any.
  vtkDebugMacro(<<"Rebuilding leader"); //---------------------------------

  // Initialize the data
  this->LeaderPoints->Initialize();
  this->LeaderLines->Initialize();
  this->LeaderArrows->Initialize();
  this->LeaderActor->SetProperty(this->GetProperty());
  this->LabelMapper->SetTextProperty(this->LabelTextProperty);

  // The easiest part is determining the two end points of the line.
  double p1[3], p2[3], ray[3];
  int *x = this->PositionCoordinate->GetComputedViewportValue(viewport);
  p1[0] = static_cast<double>(x[0]);
  p1[1] = static_cast<double>(x[1]);
  p1[2] = 0.0;
  this->LastPosition[0] = x[0];
  this->LastPosition[1] = x[1];

  x = this->Position2Coordinate->GetComputedViewportValue(viewport);
  p2[0] = static_cast<double>(x[0]);
  p2[1] = static_cast<double>(x[1]);
  p2[2] = 0.0;
  this->LastPosition2[0] = x[0];
  this->LastPosition2[1] = x[1];

  ray[0] = p2[0] - p1[0];
  ray[1] = p2[1] - p1[1];
  ray[2] = 0.0;
  double rayLength = vtkMath::Norm(ray);
  if ( rayLength <= 0.0 )
  {
    return;
  }

  double theta, theta2;
  if (ray[0] == 0. && ray[1] == 0.)
  {
    theta = 0.;
  }
  else
  {
    theta = atan2(ray[1], ray[0]);
  }
  theta2 = theta + vtkMath::Pi();

  // If there is a suitable radius then a curved leader must be created.
  // Remember the radius is expresses as a factor times the distance between (p1,p2).
  if ( fabs(this->Radius) > 0.5 )
  {
    this->BuildCurvedLeader(p1,p2,ray,rayLength,theta,viewport,viewportSizeHasChanged);
    return;
  }

  // Okay, we can continue building the straight leader--------------------------
  this->LeaderPoints->SetNumberOfPoints(8);
  this->LeaderPoints->SetPoint(0,p1);
  this->LeaderPoints->SetPoint(4,p2);
  this->LeaderPoints->Modified();

  // Build the labels
  int i, clippedLeader=0;
  double xL[3], xR[3], c1[3], c2[3];
  double *x1 = this->PositionCoordinate->GetComputedWorldValue(viewport);
  double *x2 = this->Position2Coordinate->GetComputedWorldValue(viewport);
  this->Length = sqrt(vtkMath::Distance2BetweenPoints(x1,x2));

  if ( this->AutoLabel || (this->Label != nullptr && this->Label[0] != 0) )
  {
    int stringSize[2];
    if ( this->AutoLabel )
    {
      char string[512];
      snprintf(string, sizeof(string), this->LabelFormat, this->Length);
      this->LabelMapper->SetInput(string);
    }
    else
    {
      this->LabelMapper->SetInput(this->Label);
    }

    if (this->LabelTextProperty->GetMTime() > this->BuildTime)
    {
      this->LabelMapper->GetTextProperty()->ShallowCopy(this->LabelTextProperty);
    }

    if (viewportSizeHasChanged || this->LabelTextProperty->GetMTime() > this->BuildTime)
    {
      this->SetFontSize(viewport, this->LabelMapper, size, this->LabelFactor, stringSize);
    }
    else
    {
      this->LabelMapper->GetSize(viewport, stringSize);
    }
    for (i=0; i<3; i++)
    {
      xL[i] = p1[i] + 0.5*ray[i];
    }

    // Now clip the leader with the label box
    if ( (clippedLeader=this->ClipLeader(xL,stringSize,p1,ray,c1,c2)) )
    {
      this->LabelActor->SetPosition(xL[0],xL[1]);
      this->LeaderPoints->SetPoint(3,c1);
      this->LeaderPoints->SetPoint(7,c2);
    }
    else //we cannot fit the text in the leader, it has to be placed next to the leader
    {
      double w = static_cast<double>(stringSize[0])/2.0;
      double h = static_cast<double>(stringSize[1])/2.0;
      double r = sqrt(h*h+w*w);
      xL[0] = xL[0] + r*sin(theta);
      xL[1] = xL[1] - r*cos(theta);
      this->LabelActor->SetPosition(xL[0],xL[1]);
    }
  } // If label visible

  if ( !clippedLeader )
  { //we just draw a single line across 'cause there is no label in the leader
    this->LeaderLines->InsertNextCell(2);
    this->LeaderLines->InsertCellPoint(0);
    this->LeaderLines->InsertCellPoint(4);
  }
  else
  { //draw two lines separated by label
    this->LeaderLines->InsertNextCell(2);
    this->LeaderLines->InsertCellPoint(0);
    this->LeaderLines->InsertCellPoint(3);
    this->LeaderLines->InsertNextCell(2);
    this->LeaderLines->InsertCellPoint(4);
    this->LeaderLines->InsertCellPoint(7);
  }

  // Build the arrows---------------------------------------
  if ( this->ArrowPlacement == vtkLeaderActor2D::VTK_ARROW_NONE )
  {
    ; //do nothin
  }
  else //we are creating arrows
  {
    this->Leader->Modified();
    // Convert width and length to viewport (pixel) coordinates
    double dist = sqrt(static_cast<double>(size[0]*size[0] + size[1]*size[1]));
    double width = this->ArrowWidth * dist / 2.0;
    double length = this->ArrowLength * dist;
    if ( length < width && length < this->MinimumArrowSize )
    {
      width = this->MinimumArrowSize*width/length;
      length = this->MinimumArrowSize;
    }
    else if ( width < length && width < this->MinimumArrowSize )
    {
      length = this->MinimumArrowSize*length/width;
      width = this->MinimumArrowSize;
    }
    if ( length > width && length > this->MaximumArrowSize )
    {
      width = this->MaximumArrowSize*width/length;
      length = this->MaximumArrowSize;
    }
    else if ( width > length && width > this->MaximumArrowSize )
    {
      length = this->MaximumArrowSize*length/width;
      width = this->MaximumArrowSize;
    }

    // Find the position along the line for the arrows and create the additional points
    double a1[3], a2[3];
    for (i=0; i<3; i++)
    {
      a1[i] = p1[i] + (length/rayLength)*ray[i];
      a2[i] = p1[i] + (1.0-(length/rayLength))*ray[i];
    }
    if ( this->ArrowPlacement == vtkLeaderActor2D::VTK_ARROW_POINT1 ||
         this->ArrowPlacement == vtkLeaderActor2D::VTK_ARROW_BOTH )
    {
      xL[0] = a1[0] + width*sin(theta);
      xL[1] = a1[1] - width*cos(theta);
      xR[0] = a1[0] + width*sin(theta2);
      xR[1] = a1[1] - width*cos(theta2);
      xR[2] = xL[2] = 0.0;

      this->LeaderPoints->SetPoint(1,xL);
      this->LeaderPoints->SetPoint(2,xR);
      if ( this->ArrowStyle == vtkLeaderActor2D::VTK_ARROW_FILLED )
      {
        this->LeaderArrows->InsertNextCell(3);
        this->LeaderArrows->InsertCellPoint(0);
        this->LeaderArrows->InsertCellPoint(1);
        this->LeaderArrows->InsertCellPoint(2);
      }
      else if ( this->ArrowStyle == vtkLeaderActor2D::VTK_ARROW_OPEN )
      {
        this->LeaderLines->InsertNextCell(3);
        this->LeaderLines->InsertCellPoint(1);
        this->LeaderLines->InsertCellPoint(0);
        this->LeaderLines->InsertCellPoint(2);
      }
      else //if ( this->ArrowStyle == vtkLeaderActor2D::VTK_ARROW_HOLLOW )
      {
        this->LeaderLines->InsertNextCell(4);
        this->LeaderLines->InsertCellPoint(1);
        this->LeaderLines->InsertCellPoint(0);
        this->LeaderLines->InsertCellPoint(2);
        this->LeaderLines->InsertCellPoint(1);
      }
    }
    if ( this->ArrowPlacement == vtkLeaderActor2D::VTK_ARROW_POINT2 ||
         this->ArrowPlacement == vtkLeaderActor2D::VTK_ARROW_BOTH )
    {
      xL[0] = a2[0] + width*sin(theta);
      xL[1] = a2[1] - width*cos(theta);
      xR[0] = a2[0] + width*sin(theta2);
      xR[1] = a2[1] - width*cos(theta2);
      xR[2] = xL[2] = 0.0;

      this->LeaderPoints->SetPoint(5,xL);
      this->LeaderPoints->SetPoint(6,xR);
      if ( this->ArrowStyle == vtkLeaderActor2D::VTK_ARROW_FILLED )
      {
        this->LeaderArrows->InsertNextCell(3);
        this->LeaderArrows->InsertCellPoint(4);
        this->LeaderArrows->InsertCellPoint(5);
        this->LeaderArrows->InsertCellPoint(6);
      }
      else if ( this->ArrowStyle == vtkLeaderActor2D::VTK_ARROW_OPEN )
      {
        this->LeaderLines->InsertNextCell(3);
        this->LeaderLines->InsertCellPoint(5);
        this->LeaderLines->InsertCellPoint(4);
        this->LeaderLines->InsertCellPoint(6);
      }
      else //if ( this->ArrowStyle == vtkLeaderActor2D::VTK_ARROW_HOLLOW )
      {
        this->LeaderLines->InsertNextCell(4);
        this->LeaderLines->InsertCellPoint(5);
        this->LeaderLines->InsertCellPoint(4);
        this->LeaderLines->InsertCellPoint(6);
        this->LeaderLines->InsertCellPoint(5);
      }
    }
  } //creating arrows


  this->BuildTime.Modified();
}

//----------------------------------------------------------------------------
#define VTK_LA2D_FACTOR 0.015
int vtkLeaderActor2D::SetFontSize(vtkViewport *viewport, vtkTextMapper *textMapper,
                                  int *targetSize, double factor, int *stringSize)
{
  int fontSize, targetWidth, targetHeight;

  targetWidth = targetSize[0] > targetSize[1] ? targetSize[0] : targetSize[1];
  targetHeight = static_cast<int>(VTK_LA2D_FACTOR * factor * targetSize[0] +
                                  VTK_LA2D_FACTOR * factor * targetSize[1]);

  fontSize = textMapper->SetConstrainedFontSize(viewport, targetWidth, targetHeight);
  textMapper->GetSize(viewport, stringSize);

  return fontSize;
}
#undef VTK_LA2D_FACTOR


//----------------------------------------------------------------------------
int vtkLeaderActor2D::ClipLeader(double center[3], int box[2], double p1[3],
                                 double ray[3], double c1[3], double c2[3])
{
  // Separately compute the parametric coordintes due to x-line and y-line
  // intersections. Take the coordinate closest to the center of the line.
  double tx, ty, t;
  double x = center[0] + box[0];
  double y = center[1] + box[1];

  // x-line
  if ( ray[0] != 0.0 )
  {
    tx = (x - p1[0])/ray[0];
  }
  else
  {
    tx = VTK_FLOAT_MAX;
  }

  // y-line
  if ( ray[1] != 0.0 )
  {
    ty = (y - p1[1])/ray[1];
  }
  else
  {
    ty = VTK_FLOAT_MAX;
  }

  // Find the closest intersection point nearest the center of the box
  t = ( fabs(tx-0.5) < fabs(ty-0.5) ? tx : ty );
  if ( fabs(t-0.5) > 0.45 )
  {
    return 0; //won't fit along line
  }
  else
  {
    t = ( t>0.5 ? t : 1.0-t); //make sure t is to the right of the midpoint
    for (int i=0; i<3; i++)
    {
      c1[i] = p1[i] + (1.0-t)*ray[i];
      c2[i] = p1[i] +       t*ray[i];
    }
    return 1;
  }
}

//----------------------------------------------------------------------------
void vtkLeaderActor2D::BuildCurvedLeader(double p1[3], double p2[3], double ray[3],
                                         double rayLength, double theta,
                                         vtkViewport *viewport, int viewportChanged)
{
  // Determine where the center is
  double radius = fabs(this->Radius)*rayLength;
  double midPoint[3], center[3];
  int i;
  midPoint[0] = p1[0] + 0.5*ray[0];
  midPoint[1] = p1[1] + 0.5*ray[1];
  midPoint[2] = p1[2] + 0.5*ray[2];
  double d = sqrt(radius*radius - rayLength*rayLength/4.0);
  if ( this->Radius > 0 )
  {
    center[0] = midPoint[0] + d*sin(theta);
    center[1] = midPoint[1] - d*cos(theta);
    center[2] = 0.0;
  }
  else
  {
    center[0] = midPoint[0] - d*sin(theta);
    center[1] = midPoint[1] + d*cos(theta);
    center[2] = 0.0;
  }

  // Compute some angles; make sure they are <= 180 degrees
  double phi = atan2(rayLength/2.0,d);
  double theta1 = atan2(p1[1]-center[1],p1[0]-center[0]);
  double theta2 = atan2(p2[1]-center[1],p2[0]-center[0]);
  if ( (theta1 >= 0.0 && theta1 <= vtkMath::Pi() &&
        theta2 >= 0.0 && theta2 <= vtkMath::Pi()) ||
       (theta1 <= 0.0 && theta1 >= -vtkMath::Pi() &&
        theta2 <= 0.0 && theta2 >= -vtkMath::Pi()) )
  {
    ; //do nothin angles are fine
  }
  else if ( theta1 >= 0.0 && theta2 <= 0.0 )
  {
    if ( (theta1 - theta2) >= vtkMath::Pi() )
    {
      theta2 = theta2 + 2.0*vtkMath::Pi();
    }
  }
  else //if ( theta1 <= 0.0 && theta2 >= 0.0 )
  {
    if ( (theta2 - theta1) >= vtkMath::Pi() )
    {
      theta1 = theta1 + 2.0*vtkMath::Pi();
    }
  }

  // Build the polyline for the leader. Start by generating the points.
  double x[3]; x[2]=0.0;
  double length = radius*phi;
  int numDivs = static_cast<int>((length / 3.0) + 1); //every three pixels
  for (i=0; i<=numDivs; i++)
  {
    theta = theta1 + (static_cast<double>(i)/numDivs)*(theta2-theta1);
    x[0] = center[0] + radius*cos(theta);
    x[1] = center[1] + radius*sin(theta);
    this->LeaderPoints->InsertPoint(i,x);
  }

  // Now insert lines. Only those not clipped by the string are added.
  this->Angle = vtkMath::DegreesFromRadians( theta1 - theta2);
  if ( this->AutoLabel || (this->Label != nullptr && this->Label[0] != 0) )
  {
    int stringSize[2];
    if ( this->AutoLabel )
    {
      char string[512];
      snprintf(string, sizeof(string), this->LabelFormat, this->Angle);
      this->LabelMapper->SetInput(string);
    }
    else
    {
      this->LabelMapper->SetInput(this->Label);
    }
    if (this->LabelTextProperty->GetMTime() > this->BuildTime)
    {
      this->LabelMapper->GetTextProperty()->ShallowCopy(this->LabelTextProperty);
    }

    if (viewportChanged || this->LabelTextProperty->GetMTime() > this->BuildTime)
    {
      int *size = viewport->GetSize();
      this->SetFontSize(viewport, this->LabelMapper, size, this->LabelFactor, stringSize);
    }
    else
    {
      this->LabelMapper->GetSize(viewport, stringSize);
    }

    double x1[3], c[3];
    theta = (theta1 + theta2)/2.0;
    c[0] = center[0] + radius*cos(theta);
    c[1] = center[1] + radius*sin(theta);
    c[2] = 0.0;
    this->LabelActor->SetPosition(c[0],c[1]);
    for (i=0; i<numDivs; i++)
    {
      this->LeaderPoints->GetPoint(i,x);
      this->LeaderPoints->GetPoint(i+1,x1);
      if ( ! this->InStringBox(c,stringSize,x) &&
           ! this->InStringBox(c,stringSize,x1)  )
      {
        this->LeaderLines->InsertNextCell(2);
        this->LeaderLines->InsertCellPoint(i);
        this->LeaderLines->InsertCellPoint(i+1);
      }
    }
  }
  else // no clipping against the string necessary
  {
    for (i=0; i<numDivs; i++)
    {
      this->LeaderLines->InsertNextCell(2);
      this->LeaderLines->InsertCellPoint(i);
      this->LeaderLines->InsertCellPoint(i+1);
    }
  }
}

int vtkLeaderActor2D::InStringBox(double center[3], int stringSize[2], double x[3])
{
  double minX = center[0] - static_cast<double>(stringSize[0])/2.0;
  double maxX = center[0] + static_cast<double>(stringSize[0])/2.0;
  double minY = center[1] - static_cast<double>(stringSize[1])/2.0;
  double maxY = center[1] + static_cast<double>(stringSize[1])/2.0;

  if ( minX <= x[0] && x[0] <= maxX && minY <= x[1] && x[1] <= maxY )
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

//----------------------------------------------------------------------------
// Release any graphics resources that are being consumed by this actor.
// The parameter window could be used to determine which graphic
// resources to release.
void vtkLeaderActor2D::ReleaseGraphicsResources(vtkWindow *win)
{
  this->LabelActor->ReleaseGraphicsResources(win);
  this->LeaderActor->ReleaseGraphicsResources(win);
}

//----------------------------------------------------------------------------
// Build the axis, ticks, title, and labels and render.

int vtkLeaderActor2D::RenderOpaqueGeometry(vtkViewport *viewport)
{
  int renderedSomething=0;
  this->BuildLeader(viewport);

  // Everything is built, just have to render
  if ( (this->Label != nullptr && this->Label[0]) || \
       (this->AutoLabel && this->LabelMapper->GetInput() != nullptr ) )
  {
    renderedSomething += this->LabelActor->RenderOpaqueGeometry(viewport);
  }
  renderedSomething += this->LeaderActor->RenderOpaqueGeometry(viewport);

  return renderedSomething;
}

//----------------------------------------------------------------------------
// Render the axis, ticks, title, and labels.

int vtkLeaderActor2D::RenderOverlay(vtkViewport *viewport)
{
  int renderedSomething=0;
  this->BuildLeader(viewport);

  // Everything is built, just have to render
  if ( (this->Label != nullptr && this->Label[0]) || \
       (this->AutoLabel && this->LabelMapper->GetInput() != nullptr ) )
  {
    renderedSomething += this->LabelActor->RenderOverlay(viewport);
  }
  renderedSomething += this->LeaderActor->RenderOverlay(viewport);

  return renderedSomething;
}

//-----------------------------------------------------------------------------
// Description:
// Does this prop have some translucent polygonal geometry?
vtkTypeBool vtkLeaderActor2D::HasTranslucentPolygonalGeometry()
{
  return 0;
}

//----------------------------------------------------------------------------
void vtkLeaderActor2D::ShallowCopy(vtkProp *prop)
{
  vtkLeaderActor2D *a = vtkLeaderActor2D::SafeDownCast(prop);
  if ( a != nullptr )
  {
    this->SetLabel(a->GetLabel());
    this->SetLabelTextProperty(a->GetLabelTextProperty());
    this->SetLabelFactor(a->GetLabelFactor());
    this->SetArrowPlacement(a->GetArrowPlacement());
    this->SetArrowStyle(a->GetArrowStyle());
    this->SetArrowLength(a->GetArrowLength());
    this->SetArrowWidth(a->GetArrowWidth());
    this->SetMinimumArrowSize(a->GetMinimumArrowSize());
    this->SetMaximumArrowSize(a->GetMaximumArrowSize());
  }

  // Now do superclass
  this->vtkActor2D::ShallowCopy(prop);
}
//----------------------------------------------------------------------------
void vtkLeaderActor2D::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Radius: " << this->Radius << "\n";
  os << indent << "Label: " << (this->Label ? this->Label : "(none)") << "\n";
  if (this->LabelTextProperty)
  {
    os << indent << "Label Text Property:\n";
    this->LabelTextProperty->PrintSelf(os,indent.GetNextIndent());
  }
  else
  {
    os << indent << "Label Text Property: (none)\n";
  }
  os << indent << "Label Factor: " << this->LabelFactor << "\n";
  os << indent << "Auto Label: " << (this->AutoLabel ? "On\n" : "Off\n");
  os << indent << "Label Format: " << this->LabelFormat << "\n";

  os << indent << "Arrow Style: ";
  if ( this->ArrowStyle == VTK_ARROW_FILLED )
  {
    os << "Filled\n";
  }
  else if ( this->ArrowStyle == VTK_ARROW_OPEN )
  {
    os << "Open\n";
  }
  else // if ( this->ArrowStyle == VTK_ARROW_HOLLOW )
  {
    os << "Hollow\n";
  }

  os << indent << "Arrow Length: " << this->ArrowLength << "\n";
  os << indent << "Arrow Width: " << this->ArrowWidth << "\n";
  os << indent << "Minimum Arrow Size: " << this->MinimumArrowSize << "\n";
  os << indent << "Maximum Arrow Size: " << this->MaximumArrowSize << "\n";

  os << indent << "Arrow Placement: ";
  if ( this->ArrowPlacement == VTK_ARROW_NONE )
  {
    os << "No Arrows\n";
  }
  else if ( this->ArrowPlacement == VTK_ARROW_POINT1 )
  {
    os << "Arrow on first point\n";
  }
  else if ( this->ArrowPlacement == VTK_ARROW_POINT2 )
  {
    os << "Arrow on second point\n";
  }
  else
  {
    os << "Arrow on both ends\n";
  }

  os << indent << "Angle: " << this->Angle << "\n";
  os << indent << "Length: " << this->Length << "\n";
}

