void mitk::PlanarFigureInteractor::EndInteraction( StateMachineAction*, InteractionEvent* interactionEvent )
{
  mitk::PlanarFigure *planarFigure = dynamic_cast<mitk::PlanarFigure *>( GetDataNode()->GetData() );
  GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
  planarFigure->Modified();
  planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );
  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
}
void mitk::PlanarFigureInteractor::DeselectPoint(StateMachineAction*, InteractionEvent* /*interactionEvent*/)
{
  mitk::PlanarFigure *planarFigure = dynamic_cast<mitk::PlanarFigure *>(
    GetDataNode()->GetData() );

  const bool wasSelected = planarFigure->DeselectControlPoint();
  if ( wasSelected )
  {
    // Issue event so that listeners may update themselves
    planarFigure->Modified();
    planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );

    GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
//    GetDataNode()->SetBoolProperty( "planarfigure.ishovering", false );
    GetDataNode()->Modified();
  }
}
bool mitk::PlanarFigureInteractor::FinalizeFigure( StateMachineAction*, InteractionEvent* interactionEvent )
{
  mitk::PlanarFigure *planarFigure = dynamic_cast<mitk::PlanarFigure *>( GetDataNode()->GetData() );

  planarFigure->Modified();
  planarFigure->DeselectControlPoint();
  planarFigure->RemoveLastControlPoint();
  planarFigure->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) );
  GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
  GetDataNode()->Modified();
  planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() );
  planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );

  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();

  return false;
}
void mitk::PlanarFigureInteractor::RemoveSelectedPoint(StateMachineAction*, InteractionEvent* interactionEvent)
{
  mitk::PlanarFigure *planarFigure = dynamic_cast<mitk::PlanarFigure *>( GetDataNode()->GetData() );
  mitk::BaseRenderer *renderer = interactionEvent->GetSender();

  const int selectedControlPoint = planarFigure->GetSelectedControlPoint();
  planarFigure->RemoveControlPoint( selectedControlPoint );

  // Re-evaluate features
  planarFigure->EvaluateFeatures();
  planarFigure->Modified();

  GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
  planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );
  renderer->GetRenderingManager()->RequestUpdateAll();

  HandleEvent( mitk::InternalEvent::New( renderer, this, "Dummy-Event" ), GetDataNode() );
}
void mitk::PlanarFigureInteractor::FinalizeFigure( StateMachineAction*, InteractionEvent* interactionEvent )
{
  mitk::PlanarFigure *planarFigure = dynamic_cast<mitk::PlanarFigure *>( GetDataNode()->GetData() );

  planarFigure->Modified();
  planarFigure->DeselectControlPoint();
  planarFigure->RemoveLastControlPoint();
  planarFigure->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) );
  GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
  GetDataNode()->Modified();
  planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() );
  planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );

  // Shape might change when figure is finalized, e.g., smoothing of subdivision polygon
  planarFigure->EvaluateFeatures();

  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
}
bool mitk::PlanarFigureInteractor
::ExecuteAction( Action *action, mitk::StateEvent const *stateEvent )
{
  bool ok = false;

  // Check corresponding data; has to be sub-class of mitk::PlanarFigure
  mitk::PlanarFigure *planarFigure =
    dynamic_cast< mitk::PlanarFigure * >( m_DataNode->GetData() );

  if ( planarFigure == NULL )
  {
    return false;
  }

  // Get the timestep to also support 3D+t
  const mitk::Event *theEvent = stateEvent->GetEvent();
  int timeStep = 0;
  //mitk::ScalarType timeInMS = 0.0;

  if ( theEvent )
  {
    if (theEvent->GetSender() != NULL)
    {
      timeStep = theEvent->GetSender()->GetTimeStep( planarFigure );
      //timeInMS = theEvent->GetSender()->GetTime();
    }
  }

  // Get Geometry2D of PlanarFigure
  mitk::Geometry2D *planarFigureGeometry =
    dynamic_cast< mitk::Geometry2D * >( planarFigure->GetGeometry( timeStep ) );

  // Get the Geometry2D of the window the user interacts with (for 2D point
  // projection)
  mitk::BaseRenderer *renderer = NULL;
  const Geometry2D *projectionPlane = NULL;
  if ( theEvent )
  {
    renderer = theEvent->GetSender();
    projectionPlane = renderer->GetCurrentWorldGeometry2D();
  }

  // TODO: Check if display and PlanarFigure geometries are parallel (if they are PlaneGeometries)



  switch (action->GetActionId())
  {
  case AcDONOTHING:
    PLANARFIGUREINTERACTOR_DBG << "AcDONOTHING";
    ok = true;
    break;

  case AcCHECKOBJECT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcCHECKOBJECT";
      if ( planarFigure->IsPlaced() )
      {
        this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) );
      }
      else
      {
        this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
      }
      ok = false;
      break;
    }

  case AcADD:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcADD";
      // Invoke event to notify listeners that placement of this PF starts now
      planarFigure->InvokeEvent( StartPlacementPlanarFigureEvent() );

      // Use Geometry2D of the renderer clicked on for this PlanarFigure
      mitk::PlaneGeometry *planeGeometry = const_cast< mitk::PlaneGeometry * >(
        dynamic_cast< const mitk::PlaneGeometry * >(
        renderer->GetSliceNavigationController()->GetCurrentPlaneGeometry() ) );
      if ( planeGeometry != NULL )
      {
        planarFigureGeometry = planeGeometry;
        planarFigure->SetGeometry2D( planeGeometry );
      }
      else
      {
        ok = false;
        break;
      }

      // Extract point in 2D world coordinates (relative to Geometry2D of
      // PlanarFigure)
      Point2D point2D;
      if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D,
        planarFigureGeometry ) )
      {
        ok = false;
        break;
      }

      // Place PlanarFigure at this point
      planarFigure->PlaceFigure( point2D );

      // Re-evaluate features
      planarFigure->EvaluateFeatures();
      //this->LogPrintPlanarFigureQuantities( planarFigure );

      // Set a bool property indicating that the figure has been placed in
      // the current RenderWindow. This is required so that the same render
      // window can be re-aligned to the Geometry2D of the PlanarFigure later
      // on in an application.
      m_DataNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, renderer );

      // Update rendered scene
      renderer->GetRenderingManager()->RequestUpdateAll();

      ok = true;
      break;
    }

  case AcMOVEPOINT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcMOVEPOINT";
      bool isEditable = true;
      m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable );

      // Extract point in 2D world coordinates (relative to Geometry2D of
      // PlanarFigure)
      Point2D point2D;
      if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D,
        planarFigureGeometry ) || !isEditable )
      {
        ok = false;
        break;
      }

      // check if the control points shall be hidden during interaction
      bool hidecontrolpointsduringinteraction = false;
      m_DataNode->GetBoolProperty( "planarfigure.hidecontrolpointsduringinteraction", hidecontrolpointsduringinteraction );

      // hide the control points if necessary
      m_DataNode->SetBoolProperty( "planarfigure.drawcontrolpoints", !hidecontrolpointsduringinteraction );

      // Move current control point to this point
      planarFigure->SetCurrentControlPoint( point2D );

      // Re-evaluate features
      planarFigure->EvaluateFeatures();
      //this->LogPrintPlanarFigureQuantities( planarFigure );

      // Update rendered scene
      renderer->GetRenderingManager()->RequestUpdateAll();

      ok = true;
      break;
    }


  case AcCHECKNMINUS1:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcCHECKNMINUS1";

      if ( planarFigure->GetNumberOfControlPoints() >=
        planarFigure->GetMaximumNumberOfControlPoints() )
      {
        // Initial placement finished: deselect control point and send an
        // event to notify application listeners
        planarFigure->Modified();
        planarFigure->DeselectControlPoint();
        planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() );
        planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );
        planarFigure->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) );
        m_DataNode->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
        m_DataNode->Modified();
        this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );
      }
      else
      {
        this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );
      }

      // Update rendered scene
      renderer->GetRenderingManager()->RequestUpdateAll();

      ok = true;
      break;
    }


  case AcCHECKEQUALS1:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcCHECKEQUALS1";

      // NOTE: Action name is a bit misleading; this action checks whether
      // the figure has already the minimum number of required points to
      // be finished (by double-click)

      const mitk::PositionEvent *positionEvent =
        dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() );
      if ( positionEvent == NULL )
      {
        ok = false;
        break;
      }

      if ( planarFigure->GetNumberOfControlPoints() > planarFigure->GetMinimumNumberOfControlPoints()  )
      {
        // Initial placement finished: deselect control point and send an
        // event to notify application listeners
        planarFigure->Modified();
        planarFigure->DeselectControlPoint();
        planarFigure->RemoveLastControlPoint();
        planarFigure->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) );
        m_DataNode->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
        m_DataNode->Modified();
        planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() );
        planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );

        this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) );
      }
      else
      {
        this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
      }

      // Update rendered scene
      renderer->GetRenderingManager()->RequestUpdateAll();

      ok = true;
      break;
    }


  case AcCHECKPOINT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcCHECKPOINT";
      // Check if the distance of the current point to the previously set point in display coordinates
      // is sufficient (if a previous point exists)

      // Extract display position
      const mitk::PositionEvent *positionEvent =
        dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() );
      if ( positionEvent == NULL )
      {
        ok = false;
        break;
      }

      m_LastPointWasValid = IsMousePositionAcceptableAsNewControlPoint( stateEvent, planarFigure );
      if (m_LastPointWasValid)
      {
        this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );
      }
      else
      {
        this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );
      }

      ok = true;
      break;
    }


  case AcADDPOINT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcADDPOINT";
      bool selected = false;
      bool isEditable = true;
      m_DataNode->GetBoolProperty("selected", selected);
      m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable );

      if ( !selected || !isEditable )
      {
        ok = false;
        break;
      }

      // Extract point in 2D world coordinates (relative to Geometry2D of
      // PlanarFigure)
      Point2D point2D, projectedPoint;
      if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D,
        planarFigureGeometry ) )
      {
        ok = false;
        break;
      }

      // TODO: check segement of polyline we clicked in
      int nextIndex = -1;

      // We only need to check which position to insert the control point
      // when interacting with a PlanarPolygon. For all other types
      // new control points will always be appended

      /*
       * Added check for "initiallyplaced" due to bug 13097:
       *
       * There are two possible cases in which a point can be inserted into a PlanarPolygon:
       *
       * 1. The figure is currently drawn -> the point will be appended at the end of the figure
       * 2. A point is inserted at a userdefined position after the initial placement of the figure is finished
       *
       * In the second case we need to determine the proper insertion index. In the first case the index always has
       * to be -1 so that the point is appended to the end.
       *
       * These changes are neccessary because of a mac os x specific issue: If a users draws a PlanarPolygon then the
       * next point to be added moves according to the mouse position. If then the user left clicks in order to add
       * a point one would assume the last move position is identical to the left click position. This is actually the
       * case for windows and linux but somehow NOT for mac. Because of the insertion logic of a new point in the
       * PlanarFigure then for mac the wrong current selected point is determined.
       *
       * With this check here this problem can be avoided. However a redesign of the insertion logic should be considered
       */
      bool isFigureFinished = false;
      planarFigure->GetPropertyList()->GetBoolProperty( "initiallyplaced", isFigureFinished );

      if ( dynamic_cast<mitk::PlanarPolygon*>( planarFigure ) && isFigureFinished)
      {
        nextIndex = this->IsPositionOverFigure(
          stateEvent, planarFigure,
          planarFigureGeometry,
          projectionPlane,
          renderer->GetDisplayGeometry(),
          projectedPoint
          );
      }


      // Add point as new control point
      renderer->GetDisplayGeometry()->DisplayToWorld( projectedPoint, projectedPoint );

      if ( planarFigure->IsPreviewControlPointVisible() )
      {
        point2D = planarFigure->GetPreviewControlPoint();
      }

      planarFigure->AddControlPoint( point2D, nextIndex );

      if ( planarFigure->IsPreviewControlPointVisible() )
      {
        planarFigure->SelectControlPoint( nextIndex );
        planarFigure->ResetPreviewContolPoint();
      }

      // Re-evaluate features
      planarFigure->EvaluateFeatures();
      //this->LogPrintPlanarFigureQuantities( planarFigure );

      // Update rendered scene
      renderer->GetRenderingManager()->RequestUpdateAll();

      ok = true;
      break;
    }


  case AcDESELECTPOINT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcDESELECTPOINT";
      planarFigure->DeselectControlPoint();

      // Issue event so that listeners may update themselves
      planarFigure->Modified();
      planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );

      m_DataNode->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
      m_DataNode->SetBoolProperty( "planarfigure.ishovering", false );
      m_DataNode->Modified();

      // falls through
      break;
    }

  case AcCHECKHOVERING:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcCHECKHOVERING";
      mitk::Point2D pointProjectedOntoLine;
      int previousControlPoint = mitk::PlanarFigureInteractor::IsPositionOverFigure(
        stateEvent, planarFigure,
        planarFigureGeometry,
        projectionPlane,
        renderer->GetDisplayGeometry(),
        pointProjectedOntoLine
        );
      bool isHovering = ( previousControlPoint != -1 );

      int pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker(
        stateEvent, planarFigure,
        planarFigureGeometry,
        projectionPlane,
        renderer->GetDisplayGeometry() );

      int initiallySelectedControlPoint = planarFigure->GetSelectedControlPoint();

      if ( pointIndex >= 0 )
      {
        // If mouse is above control point, mark it as selected
        planarFigure->SelectControlPoint( pointIndex );

        // If mouse is hovering above a marker, it is also hovering above the figure
        isHovering = true;
      }
      else
      {
        // Mouse in not above control point --> deselect point
        planarFigure->DeselectControlPoint();
      }

      bool renderingUpdateNeeded = true;
      if ( isHovering )
      {
        if ( !m_IsHovering )
        {
          // Invoke hover event once when the mouse is entering the figure area
          m_IsHovering = true;
          planarFigure->InvokeEvent( StartHoverPlanarFigureEvent() );

          // Set bool property to indicate that planar figure is currently in "hovering" mode
          m_DataNode->SetBoolProperty( "planarfigure.ishovering", true );

          renderingUpdateNeeded = true;
        }

        bool selected = false;
        bool isExtendable = false;
        bool isEditable = true;
        m_DataNode->GetBoolProperty("selected", selected);
        m_DataNode->GetBoolProperty("planarfigure.isextendable", isExtendable);
        m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable );

        if ( selected && isHovering && isExtendable && pointIndex == -1 && isEditable )
        {
          const mitk::PositionEvent *positionEvent =
            dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() );
          if ( positionEvent != NULL )
          {
            renderer->GetDisplayGeometry()->DisplayToWorld( pointProjectedOntoLine, pointProjectedOntoLine );
            planarFigure->SetPreviewControlPoint( pointProjectedOntoLine );

            renderingUpdateNeeded = true;
          }
        }
        else
        {
          planarFigure->ResetPreviewContolPoint();
        }

        if ( planarFigure->GetSelectedControlPoint() != initiallySelectedControlPoint  )
        {
          // the selected control point has changed -> rendering update necessary
          renderingUpdateNeeded = true;
        }

        this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );

        // Return true: only this interactor is eligible to react on this event
        ok = true;
      }
      else
      {
        if ( m_IsHovering )
        {
          planarFigure->ResetPreviewContolPoint();

          // Invoke end-hover event once the mouse is exiting the figure area
          m_IsHovering = false;
          planarFigure->InvokeEvent( EndHoverPlanarFigureEvent() );

          // Set bool property to indicate that planar figure is no longer in "hovering" mode
          m_DataNode->SetBoolProperty( "planarfigure.ishovering", false );

          renderingUpdateNeeded = true;
        }

        this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );

        // Return false so that other (PlanarFigure) Interactors may react on this
        // event as well
        ok = false;
      }

      // Update rendered scene if necessray
      if ( renderingUpdateNeeded )
      {
        renderer->GetRenderingManager()->RequestUpdateAll();
      }
      break;
    }

  case AcCHECKSELECTED:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcCHECKSELECTED";
      bool selected = false;
      m_DataNode->GetBoolProperty("selected", selected);

      if ( selected )
      {
        this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );
      }
      else
      {
        // Invoke event to notify listeners that this planar figure should be selected
        planarFigure->InvokeEvent( SelectPlanarFigureEvent() );
        this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
      }
    }

  case AcSELECTPICKEDOBJECT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcSELECTPICKEDOBJECT";
      //// Invoke event to notify listeners that this planar figure should be selected
      //planarFigure->InvokeEvent( SelectPlanarFigureEvent() );
      //planarFigure->InvokeEvent( StartInteractionPlanarFigureEvent() );

      // Check if planar figure is marked as "editable"
      bool isEditable = true;
      m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable );

      int pointIndex = -1;

      if ( isEditable )
      {
        // If planar figure is editable, check if mouse is over a control point
        pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker(
          stateEvent, planarFigure,
          planarFigureGeometry,
          projectionPlane,
          renderer->GetDisplayGeometry() );
      }

      // If editing is enabled and the mouse is currently over a control point, select it
      if ( pointIndex >= 0 )
      {
        this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );

        // Return true: only this interactor is eligible to react on this event
        ok = true;
      }
      else
      {
        // we're not hovering above a control point -> deselect!
        planarFigure->DeselectControlPoint();

        this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );

        // Return false so that other (PlanarFigure) Interactors may react on this
        // event as well
        ok = false;
      }

      ok = true;
      break;
    }

  case AcENTEROBJECT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcENTEROBJECT";
      bool selected = false;
      m_DataNode->GetBoolProperty("selected", selected);

      // no need to invoke this if the figure is already selected
      if ( !selected )
      {
        planarFigure->InvokeEvent( SelectPlanarFigureEvent() );
      }

      planarFigure->InvokeEvent( ContextMenuPlanarFigureEvent() );
      ok = true;

      // we HAVE TO proceed with 'EIDNO' here to ensure correct states
      // and convenient application behaviour
      this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );
      break;
    }


  case AcSELECTPOINT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcSELECTPOINT";
      // Invoke event to notify listeners that interaction with this PF starts now
      planarFigure->InvokeEvent( StartInteractionPlanarFigureEvent() );

      // Reset the PlanarFigure if required
      if ( planarFigure->ResetOnPointSelect() )
      {
        this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );
      }
      else
      {
        this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );
      }

      ok = true;
      break;
    }

  case AcREMOVEPOINT:
    {
      PLANARFIGUREINTERACTOR_DBG << "AcREMOVEPOINT";
      bool isExtendable = false;
      m_DataNode->GetBoolProperty("planarfigure.isextendable", isExtendable);

      if ( isExtendable )
      {
        int selectedControlPoint = planarFigure->GetSelectedControlPoint();
        planarFigure->RemoveControlPoint( selectedControlPoint );

        // Re-evaluate features
        planarFigure->EvaluateFeatures();
        planarFigure->Modified();

        m_DataNode->SetBoolProperty( "planarfigure.drawcontrolpoints", true );
        planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );
        renderer->GetRenderingManager()->RequestUpdateAll();
        this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) );
      }
      else
      {
        this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
      }
    }

    //case AcMOVEPOINT:
    //case AcMOVESELECTED:
    //  {
    //    // Update the display
    //    renderer->GetRenderingManager()->RequestUpdateAll();

    //    ok = true;
    //    break;
    //  }

    //case AcFINISHMOVE:
    //  {
    //    ok = true;
    //    break;
    //  }

  default:
    return Superclass::ExecuteAction( action, stateEvent );
  }




  return ok;
}