diff --git a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp index b05028508d..8437de9f49 100644 --- a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp +++ b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp @@ -1,764 +1,882 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-10-02 16:21:08 +0200 (Do, 02 Okt 2008) $ Version: $Revision: 13129 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html 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 notices for more information. =========================================================================*/ #include "mitkPlanarFigureInteractor.h" #include "mitkPointOperation.h" #include "mitkPositionEvent.h" #include "mitkPlanarFigure.h" #include "mitkStatusBar.h" #include "mitkDataNode.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkStateEvent.h" #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkStateMachineFactory.h" #include "mitkStateTransitionOperation.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" //how precise must the user pick the point //default value mitk::PlanarFigureInteractor ::PlanarFigureInteractor(const char * type, DataNode* dataNode, int /* n */ ) : Interactor( type, dataNode ), - m_Precision( 6.5 ), - m_IsHovering( false ) +m_Precision( 6.5 ), +m_IsHovering( false ) { } mitk::PlanarFigureInteractor::~PlanarFigureInteractor() { } void mitk::PlanarFigureInteractor::SetPrecision( mitk::ScalarType precision ) { m_Precision = precision; } // Overwritten since this class can handle it better! float mitk::PlanarFigureInteractor ::CanHandleEvent(StateEvent const* stateEvent) const { float returnValue = 0.5; - + // If it is a key event that can be handled in the current state, // then return 0.5 mitk::DisplayPositionEvent const *disPosEvent = dynamic_cast (stateEvent->GetEvent()); // Key event handling: if (disPosEvent == NULL) { // Check if the current state has a transition waiting for that key event. if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) { return 0.5; } else { return 0.0; } } mitk::PlanarFigure *planarFigure = dynamic_cast( m_DataNode->GetData() ); if ( planarFigure != NULL ) { // Give higher priority if this figure is currently selected if ( planarFigure->GetSelectedControlPoint() >= 0 ) { return 1.0; } } return returnValue; } 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: ok = true; break; case AcCHECKOBJECT: { if ( planarFigure->IsPlaced() ) { this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) ); } else { this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) ); } ok = false; break; } case 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() ) ); + 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: { // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) Point2D point2D; if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D, planarFigureGeometry ) ) { ok = false; break; } // 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: { if ( planarFigure->GetNumberOfControlPoints() >= - planarFigure->GetMaximumNumberOfControlPoints() ) + 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() ); 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: { // NOTE: Action name is a bit misleading; this action checks whether // the figure has already the minimum number of required points to // be finished. if ( planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMinimumNumberOfControlPoints() ) { // Initial placement finished: deselect control point and send an // event to notify application listeners planarFigure->Modified(); planarFigure->DeselectControlPoint(); if ( planarFigure->GetNumberOfControlPoints()-1 >= planarFigure->GetMinimumNumberOfControlPoints() ) { planarFigure->RemoveLastControlPoint(); } planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() ); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); m_DataNode->Modified(); 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: { // 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; } // Get current display position of the mouse mitk::Point2D currentDisplayPosition = positionEvent->GetDisplayPosition(); // Check if a previous point has been set int previousIndex = planarFigure->GetNumberOfControlPoints() - 2; if ( previousIndex >= 0 ) { - + // Try to convert previous point to current display coordinates mitk::Point3D previousPoint3D; planarFigureGeometry->Map( planarFigure->GetControlPoint( previousIndex ), previousPoint3D ); if ( renderer->GetDisplayGeometry()->Distance( previousPoint3D ) < 0.1 ) { mitk::Point2D previousDisplayPosition; projectionPlane->Map( previousPoint3D, previousDisplayPosition ); renderer->GetDisplayGeometry()->WorldToDisplay( previousDisplayPosition, previousDisplayPosition ); double a = currentDisplayPosition[0] - previousDisplayPosition[0]; double b = currentDisplayPosition[1] - previousDisplayPosition[1]; // If point is to close, do not set a new point if ( a * a + b * b < 25.0 ) { this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) ); ok = true; break; } } } this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); ok = true; break; } - + case AcADDPOINT: { + bool selected = false; + m_DataNode->GetBoolProperty("selected", selected); + if ( !selected ) + { + ok = false; + break; + } + // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) - Point2D point2D; + Point2D point2D, projectedPoint; if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D, planarFigureGeometry ) ) { ok = false; break; } + // TODO: check segement of polyline we clicked in + int previousIndex = this->IsPositionOverFigure( + stateEvent, planarFigure, + planarFigureGeometry, + projectionPlane, + renderer->GetDisplayGeometry(), + projectedPoint + ); + // Add point as new control point - planarFigure->AddControlPoint( point2D ); + renderer->GetDisplayGeometry()->DisplayToWorld( projectedPoint, projectedPoint ); + + if ( planarFigure->IsPreviewControlPointVisible() ) + { + point2D = planarFigure->GetPreviewControlPoint(); + } + + planarFigure->AddControlPoint( point2D, previousIndex ); + + if ( planarFigure->IsPreviewControlPointVisible() ) + { + planarFigure->SelectControlPoint( previousIndex ); + planarFigure->ResetPreviewContolPoint(); + } // Re-evaluate features planarFigure->EvaluateFeatures(); //this->LogPrintPlanarFigureQuantities( planarFigure ); // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); ok = true; break; } case AcDESELECTPOINT: { planarFigure->DeselectControlPoint(); // Issue event so that listeners may update themselves planarFigure->Modified(); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); m_DataNode->Modified(); // falls through } - case AcCHECKSELECTED: + case AcCHECKHOVERING: { - bool isHovering = mitk::PlanarFigureInteractor::IsPositionOverFigure( + mitk::Point2D pointProjectedOntoLine; + int previousControlPoint = mitk::PlanarFigureInteractor::IsPositionOverFigure( stateEvent, planarFigure, planarFigureGeometry, projectionPlane, - renderer->GetDisplayGeometry() ); + 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 = false; + 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; + m_DataNode->GetBoolProperty("selected", selected); + m_DataNode->GetBoolProperty("planarfigure.isextendable", isExtendable); + if ( selected && isHovering && isExtendable && pointIndex == -1 ) + { + 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, NULL ) ); + 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: + { + 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: { - // Invoke event to notify listeners that this planar figure should be selected - planarFigure->InvokeEvent( SelectPlanarFigureEvent() ); + //// Invoke event to notify listeners that this planar figure should be selected + //planarFigure->InvokeEvent( SelectPlanarFigureEvent() ); // 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, NULL ) ); + this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); // Return true: only this interactor is eligible to react on this event ok = true; } else { - this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) ); + 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 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 AcMOVEPOINT: - //case AcMOVESELECTED: - // { - // // Update the display - // renderer->GetRenderingManager()->RequestUpdateAll(); + case AcREMOVEPOINT: + { + int selectedControlPoint = planarFigure->GetSelectedControlPoint(); + planarFigure->RemoveControlPoint( selectedControlPoint ); - // ok = true; - // break; - // } + // Re-evaluate features + planarFigure->EvaluateFeatures(); + planarFigure->Modified(); - //case AcFINISHMOVE: - // { - // ok = true; - // break; - // } + planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); + renderer->GetRenderingManager()->RequestUpdateAll(); + this->HandleEvent( new mitk::StateEvent( EIDYES, 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; } bool mitk::PlanarFigureInteractor::TransformPositionEventToPoint2D( const StateEvent *stateEvent, Point2D &point2D, const Geometry2D *planarFigureGeometry ) { // Extract world position, and from this position on geometry, if // available const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { return false; } mitk::Point3D worldPoint3D = positionEvent->GetWorldPosition(); // TODO: proper handling of distance tolerance if ( planarFigureGeometry->Distance( worldPoint3D ) > 0.1 ) { return false; } // Project point onto plane of this PlanarFigure planarFigureGeometry->Map( worldPoint3D, point2D ); return true; } bool mitk::PlanarFigureInteractor::TransformObjectToDisplay( const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) const { mitk::Point3D point3D; // Map circle point from local 2D geometry into 3D world space objectGeometry->Map( point2D, point3D ); // TODO: proper handling of distance tolerance if ( displayGeometry->Distance( point3D ) < 0.1 ) { // Project 3D world point onto display geometry rendererGeometry->Map( point3D, displayPoint ); displayGeometry->WorldToDisplay( displayPoint, displayPoint ); return true; } return false; } bool mitk::PlanarFigureInteractor::IsPointNearLine( const mitk::Point2D& point, - const mitk::Point2D& startPoint, const mitk::Point2D& endPoint ) const + const mitk::Point2D& startPoint, + const mitk::Point2D& endPoint, + mitk::Point2D& projectedPoint + ) const { mitk::Vector2D n1 = endPoint - startPoint; n1.Normalize(); // Determine dot products between line vector and startpoint-point / endpoint-point vectors double l1 = n1 * (point - startPoint); double l2 = -n1 * (point - endPoint); // Determine projection of specified point onto line defined by start / end point mitk::Point2D crossPoint = startPoint + n1 * l1; + projectedPoint = crossPoint; // Point is inside encompassing rectangle IF // - its distance to its projected point is small enough // - it is not further outside of the line than the defined tolerance if ( (crossPoint.SquaredEuclideanDistanceTo( point ) < 20.0 ) - && ( l1 > -5.0 ) && ( l2 > -5.0 ) ) + && ( l1 > 0.0 ) && ( l2 > 0.0 ) + || endPoint.SquaredEuclideanDistanceTo( point ) < 20.0 + || startPoint.SquaredEuclideanDistanceTo( point ) < 20.0 ) { return true; } return false; } -bool mitk::PlanarFigureInteractor::IsPositionOverFigure( +int mitk::PlanarFigureInteractor::IsPositionOverFigure( const StateEvent *stateEvent, PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, - const DisplayGeometry *displayGeometry ) const + const DisplayGeometry *displayGeometry, + Point2D& pointProjectedOntoLine ) const { // Extract display position const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { return -1; } mitk::Point2D displayPosition = positionEvent->GetDisplayPosition(); // Iterate over all polylines of planar figure, and check if // any one is close to the current display position typedef mitk::PlanarFigure::PolyLineType VertexContainerType; mitk::Point2D worldPoint2D, displayControlPoint; mitk::Point3D worldPoint3D; + int previousControlPoint = -1; for ( unsigned short loop = 0; loop < planarFigure->GetPolyLinesSize(); ++loop ) { const VertexContainerType polyLine = planarFigure->GetPolyLine( loop ); + int tempControlPoint = -1; + Point2D polyLinePoint; Point2D firstPolyLinePoint; Point2D previousPolyLinePoint; bool firstPoint = true; for ( VertexContainerType::const_iterator it = polyLine.begin(); it != polyLine.end(); ++it ) { // Get plane coordinates of this point of polyline (if possible) if ( !this->TransformObjectToDisplay( it->Point, polyLinePoint, planarFigureGeometry, rendererGeometry, displayGeometry ) ) { break; // Poly line invalid (not on current 2D plane) --> skip it } + tempControlPoint = it->Index; + if ( firstPoint ) { firstPolyLinePoint = polyLinePoint; firstPoint = false; } - else if ( this->IsPointNearLine( displayPosition, previousPolyLinePoint, polyLinePoint ) ) + else if ( this->IsPointNearLine( displayPosition, previousPolyLinePoint, polyLinePoint, pointProjectedOntoLine ) ) { // Return true if the display position is close enough to this line segment - return true; + previousControlPoint = tempControlPoint; + return previousControlPoint; } previousPolyLinePoint = polyLinePoint; } // For closed figures, also check last line segment if ( planarFigure->IsClosed() - && this->IsPointNearLine( displayPosition, polyLinePoint, firstPolyLinePoint ) ) + && this->IsPointNearLine( displayPosition, polyLinePoint, firstPolyLinePoint, pointProjectedOntoLine ) ) { - return true; + previousControlPoint = 0; + return previousControlPoint; } } - return false; + return previousControlPoint; } int mitk::PlanarFigureInteractor::IsPositionInsideMarker( const StateEvent *stateEvent, const PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, const DisplayGeometry *displayGeometry ) const { // Extract display position const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { return -1; } mitk::Point2D displayPosition = positionEvent->GetDisplayPosition(); // Iterate over all control points of planar figure, and check if // any one is close to the current display position mitk::Point2D worldPoint2D, displayControlPoint; mitk::Point3D worldPoint3D; int numberOfControlPoints = planarFigure->GetNumberOfControlPoints(); for ( int i=0; iTransformObjectToDisplay( planarFigure->GetControlPoint(i), displayControlPoint, planarFigureGeometry, rendererGeometry, displayGeometry ) ) { // TODO: variable size of markers if ( displayPosition.SquaredEuclideanDistanceTo( displayControlPoint ) < 20.0 ) { return i; } - } + } } + + //for ( it = controlPoints.begin(); it != controlPoints.end(); ++it ) + //{ + // Point2D displayControlPoint; + // if ( this->TransformObjectToDisplay( it->Point, displayControlPoint, + // planarFigureGeometry, rendererGeometry, displayGeometry ) ) + // { + // // TODO: variable size of markers + // if ( (abs(displayPosition[0] - displayControlPoint[0]) < 4 ) + // && (abs(displayPosition[1] - displayControlPoint[1]) < 4 ) ) + // { + // return index; + // } + // } + //} + return -1; } void mitk::PlanarFigureInteractor::LogPrintPlanarFigureQuantities( const PlanarFigure *planarFigure ) { MITK_INFO << "PlanarFigure: " << planarFigure->GetNameOfClass(); for ( unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i ) { MITK_INFO << "* " << planarFigure->GetFeatureName( i ) << ": " << planarFigure->GetQuantity( i ) << " " << planarFigure->GetFeatureUnit( i ); } } diff --git a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.h b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.h index 4f7e827616..3f9a5615af 100644 --- a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.h +++ b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.h @@ -1,142 +1,143 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-04-18 20:20:25 +0200 (Sa, 18 Apr 2009) $ Version: $Revision: 13129 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html 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 notices for more information. =========================================================================*/ #ifndef MITKPLANARFIGUREINTERACTOR_H_HEADER_INCLUDED #define MITKPLANARFIGUREINTERACTOR_H_HEADER_INCLUDED #include "PlanarFigureExports.h" #include "mitkCommon.h" #include "mitkVector.h" #include "mitkInteractor.h" #include "mitkBaseRenderer.h" #include namespace mitk { class DataNode; class Geometry2D; class DisplayGeometry; class PlanarFigure; // Define events for PlanarFigure interaction notifications itkEventMacro( PlanarFigureEvent, itk::AnyEvent ); itkEventMacro( StartPlacementPlanarFigureEvent, PlanarFigureEvent ); itkEventMacro( EndPlacementPlanarFigureEvent, PlanarFigureEvent ); itkEventMacro( SelectPlanarFigureEvent, PlanarFigureEvent ); itkEventMacro( StartInteractionPlanarFigureEvent, PlanarFigureEvent ); itkEventMacro( EndInteractionPlanarFigureEvent, PlanarFigureEvent ); itkEventMacro( StartHoverPlanarFigureEvent, PlanarFigureEvent ); itkEventMacro( EndHoverPlanarFigureEvent, PlanarFigureEvent ); /** * \brief Interaction with mitk::PlanarFigure objects via control-points * * \ingroup Interaction */ class PlanarFigure_EXPORT PlanarFigureInteractor : public Interactor { public: mitkClassMacro(PlanarFigureInteractor, Interactor); mitkNewMacro3Param(Self, const char *, DataNode *, int); mitkNewMacro2Param(Self, const char *, DataNode *); /** \brief Sets the amount of precision */ void SetPrecision( ScalarType precision ); /** * \brief calculates how good the data, this statemachine handles, is hit * by the event. * * overwritten, cause we don't look at the boundingbox, we look at each point */ virtual float CanHandleEvent(StateEvent const *stateEvent) const; protected: /** * \brief Constructor with Param n for limited Set of Points * * if no n is set, then the number of points is unlimited* */ PlanarFigureInteractor(const char *type, DataNode *dataNode, int n = -1); /** * \brief Default Destructor **/ virtual ~PlanarFigureInteractor(); virtual bool ExecuteAction( Action *action, mitk::StateEvent const *stateEvent ); bool TransformPositionEventToPoint2D( const StateEvent *stateEvent, Point2D &point2D, const Geometry2D *planarFigureGeometry ); bool TransformObjectToDisplay( const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) const; /** \brief Returns true if the first specified point is in proximity of the line defined * the other two point; false otherwise. * * Proximity is defined as the rectangle around the line with pre-defined distance * from the line. */ bool IsPointNearLine( const mitk::Point2D& point, - const mitk::Point2D& startPoint, const mitk::Point2D& endPoint ) const; + const mitk::Point2D& startPoint, const mitk::Point2D& endPoint, mitk::Point2D& projectedPoint ) const; /** \brief Returns true if the point contained in the passed event (in display coordinates) * is over the planar figure (with a pre-defined tolerance range); false otherwise. */ - bool IsPositionOverFigure( + int IsPositionOverFigure( const StateEvent *StateEvent, PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, - const DisplayGeometry *displayGeometry ) const; + const DisplayGeometry *displayGeometry, + Point2D& pointProjectedOntoLine) const; /** \brief Returns the index of the marker (control point) over which the point contained * in the passed event (in display coordinates) currently is; -1 if the point is not over * a marker. */ int IsPositionInsideMarker( const StateEvent *StateEvent, const PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, const DisplayGeometry *displayGeometry ) const; void LogPrintPlanarFigureQuantities( const PlanarFigure *planarFigure ); private: /** \brief to store the value of precision to pick a point */ ScalarType m_Precision; /** \brief True if the mouse is currently hovering over the image. */ bool m_IsHovering; }; } #endif // MITKPLANARFIGUREINTERACTOR_H_HEADER_INCLUDED