text: /*===================================================================
  
  The Medical Imaging Interaction Toolkit (MITK)
  
  Copyright (c) German Cancer Research Center,
  Division of Medical and Biological Informatics.
  All rights reserved.
  
  This software is distributed WITHOUT ANY WARRANTY; without
  even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.
  
  See LICENSE.txt or http://www.mitk.org for details.
  
  ===================================================================*/
  
  #include "mitkAffineImageCropperInteractor.h"
  
  #include "mitkInteractionConst.h"
  #include "mitkInteractionPositionEvent.h"
  #include "mitkRotationOperation.h"
  #include "mitkSurface.h"
  #include "mitkVtkMapper.h"
  
  #include <mitkMouseWheelEvent.h>
  #include <vtkCamera.h>
  #include <vtkInteractorStyle.h>
  #include <vtkMatrix4x4.h>
  #include <vtkPointData.h>
  #include <vtkPolyData.h>
  #include <vtkRenderWindowInteractor.h>
  #include <mitkBoundingObject.h>
  
  #include <mitkScaleOperation.h>
  #include <mitkRotationOperation.h>
  
  mitk::AffineImageCropperInteractor::AffineImageCropperInteractor()
  {
    m_OriginalGeometry = Geometry3D::New();
  }
  
  mitk::AffineImageCropperInteractor::~AffineImageCropperInteractor()
  {
  }
  
  void mitk::AffineImageCropperInteractor::ConnectActionsAndFunctions()
  {
    // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually executing an action
    CONNECT_CONDITION("isOverObject", CheckOverObject);
  
    // **Function** in the statmachine patterns also referred to as **Actions**
    CONNECT_FUNCTION("selectObject",SelectObject);
    CONNECT_FUNCTION("deselectObject",DeselectObject);
    CONNECT_FUNCTION("initTranslate",InitTranslate);
    CONNECT_FUNCTION("initRotate",InitRotate);
    CONNECT_FUNCTION("initDeformation",InitDeformation);
    CONNECT_FUNCTION("translateObject",TranslateObject);
    CONNECT_FUNCTION("rotateObject",RotateObject);
    CONNECT_FUNCTION("deformObject",DeformObject);
    CONNECT_FUNCTION("scaleRadius",ScaleRadius);
  }
  
  void mitk::AffineImageCropperInteractor::DataNodeChanged()
  {
  }
  
  bool mitk::AffineImageCropperInteractor::CheckOverObject(const InteractionEvent* interactionEvent)
  {
    mitk::DataNode::Pointer dn = this->GetDataNode();
    if (dn.IsNull())
      return false;
    const InteractionPositionEvent* positionEvent = dynamic_cast<const InteractionPositionEvent*>(interactionEvent);
    Point3D currentPickedPoint = positionEvent->GetPlanePositionInWorld();
    mitk::BoundingObject* object = dynamic_cast<mitk::BoundingObject*> (dn->GetData());
    object->GetGeometry()->WorldToIndex(currentPickedPoint,currentPickedPoint);
    return object && object->GetGeometry()->GetBoundingBox()->IsInside(currentPickedPoint);
  }
  
  void mitk::AffineImageCropperInteractor::SelectObject(StateMachineAction*, InteractionEvent* interactionEvent)
  {
    mitk::DataNode::Pointer dn = this->GetDataNode();
  
    if (dn.IsNull())
      return;
  
    m_SelectedNode = dn;
  
    interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
  }
  
  void mitk::AffineImageCropperInteractor::Deselect()
  {
    mitk::DataNode::Pointer dn = this->GetDataNode();
  
    if (dn.IsNull())
      return;
  
    m_SelectedNode = dn;
  }
  
  void mitk::AffineImageCropperInteractor::DeselectObject(StateMachineAction*, InteractionEvent* interactionEvent)
  {
    Deselect();
    interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
  }
  
  void mitk::AffineImageCropperInteractor::ScaleRadius(StateMachineAction*, InteractionEvent* interactionEvent)
  {
    const MouseWheelEvent* wheelEvent = dynamic_cast<const MouseWheelEvent*>(interactionEvent);
    if(wheelEvent == NULL)
      return;
  
    if (m_SelectedNode.IsNull())
      return;
  
    double scale = (double) (wheelEvent->GetWheelDelta()) / 64.0;
    mitk::Point3D newScale;
    newScale[0] = newScale[1] = newScale[2] = scale;
  
    mitk::Point3D anchorPoint = wheelEvent->GetPlanePositionInWorld();
    ScaleOperation* doOp = new mitk::ScaleOperation(OpSCALE, newScale, anchorPoint);
    m_SelectedNode->GetData()->GetGeometry()->ExecuteOperation(doOp);
  
    interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
  }
  
  void mitk::AffineImageCropperInteractor::InitTranslate(StateMachineAction*, InteractionEvent* interactionEvent)
  {
    if(m_SelectedNode.IsNull()) return;
    InteractionPositionEvent* positionEvent = dynamic_cast<InteractionPositionEvent*>(interactionEvent);
    if(positionEvent == NULL)
      return;
  
    m_InitialPickedPoint = positionEvent->GetPlanePositionInWorld();
    m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
  
    mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface*> (m_SelectedNode->GetData());
    mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry();
    m_InitialOrigin = surGeo->GetOrigin();
  }
  
  void mitk::AffineImageCropperInteractor::InitRotate(StateMachineAction*, InteractionEvent* interactionEvent)
  {
    InteractionPositionEvent* positionEvent = dynamic_cast<InteractionPositionEvent*>(interactionEvent);
    if(positionEvent == NULL)
      return;
  
    m_InitialPickedPoint = positionEvent->GetPlanePositionInWorld();
    m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
  
    mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface*> (m_SelectedNode->GetData());
    mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry();
    m_OriginalGeometry = dynamic_cast<mitk::Geometry3D*> (surGeo.GetPointer());
  }
  
  void mitk::AffineImageCropperInteractor::InitDeformation(StateMachineAction*, InteractionEvent* interactionEvent)
  {
    InteractionPositionEvent* positionEvent = dynamic_cast<InteractionPositionEvent*>(interactionEvent);
    if(positionEvent == NULL)
      return;
  
    m_InitialPickedPoint = positionEvent->GetPlanePositionInWorld();
    m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
  
    mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface*> (m_SelectedNode->GetData());
    mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry();
    m_OriginalGeometry = dynamic_cast<mitk::Geometry3D*> (surGeo.GetPointer());
  }
  
  void mitk::AffineImageCropperInteractor::TranslateObject (StateMachineAction*, InteractionEvent* interactionEvent)
  {
    InteractionPositionEvent* positionEvent = dynamic_cast<InteractionPositionEvent*>(interactionEvent);
    if(positionEvent == NULL)
      return;
  
    Point3D currentPickedPoint = positionEvent->GetPlanePositionInWorld();
  
    Vector3D interactionMove;
    interactionMove[0] = currentPickedPoint[0] - m_InitialPickedPoint[0];
    interactionMove[1] = currentPickedPoint[1] - m_InitialPickedPoint[1];
    interactionMove[2] = currentPickedPoint[2] - m_InitialPickedPoint[2];
  
    mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface*> (m_SelectedNode->GetData());
    mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry();
    surGeo->SetOrigin(m_InitialOrigin);
    surGeo->Translate(interactionMove);
  
    interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
  }
  
  void mitk::AffineImageCropperInteractor::DeformObject (StateMachineAction*, InteractionEvent* interactionEvent)
  {
    InteractionPositionEvent* positionEvent = dynamic_cast<InteractionPositionEvent*>(interactionEvent);
    if(positionEvent == NULL)
      return;
  
    Point3D currentPickedPoint = positionEvent->GetPlanePositionInWorld();
    Vector3D interactionMove = currentPickedPoint-m_InitialPickedPoint;
  
    mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface*> (m_SelectedNode->GetData());
    surface->SetGeometry(m_OriginalGeometry);
    mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry();
  
    surGeo->WorldToIndex(interactionMove,interactionMove);
    Point3D scale;
    for(int i = 0 ; i<3 ; ++i)
    {
      scale[i] = (interactionMove[i]*surGeo->GetMatrixColumn(i).magnitude())-1;
    }
  
    mitk::Point3D anchorPoint = surGeo->GetCenter();
  
    ScaleOperation* doOp = new mitk::ScaleOperation(OpSCALE, scale, anchorPoint);
    surGeo->ExecuteOperation(doOp);
  
    mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  }
  
  void mitk::AffineImageCropperInteractor::RotateObject (StateMachineAction*, InteractionEvent* interactionEvent)
  {
    InteractionPositionEvent* positionEvent = dynamic_cast<InteractionPositionEvent*>(interactionEvent);
    if(positionEvent == NULL)
      return;
  
    Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
    if(currentPickedDisplayPoint.EuclideanDistanceTo(m_InitialPickedDisplayPoint) < 1)
      return;
  
    vtkRenderer* currentVtkRenderer = interactionEvent->GetSender()->GetVtkRenderer();
  
    if ( currentVtkRenderer &&  currentVtkRenderer->GetActiveCamera())
    {
      double vpn[3];
      currentVtkRenderer->GetActiveCamera()->GetViewPlaneNormal( vpn );
  
      Vector3D rotationAxis;
      rotationAxis[0] = vpn[0];
      rotationAxis[1] = vpn[1];
      rotationAxis[2] = vpn[2];
      rotationAxis.Normalize();
  
      Vector2D move = currentPickedDisplayPoint - m_InitialPickedDisplayPoint;
  
      double rotationAngle = -57.3 * atan(move[0]/move[1]);
      if(move[1]<0) rotationAngle +=180;
  
      // Use center of data bounding box as center of rotation
      Point3D rotationCenter = m_OriginalGeometry->GetCenter();
      if(positionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard2D)
        rotationCenter = m_InitialPickedPoint;
  
      // Reset current Geometry3D to original state (pre-interaction) and
      // apply rotation
      RotationOperation op( OpROTATE, rotationCenter, rotationAxis, rotationAngle );
      Geometry3D::Pointer newGeometry = static_cast<Geometry3D*>(m_OriginalGeometry->Clone().GetPointer());
      newGeometry->ExecuteOperation( &op );
      m_SelectedNode->GetData()->SetGeometry(newGeometry);
  
      interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
    }
  }
  