text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    vtkSphereRepresentation.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 "vtkSphereRepresentation.h"
  #include "vtkActor.h"
  #include "vtkActor2D.h"
  #include "vtkAssemblyPath.h"
  #include "vtkCallbackCommand.h"
  #include "vtkCamera.h"
  #include "vtkCellArray.h"
  #include "vtkCellPicker.h"
  #include "vtkCursor3D.h"
  #include "vtkDoubleArray.h"
  #include "vtkInteractorObserver.h"
  #include "vtkLineSource.h"
  #include "vtkMath.h"
  #include "vtkObjectFactory.h"
  #include "vtkPickingManager.h"
  #include "vtkPolyData.h"
  #include "vtkPolyDataMapper.h"
  #include "vtkProperty.h"
  #include "vtkRenderWindow.h"
  #include "vtkRenderWindowInteractor.h"
  #include "vtkRenderer.h"
  #include "vtkSphere.h"
  #include "vtkSphereSource.h"
  #include "vtkTextMapper.h"
  #include "vtkTextProperty.h"
  #include "vtkTransform.h"
  #include "vtkWindow.h"
  
  #include <cassert>
  
  vtkStandardNewMacro(vtkSphereRepresentation);
  
  //------------------------------------------------------------------------------
  vtkSphereRepresentation::vtkSphereRepresentation()
  {
    // The initial state
    this->InteractionState = vtkSphereRepresentation::Outside;
  
    // Handle size is in pixels for this widget
    this->HandleSize = 10.0;
  
    // Set up the initial representation
    this->Representation = VTK_SPHERE_WIREFRAME;
  
    // Set up the initial properties
    this->SphereProperty = nullptr;
    this->SelectedSphereProperty = nullptr;
    this->HandleProperty = nullptr;
    this->SelectedHandleProperty = nullptr;
    this->HandleTextProperty = nullptr;
    this->RadialLineProperty = nullptr;
    this->CreateDefaultProperties();
  
    // Build the representation of the widget
    // Represent the sphere
    this->SphereSource = vtkSphereSource::New();
    this->SphereSource->SetThetaResolution(16);
    this->SphereSource->SetPhiResolution(8);
    this->SphereSource->LatLongTessellationOn();
    this->SphereMapper = vtkPolyDataMapper::New();
    this->SphereMapper->SetInputConnection(this->SphereSource->GetOutputPort());
    this->SphereActor = vtkActor::New();
    this->SphereActor->SetMapper(this->SphereMapper);
  
    // the handle
    this->HandleVisibility = 0;
    this->HandleDirection[0] = 1.0;
    this->HandleDirection[1] = 0.0;
    this->HandleDirection[2] = 0.0;
    this->HandleSource = vtkSphereSource::New();
    this->HandleSource->SetThetaResolution(16);
    this->HandleSource->SetPhiResolution(8);
    this->HandleMapper = vtkPolyDataMapper::New();
    this->HandleMapper->SetInputConnection(this->HandleSource->GetOutputPort());
    this->HandleActor = vtkActor::New();
    this->HandleActor->SetMapper(this->HandleMapper);
  
    // Manage the handle label
    this->HandleText = 1;
    this->HandleTextMapper = vtkTextMapper::New();
    this->HandleTextMapper->SetTextProperty(this->HandleTextProperty);
    this->HandleTextActor = vtkActor2D::New();
    this->HandleTextActor->SetMapper(this->HandleTextMapper);
    this->HandleTextActor->GetPositionCoordinate()->SetCoordinateSystemToDisplay();
  
    // Manage the radial line segment
    this->RadialLine = 1;
    this->RadialLineSource = vtkLineSource::New();
    this->RadialLineSource->SetResolution(1);
    this->RadialLineMapper = vtkPolyDataMapper::New();
    this->RadialLineMapper->SetInputConnection(this->RadialLineSource->GetOutputPort());
    this->RadialLineActor = vtkActor::New();
    this->RadialLineActor->SetMapper(this->RadialLineMapper);
    this->RadialLineActor->SetProperty(this->RadialLineProperty);
  
    // Represent the center cursor
    this->CenterCursor = false;
    this->CenterCursorSource = vtkCursor3D::New();
    this->CenterCursorSource->AllOff();
    this->CenterCursorSource->AxesOn();
    this->CenterCursorSource->TranslationModeOn();
    this->CenterMapper = vtkPolyDataMapper::New();
    this->CenterMapper->SetInputConnection(this->CenterCursorSource->GetOutputPort());
    this->CenterActor = vtkActor::New();
    this->CenterActor->SetMapper(this->CenterMapper);
  
    // 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;
  
    // First creation of the widget, serves to initialize it
    this->PlaceWidget(bounds);
  
    // Manage the picking stuff
    this->HandlePicker = vtkCellPicker::New();
    this->HandlePicker->SetTolerance(0.005); // need some fluff
    this->HandlePicker->AddPickList(this->HandleActor);
    this->HandlePicker->PickFromListOn();
  
    this->SpherePicker = vtkCellPicker::New();
    this->SpherePicker->SetTolerance(0.005);
    this->SpherePicker->AddPickList(this->SphereActor);
    this->SpherePicker->PickFromListOn();
  
    this->SphereActor->SetProperty(this->SphereProperty);
    this->HandleActor->SetProperty(this->HandleProperty);
  
    this->TranslationAxis = Axis::NONE;
  }
  
  //------------------------------------------------------------------------------
  vtkSphereRepresentation::~vtkSphereRepresentation()
  {
    this->SphereActor->Delete();
    this->SphereMapper->Delete();
    this->SphereSource->Delete();
  
    this->HandlePicker->Delete();
    this->SpherePicker->Delete();
  
    this->HandleSource->Delete();
    this->HandleMapper->Delete();
    this->HandleActor->Delete();
  
    // the handle
    this->HandleTextProperty->Delete();
    this->HandleTextMapper->Delete();
    this->HandleTextActor->Delete();
  
    // the text
    this->RadialLineProperty->Delete();
    this->RadialLineSource->Delete();
    this->RadialLineMapper->Delete();
    this->RadialLineActor->Delete();
  
    // The cursor
    this->CenterCursorSource->Delete();
    this->CenterMapper->Delete();
    this->CenterActor->Delete();
  
    if (this->SphereProperty)
    {
      this->SphereProperty->Delete();
    }
    if (this->SelectedSphereProperty)
    {
      this->SelectedSphereProperty->Delete();
    }
    if (this->HandleProperty)
    {
      this->HandleProperty->Delete();
    }
    if (this->SelectedHandleProperty)
    {
      this->SelectedHandleProperty->Delete();
    }
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::GetPolyData(vtkPolyData* pd)
  {
    this->SphereSource->Update();
    pd->ShallowCopy(this->SphereSource->GetOutput());
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::GetSphere(vtkSphere* sphere)
  {
    sphere->SetRadius(this->SphereSource->GetRadius());
    sphere->SetCenter(this->SphereSource->GetCenter());
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::HighlightSphere(int highlight)
  {
    if (highlight)
    {
      this->ValidPick = 1;
      this->SphereActor->SetProperty(this->SelectedSphereProperty);
    }
    else
    {
      this->SphereActor->SetProperty(this->SphereProperty);
    }
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::HighlightHandle(int highlight)
  {
    if (highlight)
    {
      this->ValidPick = 1;
      this->HandleActor->SetProperty(this->SelectedHandleProperty);
    }
    else
    {
      this->HandleActor->SetProperty(this->HandleProperty);
    }
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::RegisterPickers()
  {
    vtkPickingManager* pm = this->GetPickingManager();
    if (!pm)
    {
      return;
    }
    pm->AddPicker(this->HandlePicker, this);
    pm->AddPicker(this->SpherePicker, this);
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::Scale(const double* p1, const 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 radius = this->SphereSource->GetRadius();
    double* c = this->SphereSource->GetCenter();
  
    // Compute the scale factor
    double sf = vtkMath::Norm(v) / radius;
    if (Y > this->LastEventPosition[1])
    {
      sf = 1.0 + sf;
    }
    else
    {
      sf = 1.0 - sf;
    }
  
    // Make sure that the radius is valid; don't let it shrink further
    // but it can still grow in radius.
    if (Y <= this->LastEventPosition[1] && sf * radius < 1.0e-06 * this->InitialLength)
    {
      return;
    }
  
    // Need to prevent radius going to zero
    this->SphereSource->SetRadius(sf * radius);
    this->HandlePosition[0] = c[0] + sf * (this->HandlePosition[0] - c[0]);
    this->HandlePosition[1] = c[1] + sf * (this->HandlePosition[1] - c[1]);
    this->HandlePosition[2] = c[2] + sf * (this->HandlePosition[2] - c[2]);
    this->HandleSource->SetCenter(this->HandlePosition);
    this->AdaptCenterCursorBounds();
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::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;
  
    this->ComputeInteractionState(static_cast<int>(e[0]), static_cast<int>(e[1]), 0);
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::WidgetInteraction(double e[2])
  {
    // Convert events to appropriate coordinate systems
    vtkCamera* camera = this->Renderer->GetActiveCamera();
    if (!camera)
    {
      return;
    }
    double focalPoint[4], pickPoint[4], prevPickPoint[4];
    double z, vpn[3];
    camera->GetViewPlaneNormal(vpn);
  
    // Compute the two points defining the motion vector
    vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, this->LastPickPosition[0],
      this->LastPickPosition[1], this->LastPickPosition[2], focalPoint);
    z = focalPoint[2];
    vtkInteractorObserver::ComputeDisplayToWorld(
      this->Renderer, this->LastEventPosition[0], this->LastEventPosition[1], z, prevPickPoint);
    vtkInteractorObserver::ComputeDisplayToWorld(this->Renderer, e[0], e[1], z, pickPoint);
  
    // Process the motion
    if (this->InteractionState == vtkSphereRepresentation::Translating)
    {
      this->Translate(prevPickPoint, pickPoint);
    }
  
    else if (this->InteractionState == vtkSphereRepresentation::Scaling)
    {
      this->Scale(prevPickPoint, pickPoint, static_cast<int>(e[0]), static_cast<int>(e[1]));
    }
    else if (this->InteractionState == vtkSphereRepresentation::MovingHandle)
    {
      vtkAssemblyPath* path = this->GetAssemblyPath(e[0], e[1], 0., this->SpherePicker);
  
      if (path != nullptr)
      {
        double pos[3], dir[3], c[3];
        this->SpherePicker->GetPickPosition(pos);
        this->SphereSource->GetCenter(c);
        dir[0] = pos[0] - c[0];
        dir[1] = pos[1] - c[1];
        dir[2] = pos[2] - c[2];
        this->SetHandleDirection(dir);
      }
    }
  
    // Store the position
    this->LastEventPosition[0] = e[0];
    this->LastEventPosition[1] = e[1];
    this->LastEventPosition[2] = 0.0;
  }
  
  //------------------------------------------------------------------------------
  // Loop through all points and translate them
  void vtkSphereRepresentation::Translate(const double* p1, const double* p2)
  {
    // Get the motion vector
    double v[3] = { 0, 0, 0 };
  
    if (!this->IsTranslationConstrained())
    {
      v[0] = p2[0] - p1[0];
      v[1] = p2[1] - p1[1];
      v[2] = p2[2] - p1[2];
    }
    else
    {
      assert(this->TranslationAxis > -1 && this->TranslationAxis < 3 &&
        "this->TranslationAxis out of bounds");
      v[this->TranslationAxis] = p2[this->TranslationAxis] - p1[this->TranslationAxis];
    }
  
    double* center = this->SphereSource->GetCenter();
  
    double center1[3];
    for (int i = 0; i < 3; i++)
    {
      center1[i] = center[i] + v[i];
      this->HandlePosition[i] += v[i];
    }
  
    this->SphereSource->SetCenter(center1);
    this->CenterCursorSource->SetFocalPoint(center1);
    this->HandleSource->SetCenter(HandlePosition);
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::CreateDefaultProperties()
  {
    if (!this->SphereProperty)
    {
      this->SphereProperty = vtkProperty::New();
    }
    if (!this->SelectedSphereProperty)
    {
      this->SelectedSphereProperty = vtkProperty::New();
    }
  
    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->HandleTextProperty)
    {
      this->HandleTextProperty = vtkTextProperty::New();
      this->HandleTextProperty->SetFontSize(12);
      this->HandleTextProperty->SetBold(1);
      this->HandleTextProperty->SetItalic(1);
      this->HandleTextProperty->SetShadow(1);
      this->HandleTextProperty->SetFontFamilyToArial();
    }
  
    if (!this->RadialLineProperty)
    {
      this->RadialLineProperty = vtkProperty::New();
      this->RadialLineProperty->SetColor(1, 0, 0);
    }
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::PlaceWidget(double center[3], double handle[3])
  {
    double r = sqrt(vtkMath::Distance2BetweenPoints(center, handle));
    this->SphereSource->SetCenter(center);
    this->SphereSource->SetRadius(r);
    this->SphereSource->Update();
  
    this->HandlePosition[0] = handle[0];
    this->HandlePosition[1] = handle[1];
    this->HandlePosition[2] = handle[2];
    this->HandleSource->SetCenter(handle);
    this->HandleSource->Update();
  
    this->CenterCursorSource->SetFocalPoint(center);
    this->CenterCursorSource->Update();
  
    this->HandleDirection[0] = handle[0] - center[0];
    this->HandleDirection[1] = handle[1] - center[1];
    this->HandleDirection[2] = handle[2] - center[2];
  
    this->InitialLength = r;
    this->InitialBounds[0] = center[0] - r;
    this->InitialBounds[1] = center[0] + r;
    this->InitialBounds[2] = center[1] - r;
    this->InitialBounds[3] = center[1] + r;
    this->InitialBounds[4] = center[2] - r;
    this->InitialBounds[5] = center[2] + r;
  
    this->ValidPick = 1;
    this->BuildRepresentation();
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::SetCenter(double center[3])
  {
    double c[3];
    this->SphereSource->GetCenter(c);
    if (c[0] != center[0] || c[1] != center[1] || c[2] != center[2])
    {
      double handle[3];
      this->SphereSource->SetCenter(center);
  
      if (this->GetHandleVisibility())
      {
        this->HandleSource->GetCenter(handle);
        this->HandleDirection[0] = handle[0] - center[0];
        this->HandleDirection[1] = handle[1] - center[1];
        this->HandleDirection[2] = handle[2] - center[2];
        double r = sqrt(static_cast<double>(vtkMath::Distance2BetweenPoints(handle, center)));
        this->SphereSource->SetRadius(r);
      }
  
      this->SphereSource->Update();
  
      this->CenterCursorSource->SetFocalPoint(center);
      this->CenterCursorSource->Update();
  
      this->Modified();
    }
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::SetRadius(double r)
  {
    r = (r <= this->InitialLength * 1.0e-04 ? this->InitialLength * 1.0e-04 : r);
    if (r != this->SphereSource->GetRadius())
    {
      double center[3];
      this->SphereSource->SetRadius(r);
      this->SphereSource->GetCenter(center);
      this->PlaceHandle(center, r);
      this->SphereSource->Update();
      this->Modified();
    }
  }
  
  //------------------------------------------------------------------------------
  // This method may change the radius of the sphere
  void vtkSphereRepresentation::SetHandlePosition(double handle[3])
  {
    double h[3];
    this->HandleSource->GetCenter(h);
    if (h[0] != handle[0] || h[1] != handle[1] || h[2] != handle[2])
    {
      double c[3];
      this->HandleSource->SetCenter(handle);
      this->SphereSource->GetCenter(c);
      this->HandleDirection[0] = handle[0] - c[0];
      this->HandleDirection[1] = handle[1] - c[1];
      this->HandleDirection[2] = handle[2] - c[2];
      double r = static_cast<double>(vtkMath::Distance2BetweenPoints(handle, c));
      this->SphereSource->SetRadius(sqrt(r));
      this->SphereSource->Update();
      this->HandleSource->Update();
      this->Modified();
    }
  }
  
  //------------------------------------------------------------------------------
  // This method preserves the radius of the sphere. The handle is repositioned
  // on the existing sphere but in the new direction. So the handle will move across
  // the surface of the sphere. Note that the HandlePosition[3] data member is
  // adjusted to be consistent with the sphere center and the current sphere radius.
  void vtkSphereRepresentation::SetHandleDirection(double dir[3])
  {
    double* d = this->HandleDirection;
    double dirMag = vtkMath::Norm(dir);
    if ((dirMag != 0.0) && (d[0] != dir[0] || d[1] != dir[1] || d[2] != dir[2]))
    {
      double r, f, c[3];
      r = this->SphereSource->GetRadius();
      f = r / dirMag;
      this->SphereSource->GetCenter(c);
      this->HandlePosition[0] = c[0] + f * dir[0];
      this->HandlePosition[1] = c[1] + f * dir[1];
      this->HandlePosition[2] = c[2] + f * dir[2];
      this->HandleSource->SetCenter(this->HandlePosition);
      this->HandleSource->Update();
      this->Modified();
    }
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::PlaceWidget(double bds[6])
  {
    double bounds[6], center[3], radius;
  
    this->AdjustBounds(bds, bounds, center);
  
    radius = (bounds[1] - bounds[0]) / 2.0;
    if (radius > ((bounds[3] - bounds[2]) / 2.0))
    {
      radius = (bounds[3] - bounds[2]) / 2.0;
    }
    radius = (bounds[1] - bounds[0]) / 2.0;
    if (radius > ((bounds[5] - bounds[4]) / 2.0))
    {
      radius = (bounds[5] - bounds[4]) / 2.0;
    }
  
    this->SphereSource->SetCenter(center);
    this->SphereSource->SetRadius(radius);
    this->SphereSource->Update();
  
    this->CenterCursorSource->SetFocalPoint(center);
    this->CenterCursorSource->Update();
  
    // place the handle
    this->PlaceHandle(center, radius);
  
    for (int 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]));
  
    this->ValidPick = 1; // since we have set up widget properly
    this->SizeHandles();
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::PlaceHandle(const double* center, double radius)
  {
    double sf = radius / vtkMath::Norm(this->HandleDirection);
  
    this->HandlePosition[0] = center[0] + sf * this->HandleDirection[0];
    this->HandlePosition[1] = center[1] + sf * this->HandleDirection[1];
    this->HandlePosition[2] = center[2] + sf * this->HandleDirection[2];
    this->HandleSource->SetCenter(this->HandlePosition);
    this->HandleSource->Update();
  }
  
  //------------------------------------------------------------------------------
  int vtkSphereRepresentation::ComputeInteractionState(int X, int Y, int vtkNotUsed(modify))
  {
    // Okay, we can process this. Try to pick handles first;
    // if no handles picked, then pick the bounding box.
    this->InteractionState = vtkSphereRepresentation::Outside;
    if (!this->Renderer || !this->Renderer->IsInViewport(X, Y))
    {
      return this->InteractionState;
    }
  
    // Try and pick a handle first. This allows the picking of the handle even
    // if it is "behind" the sphere.
    vtkAssemblyPath* path;
    int handlePicked = 0;
    if (this->HandleVisibility || this->HandleText || this->RadialLine)
    {
      path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
  
      if (path != nullptr)
      {
        this->ValidPick = 1;
        this->InteractionState = vtkSphereRepresentation::MovingHandle;
        this->HandleSource->GetCenter(this->LastPickPosition);
        this->HandleSource->GetCenter(this->HandlePosition);
        handlePicked = 1;
      }
    }
  
    if (!handlePicked)
    {
      path = this->GetAssemblyPath(X, Y, 0., this->SpherePicker);
  
      if (path != nullptr)
      {
        this->ValidPick = 1;
        this->InteractionState = vtkSphereRepresentation::OnSphere;
        this->SpherePicker->GetPickPosition(this->LastPickPosition);
      }
    }
  
    return this->InteractionState;
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::AdaptCenterCursorBounds()
  {
    double center[3], newBounds[6];
    this->CenterCursorSource->GetFocalPoint(center);
    double radius = this->SizeHandlesInPixels(2.0, center);
    for (int i = 0; i < 3; i++)
    {
      newBounds[2 * i] = center[i] - radius;
      newBounds[2 * i + 1] = center[i] + radius;
    }
    this->CenterCursorSource->SetModelBounds(newBounds);
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::SetInteractionState(int state)
  {
    // Clamp to allowable values
    state = (state < vtkSphereRepresentation::Outside
        ? vtkSphereRepresentation::Outside
        : (state > vtkSphereRepresentation::Scaling ? vtkSphereRepresentation::Scaling : state));
  
    // Depending on state, highlight appropriate parts of representation
    this->InteractionState = state;
  }
  
  //------------------------------------------------------------------------------
  double* vtkSphereRepresentation::GetBounds()
  {
    this->BuildRepresentation();
    return this->SphereSource->GetOutput()->GetBounds();
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::BuildRepresentation()
  {
    // Always rebuild, it's not worth keeping track of modified
    switch (this->Representation)
    {
      case VTK_SPHERE_OFF:
        break;
      case VTK_SPHERE_WIREFRAME:
        this->SphereProperty->SetRepresentationToWireframe();
        this->SelectedSphereProperty->SetRepresentationToWireframe();
        break;
      case VTK_SPHERE_SURFACE:
        this->SphereProperty->SetRepresentationToSurface();
        this->SelectedSphereProperty->SetRepresentationToSurface();
        break;
    }
    this->SphereSource->Update();
    this->SizeHandles();
  
    // Now the annotations
    if (this->RadialLine)
    {
      this->RadialLineSource->SetPoint1(this->SphereSource->GetCenter());
      this->RadialLineSource->SetPoint2(this->HandleSource->GetCenter());
      this->RadialLineSource->Update();
    }
  
    if (this->HandleText && this->Renderer)
    {
      char str[256];
      double c[3], hc[3], tc[4];
      this->SphereSource->GetCenter(c);
      this->HandleSource->GetCenter(hc);
      double r = sqrt(static_cast<double>(vtkMath::Distance2BetweenPoints(c, hc)));
      r = (r <= 0.0 ? 1.0 : r);
      double theta = vtkMath::DegreesFromRadians(atan2((hc[1] - c[1]), (hc[0] - c[0])));
      double phi = vtkMath::DegreesFromRadians(acos((hc[2] - c[2]) / r));
      snprintf(str, sizeof(str), "(%0.2g, %1.1f, %1.1f)", r, theta, phi);
      this->HandleTextMapper->SetInput(str);
      vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, hc[0], hc[1], hc[2], tc);
      this->HandleTextActor->GetPositionCoordinate()->SetValue(tc[0] + 10, tc[1] + 10);
    }
    this->AdaptCenterCursorBounds();
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::ReleaseGraphicsResources(vtkWindow* w)
  {
    this->SphereActor->ReleaseGraphicsResources(w);
    this->HandleActor->ReleaseGraphicsResources(w);
    this->HandleTextActor->ReleaseGraphicsResources(w);
    this->RadialLineActor->ReleaseGraphicsResources(w);
    this->CenterActor->ReleaseGraphicsResources(w);
  }
  
  //------------------------------------------------------------------------------
  int vtkSphereRepresentation::RenderOpaqueGeometry(vtkViewport* v)
  {
    int count = 0;
    this->BuildRepresentation();
  
    if (this->Representation != VTK_SPHERE_OFF)
    {
      count += this->SphereActor->RenderOpaqueGeometry(v);
    }
    if (this->HandleVisibility)
    {
      count += this->HandleActor->RenderOpaqueGeometry(v);
    }
    if (this->RadialLine)
    {
      count += this->RadialLineActor->RenderOpaqueGeometry(v);
    }
    if (this->CenterCursor)
    {
      count += this->CenterActor->RenderOpaqueGeometry(v);
    }
  
    return count;
  }
  
  //------------------------------------------------------------------------------
  int vtkSphereRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport* v)
  {
    int count = 0;
  
    if (this->Representation != VTK_SPHERE_OFF)
    {
      count += this->SphereActor->RenderTranslucentPolygonalGeometry(v);
    }
    if (this->HandleVisibility)
    {
      count += this->HandleActor->RenderTranslucentPolygonalGeometry(v);
    }
    if (this->RadialLine)
    {
      count += this->RadialLineActor->RenderTranslucentPolygonalGeometry(v);
    }
    if (this->CenterCursor)
    {
      count += this->CenterActor->RenderTranslucentPolygonalGeometry(v);
    }
  
    return count;
  }
  
  //------------------------------------------------------------------------------
  int vtkSphereRepresentation::RenderOverlay(vtkViewport* v)
  {
    int count = 0;
  
    if (this->HandleText)
    {
      count += this->HandleTextActor->RenderOverlay(v);
    }
  
    return count;
  }
  
  //------------------------------------------------------------------------------
  vtkTypeBool vtkSphereRepresentation::HasTranslucentPolygonalGeometry()
  {
    int result = 0;
    this->BuildRepresentation();
  
    if (this->Representation != VTK_SPHERE_OFF)
    {
      result |= this->SphereActor->HasTranslucentPolygonalGeometry();
    }
    if (this->HandleVisibility)
    {
      result |= this->HandleActor->HasTranslucentPolygonalGeometry();
    }
    if (this->HandleText)
    {
      result |= this->HandleTextActor->HasTranslucentPolygonalGeometry();
    }
    if (this->RadialLine)
    {
      result |= this->RadialLineActor->HasTranslucentPolygonalGeometry();
    }
    if (this->CenterCursor)
    {
      result |= this->CenterActor->HasTranslucentPolygonalGeometry();
    }
  
    return result;
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::SizeHandles()
  {
    double radius = this->vtkWidgetRepresentation::SizeHandlesInPixels(
      1.5, this->HandleSource->GetOutput()->GetCenter());
    this->HandleSource->SetRadius(radius);
  }
  
  //------------------------------------------------------------------------------
  void vtkSphereRepresentation::PrintSelf(ostream& os, vtkIndent indent)
  {
    this->Superclass::PrintSelf(os, indent);
  
    os << indent << "Sphere Representation: ";
    if (this->Representation == VTK_SPHERE_OFF)
    {
      os << "Off\n";
    }
    else if (this->Representation == VTK_SPHERE_WIREFRAME)
    {
      os << "Wireframe\n";
    }
    else // if ( this->Representation == VTK_SPHERE_SURFACE )
    {
      os << "Surface\n";
    }
  
    if (this->SphereProperty)
    {
      os << indent << "Sphere Property: " << this->SphereProperty << "\n";
    }
    else
    {
      os << indent << "Sphere Property: (none)\n";
    }
    if (this->SelectedSphereProperty)
    {
      os << indent << "Selected Sphere Property: " << this->SelectedSphereProperty << "\n";
    }
    else
    {
      os << indent << "Selected Sphere Property: (none)\n";
    }
  
    if (this->HandleProperty)
    {
      os << indent << "Handle Property: " << this->HandleProperty << "\n";
    }
    else
    {
      os << indent << "Handle Property: (none)\n";
    }
    if (this->SelectedHandleProperty)
    {
      os << indent << "Selected Handle Property: " << this->SelectedHandleProperty << "\n";
    }
    else
    {
      os << indent << "Selected Handle Property: (none)\n";
    }
  
    os << indent << "Handle Visibility: " << (this->HandleVisibility ? "On\n" : "Off\n");
    os << indent << "Handle Direction: (" << this->HandleDirection[0] << ", "
       << this->HandleDirection[1] << ", " << this->HandleDirection[2] << ")\n";
    os << indent << "Handle Position: (" << this->HandlePosition[0] << ", " << this->HandlePosition[1]
       << ", " << this->HandlePosition[2] << ")\n";
  
    int thetaRes = this->SphereSource->GetThetaResolution();
    int phiRes = this->SphereSource->GetPhiResolution();
    double* center = this->SphereSource->GetCenter();
    double r = this->SphereSource->GetRadius();
  
    os << indent << "Theta Resolution: " << thetaRes << "\n";
    os << indent << "Phi Resolution: " << phiRes << "\n";
    os << indent << "Center: (" << center[0] << ", " << center[1] << ", " << center[2] << ")\n";
    os << indent << "Radius: " << r << "\n";
  
    os << indent << "Handle Text: " << this->HandleText << "\n";
    os << indent << "Radial Line: " << this->RadialLine << "\n";
    os << indent << "Center Cursor: " << this->CenterCursor << "\n";
  
    if (this->HandleTextProperty)
    {
      os << indent << "Handle Text Property: " << this->HandleTextProperty << "\n";
    }
    else
    {
      os << indent << "Handle Text Property: (none)\n";
    }
  
    if (this->RadialLineProperty)
    {
      os << indent << "Radial Line Property: " << this->RadialLineProperty << "\n";
    }
    else
    {
      os << indent << "Radial Line Property: (none)\n";
    }
  }
  