text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    vtkMagnifierRepresentation.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 "vtkMagnifierRepresentation.h"
  #include "vtkActor2D.h"
  #include "vtkCamera.h"
  #include "vtkCellArray.h"
  #include "vtkObjectFactory.h"
  #include "vtkPoints.h"
  #include "vtkPolyData.h"
  #include "vtkPolyDataMapper2D.h"
  #include "vtkProperty2D.h"
  #include "vtkRenderWindow.h"
  #include "vtkRenderer.h"
  #include "vtkWindow.h"
  
  vtkStandardNewMacro(vtkMagnifierRepresentation);
  
  //------------------------------------------------------------------------------
  vtkMagnifierRepresentation::vtkMagnifierRepresentation()
  {
    this->MagnificationFactor = 10.0;
    this->Props = vtkPropCollection::New();
    this->Size[0] = this->Size[1] = 75;
    this->Border = false;
  
    this->InteractionState = Invisible;
    this->MagnificationRenderer = vtkRenderer::New();
    this->Coordinate = vtkCoordinate::New();
    this->Coordinate->SetCoordinateSystemToDisplay();
    this->InsideRenderer = false;
  
    // Create the geometry in canonical coordinates
    this->BorderPoints = vtkPoints::New();
    this->BorderPoints->SetDataTypeToDouble();
    this->BorderPoints->SetNumberOfPoints(4);
    this->BorderPoints->SetPoint(0, 0.0, 0.0, 0.0);
    this->BorderPoints->SetPoint(1, 1.0, 0.0, 0.0);
    this->BorderPoints->SetPoint(2, 1.0, 1.0, 0.0);
    this->BorderPoints->SetPoint(3, 0.0, 1.0, 0.0);
  
    vtkCellArray* outline = vtkCellArray::New();
    outline->InsertNextCell(5);
    outline->InsertCellPoint(0);
    outline->InsertCellPoint(1);
    outline->InsertCellPoint(2);
    outline->InsertCellPoint(3);
    outline->InsertCellPoint(0);
  
    this->BorderPolyData = vtkPolyData::New();
    this->BorderPolyData->SetPoints(this->BorderPoints);
    this->BorderPolyData->SetLines(outline);
    outline->Delete();
  
    this->BorderMapper = vtkPolyDataMapper2D::New();
    this->BorderMapper->SetInputData(this->BorderPolyData);
    this->BorderActor = vtkActor2D::New();
    this->BorderActor->SetMapper(this->BorderMapper);
  
    this->BorderProperty = vtkProperty2D::New();
    this->BorderProperty->SetLineWidth(2);
    this->BorderProperty->SetColor(1, 0, 0);
    this->BorderActor->SetProperty(this->BorderProperty);
  }
  
  //------------------------------------------------------------------------------
  vtkMagnifierRepresentation::~vtkMagnifierRepresentation()
  {
    this->Props->Delete();
    this->BorderProperty->Delete();
  
    if (this->Renderer && this->Renderer->GetRenderWindow())
    {
      this->Renderer->GetRenderWindow()->RemoveRenderer(this->MagnificationRenderer);
    }
    this->MagnificationRenderer->Delete();
    this->Coordinate->Delete();
  
    this->BorderPoints->Delete();
    this->BorderPolyData->Delete();
    this->BorderMapper->Delete();
    this->BorderActor->Delete();
  }
  
  //------------------------------------------------------------------------------
  // Move the magnifier around. This method is invoked every time the mouse
  // moves.
  void vtkMagnifierRepresentation::WidgetInteraction(double eventPos[2])
  {
    int XF = eventPos[0];
    int YF = eventPos[1];
  
    // Make sure the renderer and render window have been defined
    vtkRenderWindow* renWin;
    if (!this->Renderer || !(renWin = this->Renderer->GetRenderWindow()))
    {
      return;
    }
  
    // If event outside of this window, turn off magnify renderer
    this->InsideRenderer = (this->Renderer->IsInViewport(XF, YF) != 0);
  
    // Build the representation as necessary
    this->BuildRepresentation();
  
    // Move the viewport /renderer to the current mouse position
    int* winSize = this->Renderer->GetRenderWindow()->GetSize();
    int* vpSize = this->Renderer->GetSize();
    double vpxMax = static_cast<double>(vpSize[0]) / winSize[0];
    double vpyMax = static_cast<double>(vpSize[1]) / winSize[1];
    double viewPort[4];
    viewPort[0] = eventPos[0] / winSize[0];
    viewPort[1] = eventPos[1] / winSize[1];
    viewPort[2] = viewPort[0] + static_cast<double>(this->Size[0]) / winSize[0];
    viewPort[3] = viewPort[1] + static_cast<double>(this->Size[1]) / winSize[1];
    viewPort[2] = (viewPort[2] > vpxMax ? vpxMax : viewPort[2]);
    viewPort[3] = (viewPort[3] > vpyMax ? vpyMax : viewPort[3]);
  
    this->MagnificationRenderer->SetViewport(viewPort);
  
    // Update the magnificationcamera
    // Grab the containing renderer's camera and copy it. Adjust the view angle
    vtkCamera* cam = this->Renderer->GetActiveCamera();
    double viewAngle = cam->GetViewAngle();
    vtkCamera* magCam = this->MagnificationRenderer->GetActiveCamera();
    magCam->DeepCopy(cam);
    magCam->SetViewAngle(viewAngle / this->MagnificationFactor);
  
    // Specify the focal point
    this->Coordinate->SetValue(XF, YF);
    double* focal = this->Coordinate->GetComputedWorldValue(this->Renderer);
    this->MagnificationRenderer->GetActiveCamera()->SetFocalPoint(focal);
  
    // Setup the border if requested. We offset the border slightly to
    // accomodate the width of the line.
    if (this->Border)
    {
      this->BorderPoints->SetPoint(0, 1, 1, 0.0);
      this->BorderPoints->SetPoint(1, (this->Size[0] - 1), 1, 0.0);
      this->BorderPoints->SetPoint(2, (this->Size[0] - 1), (this->Size[1] - 1), 0.0);
      this->BorderPoints->SetPoint(3, 1, (this->Size[1] - 1), 0.0);
    }
  }
  
  //------------------------------------------------------------------------------
  // This method is invoked when this class or dependent classes change (based
  // on modified time).
  void vtkMagnifierRepresentation::BuildRepresentation()
  {
    // Make sure a renderer and render window are available
    if (!this->Renderer || !this->Renderer->GetRenderWindow())
    {
      return;
    }
  
    // If we've been turned off, make it so
    if (this->InteractionState == Invisible || !this->InsideRenderer)
    {
      this->Renderer->GetRenderWindow()->RemoveRenderer(this->MagnificationRenderer);
      return;
    }
  
    // Set up the renderer and build the border if requested.
    // Add the magnification renderer to the render window
    this->Renderer->GetRenderWindow()->AddRenderer(this->MagnificationRenderer);
  
    // If props are specifically listed, add them to the magnification
    // renderer. Otherwise, use the containing renderer's props.
    this->MagnificationRenderer->RemoveAllViewProps();
    vtkPropCollection* props;
    if (this->Props->GetNumberOfItems() > 0)
    {
      props = this->Props;
    }
    else
    {
      props = this->Renderer->GetViewProps();
    }
    int numItems = props->GetNumberOfItems();
    props->InitTraversal();
    for (auto i = 0; i < numItems; ++i)
    {
      this->MagnificationRenderer->AddViewProp(static_cast<vtkProp*>(props->GetNextItemAsObject()));
    }
  
    // Add the border if desired
    if (this->Border)
    {
      this->MagnificationRenderer->AddViewProp(this->BorderActor);
    }
  }
  
  //------------------------------------------------------------------------------
  vtkMTimeType vtkMagnifierRepresentation::GetMTime()
  {
    vtkMTimeType mTime = this->Superclass::GetMTime();
    mTime = std::max(mTime, this->BorderProperty->GetMTime());
    return mTime;
  }
  
  //------------------------------------------------------------------------------
  // Optionally, use different view props than that used by the associated
  // renderer. This enables special effects etc during magnification (or the
  // ability to remove props from the scence like widgets etc).
  void vtkMagnifierRepresentation::AddViewProp(vtkProp* prop)
  {
    this->Props->AddItem(prop);
  }
  
  //------------------------------------------------------------------------------
  int vtkMagnifierRepresentation::HasViewProp(vtkProp* prop)
  {
    return (prop && this->Props->IsItemPresent(prop));
  }
  
  //------------------------------------------------------------------------------
  void vtkMagnifierRepresentation::RemoveViewProp(vtkProp* prop)
  {
    this->Props->RemoveItem(prop);
  }
  
  //------------------------------------------------------------------------------
  void vtkMagnifierRepresentation::RemoveAllViewProps()
  {
    return this->Props->RemoveAllItems();
  }
  
  //------------------------------------------------------------------------------
  void vtkMagnifierRepresentation::ReleaseGraphicsResources(vtkWindow* w)
  {
    this->BorderActor->ReleaseGraphicsResources(w);
  }
  
  //------------------------------------------------------------------------------
  int vtkMagnifierRepresentation::RenderOverlay(vtkViewport* w)
  {
    if (this->Border && w == this->MagnificationRenderer)
    {
      this->BuildRepresentation();
      return this->BorderActor->RenderOverlay(w);
    }
    return 0;
  }
  
  //------------------------------------------------------------------------------
  int vtkMagnifierRepresentation::RenderOpaqueGeometry(vtkViewport* w)
  {
    if (this->Border && w == this->MagnificationRenderer)
    {
      this->BuildRepresentation();
      return this->BorderActor->RenderOpaqueGeometry(w);
    }
    return 0;
  }
  
  //------------------------------------------------------------------------------
  int vtkMagnifierRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport* w)
  {
    if (this->Border && w == this->MagnificationRenderer)
    {
      this->BuildRepresentation();
      return this->BorderActor->RenderTranslucentPolygonalGeometry(w);
    }
    return 0;
  }
  
  //------------------------------------------------------------------------------
  // Description:
  // Does this prop have some translucent polygonal geometry?
  vtkTypeBool vtkMagnifierRepresentation::HasTranslucentPolygonalGeometry()
  {
    if (this->Border)
    {
      this->BuildRepresentation();
      return this->BorderActor->HasTranslucentPolygonalGeometry();
    }
    return false;
  }
  
  //------------------------------------------------------------------------------
  void vtkMagnifierRepresentation::PrintSelf(ostream& os, vtkIndent indent)
  {
    this->Superclass::PrintSelf(os, indent);
  
    os << indent
       << "Interaction State: " << (this->InteractionState == Visible ? "Visible\n" : "Invisible\n");
  
    os << indent << "Magnification Factor: " << this->MagnificationFactor << "\n";
  
    os << indent << "Props:\n";
    this->Props->PrintSelf(os, indent.GetNextIndent());
  
    os << indent << "Size: " << this->Size[0] << " " << this->Size[1] << endl;
  
    os << indent << "Border: " << (this->Border ? "On\n" : "Off\n");
  
    if (this->BorderProperty)
    {
      os << indent << "Border Property:\n";
      this->BorderProperty->PrintSelf(os, indent.GetNextIndent());
    }
    else
    {
      os << indent << "Border Property: (none)\n";
    }
  }
  