diff --git a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp index 2b5a8569fb..c5bf8fd365 100644 --- a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp +++ b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp @@ -1,979 +1,999 @@ /*=================================================================== 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. ===================================================================*/ +#define PLANARFIGUREINTERACTOR_DBG MITK_DEBUG("PlanarFigureInteractor") << __LINE__ << ": " + #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_MinimumPointDistance( 25.0 ), m_IsHovering( false ), m_LastPointWasValid( false ) { } mitk::PlanarFigureInteractor::~PlanarFigureInteractor() { } void mitk::PlanarFigureInteractor::SetPrecision( mitk::ScalarType precision ) { m_Precision = precision; } void mitk::PlanarFigureInteractor::SetMinimumPointDistance( ScalarType minimumDistance ) { m_MinimumPointDistance = minimumDistance; } // 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: + 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( positionEvent, 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 = 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 { 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() ); } // if this was a right mouse button click, invoke the event if ( theEvent->GetButton() == 2 ) { planarFigure->InvokeEvent( ContextMenuPlanarFigureEvent() ); ok = true; } else { ok = false; } // 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; } 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, 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 > 0.0) && (l2 > 0.0)) || endPoint.SquaredEuclideanDistanceTo(point) < 20.0 || startPoint.SquaredEuclideanDistanceTo(point) < 20.0) { return true; } return false; } int mitk::PlanarFigureInteractor::IsPositionOverFigure( const StateEvent *stateEvent, PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, 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; for ( unsigned short loop = 0; loop < planarFigure->GetPolyLinesSize(); ++loop ) { const VertexContainerType polyLine = planarFigure->GetPolyLine( loop ); 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 } if ( firstPoint ) { firstPolyLinePoint = polyLinePoint; firstPoint = false; } else if ( this->IsPointNearLine( displayPosition, previousPolyLinePoint, polyLinePoint, pointProjectedOntoLine ) ) { // Point is close enough to line segment --> Return index of the segment return it->Index; } previousPolyLinePoint = polyLinePoint; } // For closed figures, also check last line segment if ( planarFigure->IsClosed() && this->IsPointNearLine( displayPosition, polyLinePoint, firstPolyLinePoint, pointProjectedOntoLine ) ) { return 0; // Return index of first control point } } return -1; } 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 ); } } bool mitk::PlanarFigureInteractor::IsMousePositionAcceptableAsNewControlPoint( const PositionEvent* positionEvent, const PlanarFigure* planarFigure ) { assert(positionEvent && planarFigure); BaseRenderer* renderer = positionEvent->GetSender(); assert(renderer); // Get the timestep to support 3D+t int timeStep( renderer->GetTimeStep( planarFigure ) ); // Get current display position of the mouse Point2D currentDisplayPosition = positionEvent->GetDisplayPosition(); // Check if a previous point has been set bool tooClose = false; for( int i=0; i < (int)planarFigure->GetNumberOfControlPoints(); i++ ) { if ( i != planarFigure->GetSelectedControlPoint() ) { // Try to convert previous point to current display coordinates mitk::Geometry2D *planarFigureGeometry = dynamic_cast< mitk::Geometry2D * >( planarFigure->GetGeometry( timeStep ) ); const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); mitk::Point3D previousPoint3D; planarFigureGeometry->Map( planarFigure->GetControlPoint( i ), previousPoint3D ); if ( renderer->GetDisplayGeometry()->Distance( previousPoint3D ) < 0.1 ) // ugly, but assert makes this work { 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 tooClose = (a * a + b * b < m_MinimumPointDistance ); } if ( tooClose ) return false; // abort loop early } } return !tooClose; // default } diff --git a/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml b/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml index 6cc6005c05..5d6eff6083 100644 --- a/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml +++ b/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml @@ -1,3824 +1,3826 @@ - + - + - + - - + + - + - + - - - + + + - - + + - + - + + + diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp index 5355c62328..3b4a4825b8 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp @@ -1,1708 +1,631 @@ /*=================================================================== 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. ===================================================================*/ +#define MEASUREMENT_DEBUG MITK_DEBUG("QmitkMeasurementView") << __LINE__ << ": " + #include "QmitkMeasurementView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_Figure(0), m_EndPlacementObserverTag(0), m_SelectObserverTag(0), m_StartInteractionObserverTag(0), m_EndInteractionObserverTag(0) { } mitk::PlanarFigure* m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; }; struct QmitkMeasurementViewData { QmitkMeasurementViewData() : m_LineCounter(0), m_PathCounter(0), m_AngleCounter(0), m_FourPointAngleCounter(0), m_EllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0) { } // internal vars unsigned int m_LineCounter; unsigned int m_PathCounter; unsigned int m_AngleCounter; unsigned int m_FourPointAngleCounter; unsigned int m_EllipseCounter; unsigned int m_RectangleCounter; unsigned int m_PolygonCounter; QList m_CurrentSelection; std::map m_DataNodeToPlanarFigureData; mitk::WeakPointer m_SelectedImageNode; // WIDGETS QWidget* m_Parent; QLabel* m_SelectedImageLabel; QAction* m_DrawLine; QAction* m_DrawPath; QAction* m_DrawAngle; QAction* m_DrawFourPointAngle; QAction* m_DrawEllipse; QAction* m_DrawRectangle; QAction* m_DrawPolygon; QToolBar* m_DrawActionsToolBar; QActionGroup* m_DrawActionsGroup; QTextBrowser* m_SelectedPlanarFiguresText; QPushButton* m_CopyToClipboard; QGridLayout* m_Layout; }; const std::string QmitkMeasurementView::VIEW_ID = "org.mitk.views.measurement"; QmitkMeasurementView::QmitkMeasurementView() : d( new QmitkMeasurementViewData ) { } QmitkMeasurementView::~QmitkMeasurementView() { this->RemoveAllInteractors(); delete d; } void QmitkMeasurementView::CreateQtPartControl(QWidget* parent) { d->m_Parent = parent; // image label QLabel* selectedImageLabel = new QLabel("Reference Image: "); d->m_SelectedImageLabel = new QLabel; d->m_SelectedImageLabel->setStyleSheet("font-weight: bold;"); d->m_DrawActionsToolBar = new QToolBar; d->m_DrawActionsGroup = new QActionGroup(this); d->m_DrawActionsGroup->setExclusive(true); //# add actions QAction* currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/line.png"), "Draw Line"); d->m_DrawLine = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/path.png"), "Draw Path"); d->m_DrawPath = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/angle.png"), "Draw Angle"); d->m_DrawAngle = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/four-point-angle.png"), "Draw Four Point Angle"); d->m_DrawFourPointAngle = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/circle.png"), "Draw Circle"); d->m_DrawEllipse = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/rectangle.png"), "Draw Rectangle"); d->m_DrawRectangle = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/polygon.png"), "Draw Polygon"); d->m_DrawPolygon = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); // planar figure details text d->m_SelectedPlanarFiguresText = new QTextBrowser; // copy to clipboard button d->m_CopyToClipboard = new QPushButton("Copy to Clipboard"); d->m_Layout = new QGridLayout; d->m_Layout->addWidget(selectedImageLabel, 0, 0, 1, 1); d->m_Layout->addWidget(d->m_SelectedImageLabel, 0, 1, 1, 1); d->m_Layout->addWidget(d->m_DrawActionsToolBar, 1, 0, 1, 2); d->m_Layout->addWidget(d->m_SelectedPlanarFiguresText, 2, 0, 1, 2); d->m_Layout->addWidget(d->m_CopyToClipboard, 3, 0, 1, 2); d->m_Parent->setLayout(d->m_Layout); // create connections this->CreateConnections(); // readd interactors and observers this->AddAllInteractors(); } void QmitkMeasurementView::CreateConnections() { QObject::connect( d->m_DrawLine, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawLineTriggered(bool) ) ); QObject::connect( d->m_DrawPath, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawPathTriggered(bool) ) ); QObject::connect( d->m_DrawAngle, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawAngleTriggered(bool) ) ); QObject::connect( d->m_DrawFourPointAngle, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawFourPointAngleTriggered(bool) ) ); QObject::connect( d->m_DrawEllipse, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawEllipseTriggered(bool) ) ); QObject::connect( d->m_DrawRectangle, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawRectangleTriggered(bool) ) ); QObject::connect( d->m_DrawPolygon, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawPolygonTriggered(bool) ) ); QObject::connect( d->m_CopyToClipboard, SIGNAL( clicked(bool) ) , this, SLOT( CopyToClipboard(bool) ) ); } void QmitkMeasurementView::NodeAdded( const mitk::DataNode* node ) { // add observer for selection in renderwindow mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); if( figure ) { - MITK_DEBUG << "figure added. will add interactor if needed."; + MEASUREMENT_DEBUG << "figure added. will add interactor if needed."; mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); mitk::DataNode* nonConstNode = const_cast( node ); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); } else { // just to be sure that the interactor is not added twice mitk::GlobalInteraction::GetInstance()->RemoveInteractor(figureInteractor); } - MITK_DEBUG << "adding interactor to globalinteraction"; + MEASUREMENT_DEBUG << "adding interactor to globalinteraction"; mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); - MITK_DEBUG << "will now add observers for planarfigure"; + MEASUREMENT_DEBUG << "will now add observers for planarfigure"; QmitkPlanarFigureData data; data.m_Figure = figure; // add observer for event when figure has been placed typedef itk::SimpleMemberCommand< QmitkMeasurementView > SimpleCommandType; SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); initializationCommand->SetCallbackFunction( this, &QmitkMeasurementView::PlanarFigureInitialized ); data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkMeasurementView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkMeasurementView::PlanarFigureSelected ); data.m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction( this, &QmitkMeasurementView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkMeasurementView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); // adding to the map of tracked planarfigures d->m_DataNodeToPlanarFigureData[nonConstNode] = data; } this->CheckForTopMostVisibleImage(); } void QmitkMeasurementView::NodeChanged(const mitk::DataNode* node) { // DETERMINE IF WE HAVE TO RENEW OUR DETAILS TEXT (ANY NODE CHANGED IN OUR SELECTION?) bool renewText = false; for( int i=0; i < d->m_CurrentSelection.size(); ++i ) { if( node == d->m_CurrentSelection.at(i) ) { renewText = true; break; } } if(renewText) { - MITK_DEBUG << "Selected nodes changed. Refreshing text."; + MEASUREMENT_DEBUG << "Selected nodes changed. Refreshing text."; this->UpdateMeasurementText(); } this->CheckForTopMostVisibleImage(); } void QmitkMeasurementView::CheckForTopMostVisibleImage() { d->m_SelectedImageNode = this->DetectTopMostVisibleImage().GetPointer(); if( d->m_SelectedImageNode.IsNotNull() ) { - MITK_DEBUG << "Reference image found"; + MEASUREMENT_DEBUG << "Reference image found"; d->m_SelectedImageLabel->setText( QString::fromStdString( d->m_SelectedImageNode->GetName() ) ); d->m_DrawActionsToolBar->setEnabled(true); - MITK_DEBUG << "Updating Measurement text"; + MEASUREMENT_DEBUG << "Updating Measurement text"; } else { - MITK_DEBUG << "No reference image available. Will disable actions for creating new planarfigures"; + MEASUREMENT_DEBUG << "No reference image available. Will disable actions for creating new planarfigures"; d->m_SelectedImageLabel->setText( "No visible image available." ); d->m_DrawActionsToolBar->setEnabled(false); } } void QmitkMeasurementView::NodeRemoved(const mitk::DataNode* node) { - MITK_DEBUG << "node removed from data storage"; + MEASUREMENT_DEBUG << "node removed from data storage"; mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = d->m_DataNodeToPlanarFigureData.find(nonConstNode); if( it != d->m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; - MITK_DEBUG << "removing figure interactor to globalinteraction"; + MEASUREMENT_DEBUG << "removing figure interactor to globalinteraction"; mitk::Interactor::Pointer oldInteractor = node->GetInteractor(); if(oldInteractor.IsNotNull()) mitk::GlobalInteraction::GetInstance()->RemoveInteractor(oldInteractor); // remove observers data.m_Figure->RemoveObserver( data.m_EndPlacementObserverTag ); data.m_Figure->RemoveObserver( data.m_SelectObserverTag ); data.m_Figure->RemoveObserver( data.m_StartInteractionObserverTag ); data.m_Figure->RemoveObserver( data.m_EndInteractionObserverTag ); - MITK_DEBUG << "removing from the list of tracked planar figures"; + MEASUREMENT_DEBUG << "removing from the list of tracked planar figures"; d->m_DataNodeToPlanarFigureData.erase( it ); } this->CheckForTopMostVisibleImage(); } void QmitkMeasurementView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { - MITK_DEBUG << "planar figure " << object << " selected"; + MEASUREMENT_DEBUG << "planar figure " << object << " selected"; std::map::iterator it = d->m_DataNodeToPlanarFigureData.begin(); d->m_CurrentSelection.clear(); while( it != d->m_DataNodeToPlanarFigureData.end()) { mitk::DataNode* node = it->first; QmitkPlanarFigureData& data = it->second; if( data.m_Figure == object ) { + MITK_DEBUG << "selected node found. enabling selection"; node->SetSelected(true); d->m_CurrentSelection.push_back( node ); } else { node->SetSelected(false); } ++it; } this->UpdateMeasurementText(); + this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::PlanarFigureInitialized() { - MITK_DEBUG << "planar figure initialized"; + MEASUREMENT_DEBUG << "planar figure initialized"; } void QmitkMeasurementView::SetFocus() { d->m_SelectedImageLabel->setFocus(); } void QmitkMeasurementView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) { - MITK_DEBUG << "Determine the top most visible image"; - MITK_DEBUG << "The PlanarFigure interactor will take the currently visible PlaneGeometry from the slice navigation controller"; + MEASUREMENT_DEBUG << "Determine the top most visible image"; + MEASUREMENT_DEBUG << "The PlanarFigure interactor will take the currently visible PlaneGeometry from the slice navigation controller"; this->CheckForTopMostVisibleImage(); - MITK_DEBUG << "refreshing selection and detailed text"; + MEASUREMENT_DEBUG << "refreshing selection and detailed text"; d->m_CurrentSelection = nodes; this->UpdateMeasurementText(); + this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::ActionDrawLineTriggered(bool checked) { mitk::PlanarLine::Pointer figure = mitk::PlanarLine::New(); QString qString = QString("Line%1").arg(++d->m_LineCounter); this->AddFigureToDataStorage(figure, qString); - MITK_DEBUG << "PlanarLine initialized..."; + MEASUREMENT_DEBUG << "PlanarLine initialized..."; } void QmitkMeasurementView::ActionDrawPathTriggered(bool checked) { mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOff(); QString qString = QString("Path%1").arg(++d->m_PathCounter); mitk::DataNode::Pointer node = this->AddFigureToDataStorage(figure, qString); mitk::BoolProperty::Pointer closedProperty = mitk::BoolProperty::New( false ); node->SetProperty("ClosedPlanarPolygon", closedProperty); - MITK_DEBUG << "PlanarPath initialized..."; + MEASUREMENT_DEBUG << "PlanarPath initialized..."; } void QmitkMeasurementView::ActionDrawAngleTriggered(bool checked) { mitk::PlanarAngle::Pointer figure = mitk::PlanarAngle::New(); QString qString = QString("Angle%1").arg(++d->m_AngleCounter); this->AddFigureToDataStorage(figure, qString); - MITK_DEBUG << "PlanarAngle initialized..."; + MEASUREMENT_DEBUG << "PlanarAngle initialized..."; } void QmitkMeasurementView::ActionDrawFourPointAngleTriggered(bool checked) { mitk::PlanarFourPointAngle::Pointer figure = mitk::PlanarFourPointAngle::New(); QString qString = QString("Four Point Angle%1").arg(++d->m_FourPointAngleCounter); this->AddFigureToDataStorage(figure, qString); - MITK_DEBUG << "PlanarFourPointAngle initialized..."; + MEASUREMENT_DEBUG << "PlanarFourPointAngle initialized..."; } void QmitkMeasurementView::ActionDrawEllipseTriggered(bool checked) { mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); QString qString = QString("Circle%1").arg(++d->m_EllipseCounter); this->AddFigureToDataStorage(figure, qString); - MITK_DEBUG << "PlanarCircle initialized..."; + MEASUREMENT_DEBUG << "PlanarCircle initialized..."; } void QmitkMeasurementView::ActionDrawRectangleTriggered(bool checked) { mitk::PlanarRectangle::Pointer figure = mitk::PlanarRectangle::New(); QString qString = QString("Rectangle%1").arg(++d->m_RectangleCounter); this->AddFigureToDataStorage(figure, qString); - MITK_DEBUG << "PlanarRectangle initialized..."; + MEASUREMENT_DEBUG << "PlanarRectangle initialized..."; } void QmitkMeasurementView::ActionDrawPolygonTriggered(bool checked) { mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); QString qString = QString("Polygon%1").arg(++d->m_PolygonCounter); this->AddFigureToDataStorage(figure, qString); - MITK_DEBUG << "PlanarPolygon initialized..."; + MEASUREMENT_DEBUG << "PlanarPolygon initialized..."; } void QmitkMeasurementView::CopyToClipboard( bool checked ) { - MITK_DEBUG << "Copying current Text to clipboard..."; + MEASUREMENT_DEBUG << "Copying current Text to clipboard..."; QString clipboardText = d->m_SelectedPlanarFiguresText->toPlainText(); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } mitk::DataNode::Pointer QmitkMeasurementView::AddFigureToDataStorage( mitk::PlanarFigure* figure, const QString& name) { // add as - MITK_DEBUG << "Adding new figure to datastorage..."; + MEASUREMENT_DEBUG << "Adding new figure to datastorage..."; if( d->m_SelectedImageNode.IsNull() ) { MITK_ERROR << "No reference image available"; return 0; } mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); // set as selected - // newNode->SetSelected( true ); + newNode->SetSelected( true ); this->GetDataStorage()->Add(newNode, d->m_SelectedImageNode); + + // set all others in selection as deselected + for( size_t i=0; im_CurrentSelection.size(); ++i) + d->m_CurrentSelection.at(i)->SetSelected(false); + d->m_CurrentSelection.clear(); + d->m_CurrentSelection.push_back( newNode ); + this->UpdateMeasurementText(); + this->DisableCrosshairNavigation(); return newNode; } void QmitkMeasurementView::UpdateMeasurementText() { d->m_SelectedPlanarFiguresText->clear(); QString infoText; QString plainInfoText; unsigned int j = 1; mitk::PlanarFigure* _PlanarFigure = 0; mitk::PlanarAngle* planarAngle = 0; mitk::PlanarFourPointAngle* planarFourPointAngle = 0; mitk::DataNode::Pointer node = 0; for (unsigned int i=0; im_CurrentSelection.size(); ++i, ++j) { plainInfoText.clear(); node = d->m_CurrentSelection.at(i); _PlanarFigure = dynamic_cast (node->GetData()); if( !_PlanarFigure ) continue; if(j>1) infoText.append("
"); infoText.append(QString("%1
").arg(QString::fromStdString( node->GetName()))); plainInfoText.append(QString("%1").arg(QString::fromStdString( node->GetName()))); planarAngle = dynamic_cast (_PlanarFigure); if(!planarAngle) { planarFourPointAngle = dynamic_cast (_PlanarFigure); } double featureQuantity = 0.0; for (unsigned int k = 0; k < _PlanarFigure->GetNumberOfFeatures(); ++k) { if ( !_PlanarFigure->IsFeatureActive( k ) ) continue; featureQuantity = _PlanarFigure->GetQuantity(k); if ((planarAngle && k == planarAngle->FEATURE_ID_ANGLE) || (planarFourPointAngle && k == planarFourPointAngle->FEATURE_ID_ANGLE)) featureQuantity = featureQuantity * 180 / vnl_math::pi; infoText.append( QString("%1: %2 %3") .arg(QString( _PlanarFigure->GetFeatureName(k))) .arg(featureQuantity, 0, 'f', 2) .arg(QString(_PlanarFigure->GetFeatureUnit(k)))); plainInfoText.append( QString("\n%1: %2 %3") .arg(QString(_PlanarFigure->GetFeatureName(k))) .arg( featureQuantity, 0, 'f', 2) .arg(QString( _PlanarFigure->GetFeatureUnit(k)))); if(k+1 != _PlanarFigure->GetNumberOfFeatures()) infoText.append("
"); } if (j != d->m_CurrentSelection.size()) infoText.append("
"); } d->m_SelectedPlanarFiguresText->setHtml(infoText); } void QmitkMeasurementView::AddAllInteractors() { - MITK_DEBUG << "Adding interactors to all planar figures"; + MEASUREMENT_DEBUG << "Adding interactors to all planar figures"; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); const mitk::DataNode* node = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); this->NodeAdded( node ); } } void QmitkMeasurementView::RemoveAllInteractors() { - MITK_DEBUG << "Removing interactors and observers from all planar figures"; + MEASUREMENT_DEBUG << "Removing interactors and observers from all planar figures"; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); const mitk::DataNode* node = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); this->NodeRemoved( node ); } } mitk::DataNode::Pointer QmitkMeasurementView::DetectTopMostVisibleImage() { // get all images from the data storage mitk::DataStorage::SetOfObjects::ConstPointer Images = this->GetDataStorage()->GetSubset( mitk::NodePredicateDataType::New("Image") ); mitk::DataNode::Pointer currentNode; int maxLayer = itk::NumericTraits::min(); // iterate over selection for (mitk::DataStorage::SetOfObjects::ConstIterator sofIt = Images->Begin(); sofIt != Images->End(); ++sofIt) { mitk::DataNode::Pointer node = sofIt->Value(); if ( node.IsNull() ) continue; if (node->IsVisible(NULL) == false) continue; int layer = 0; node->GetIntProperty("layer", layer); if ( layer < maxLayer ) continue; currentNode = node; } return currentNode; } void QmitkMeasurementView::EnableCrosshairNavigation() { - // enable the crosshair navigation - if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart())) - { - linkedRenderWindow->EnableLinkedNavigation(true); - } -} - -void QmitkMeasurementView::DisableCrosshairNavigation() -{ - // disable the crosshair navigation during the drawing - if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart())) - { - linkedRenderWindow->EnableLinkedNavigation(false); - } -} - -/* -#include -#include -#include - -#include "mitkGlobalInteraction.h" -#include "mitkPointSet.h" -#include "mitkProperties.h" -#include "mitkStringProperty.h" -#include "mitkIDataStorageService.h" -#include "mitkDataNodeObject.h" -#include -#include -#include -#include -#include -#include -#include - -#include "mitkPlanarCircle.h" -#include "mitkPlanarPolygon.h" -#include "mitkPlanarAngle.h" -#include "mitkPlanarRectangle.h" -#include "mitkPlanarLine.h" -#include "mitkPlanarCross.h" -#include "mitkPlanarFourPointAngle.h" -#include "mitkPlanarFigureInteractor.h" -#include "mitkPlaneGeometry.h" -#include "QmitkPlanarFiguresTableModel.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "mitkNodePredicateDataType.h" -#include "mitkPlanarFigure.h" - -#include -#include -#include -#include - -const std::string QmitkMeasurementView::VIEW_ID = -"org.mitk.views.measurement"; - -QmitkMeasurementView::QmitkMeasurementView() : -m_Parent(0), m_Layout(0), m_DrawActionsToolBar(0), -m_DrawActionsGroup(0), m_MeasurementInfoRenderer(0), -m_MeasurementInfoAnnotation(0), m_SelectedPlanarFigures(0), -m_SelectedImageNode(), -m_LineCounter(0), m_PathCounter(0), -m_AngleCounter(0), m_FourPointAngleCounter(0), m_EllipseCounter(0), - m_RectangleCounter(0), m_PolygonCounter(0), m_Visible(false), - m_CurrentFigureNodeInitialized(false), m_Activated(false), - m_LastRenderWindow(0) -{ - -} - -QmitkMeasurementView::~QmitkMeasurementView() -{ - this->GetDataStorage()->AddNodeEvent -= mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeAddedInDataStorage ); - - m_SelectedPlanarFigures->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeChanged ) ); - - m_SelectedPlanarFigures->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeRemoved ) ); - - m_SelectedPlanarFigures->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkMeasurementView::PropertyChanged ) ); - - m_SelectedImageNode->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeChanged ) ); - - m_SelectedImageNode->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeRemoved ) ); - - m_SelectedImageNode->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkMeasurementView::PropertyChanged ) ); - - this->RemoveEndPlacementObserverTag(); - - if(this->m_LastRenderWindow != NULL) - { - this->SetMeasurementInfoToRenderWindow("",m_LastRenderWindow); - mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->RemoveRenderer( - m_MeasurementInfoRenderer); - } - this->m_MeasurementInfoRenderer->Delete(); -} - -void QmitkMeasurementView::CreateQtPartControl(QWidget* parent) -{ - m_Parent = parent; - m_MeasurementInfoRenderer = vtkRenderer::New(); - m_MeasurementInfoAnnotation = vtkCornerAnnotation::New(); - vtkTextProperty *textProp = vtkTextProperty::New(); - - m_MeasurementInfoAnnotation->SetMaximumFontSize(12); - textProp->SetColor(1.0, 1.0, 1.0); - m_MeasurementInfoAnnotation->SetTextProperty(textProp); - - m_MeasurementInfoRenderer->AddActor(m_MeasurementInfoAnnotation); - m_DrawActionsToolBar = new QToolBar; - m_DrawActionsGroup = new QActionGroup(this); - m_DrawActionsGroup->setExclusive(true); - - //# add actions - QAction* currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/measurement/line.png"), "Draw Line"); - m_DrawLine = currentAction; - m_DrawLine->setCheckable(true); - m_DrawActionsToolBar->addAction(currentAction); - m_DrawActionsGroup->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ActionDrawLineTriggered(bool) ) ); - - currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/measurement/path.png"), "Draw Path"); - m_DrawPath = currentAction; - m_DrawPath->setCheckable(true); - m_DrawActionsToolBar->addAction(currentAction); - m_DrawActionsGroup->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ActionDrawPathTriggered(bool) ) ); - - currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/measurement/angle.png"), "Draw Angle"); - m_DrawAngle = currentAction; - m_DrawAngle->setCheckable(true); - m_DrawActionsToolBar->addAction(currentAction); - m_DrawActionsGroup->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ActionDrawAngleTriggered(bool) ) ); - - currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/measurement/four-point-angle.png"), "Draw Four Point Angle"); - m_DrawFourPointAngle = currentAction; - m_DrawFourPointAngle->setCheckable(true); - m_DrawActionsToolBar->addAction(currentAction); - m_DrawActionsGroup->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ActionDrawFourPointAngleTriggered(bool) ) ); - - currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/measurement/circle.png"), "Draw Circle"); - m_DrawEllipse = currentAction; - m_DrawEllipse->setCheckable(true); - m_DrawActionsToolBar->addAction(currentAction); - m_DrawActionsGroup->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ActionDrawEllipseTriggered(bool) ) ); - - currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/measurement/rectangle.png"), "Draw Rectangle"); - m_DrawRectangle = currentAction; - m_DrawRectangle->setCheckable(true); - m_DrawActionsToolBar->addAction(currentAction); - m_DrawActionsGroup->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ActionDrawRectangleTriggered(bool) ) ); - - currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/measurement/polygon.png"), "Draw Polygon"); - m_DrawPolygon = currentAction; - m_DrawPolygon->setCheckable(true); - m_DrawActionsToolBar->addAction(currentAction); - m_DrawActionsGroup->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ActionDrawPolygonTriggered(bool) ) ); - - currentAction = m_DrawActionsToolBar->addAction(QIcon( - ":/Qmitk/Images_48.png"), "Reproduce potential bug"); - m_DrawActionsToolBar->addAction(currentAction); - QObject::connect( currentAction, SIGNAL( triggered(bool) ) - , this, SLOT( ReproducePotentialBug(bool) ) ); - - - QLabel* selectedImageLabel = new QLabel("Selected Image: "); - m_SelectedImage = new QLabel; - m_SelectedImage->setStyleSheet("font-weight: bold;"); - m_SelectedPlanarFiguresText = new QTextBrowser; - - m_CopyToClipboard = new QPushButton("Copy to Clipboard"); - QObject::connect( m_CopyToClipboard, SIGNAL( clicked(bool) ) - , this, SLOT( CopyToClipboard(bool) ) ); - - m_Layout = new QGridLayout; - m_Layout->addWidget(selectedImageLabel, 0, 0, 1, 1); - m_Layout->addWidget(m_SelectedImage, 0, 1, 1, 1); - m_Layout->addWidget(m_DrawActionsToolBar, 1, 0, 1, 2); - m_Layout->addWidget(m_SelectedPlanarFiguresText, 2, 0, 1, 2); - m_Layout->addWidget(m_CopyToClipboard, 3, 0, 1, 2); - m_Layout->setRowStretch(0, 1); - m_Layout->setRowStretch(1, 1); - m_Layout->setRowStretch(2, 10); - m_Layout->setRowStretch(3, 1); - m_Layout->setContentsMargins(2, 2, 2, 2); - - parent->setLayout(m_Layout); - - - m_SelectedPlanarFigures = mitk::DataStorageSelection::New(this->GetDataStorage(), false); - - m_SelectedPlanarFigures->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeChanged ) ); - - m_SelectedPlanarFigures->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeRemoved ) ); - - m_SelectedPlanarFigures->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkMeasurementView::PropertyChanged ) ); - - m_SelectedImageNode = mitk::DataStorageSelection::New(this->GetDataStorage(), false); - - m_SelectedImageNode->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkMeasurementView::PropertyChanged ) ); - - m_SelectedImageNode->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeChanged ) ); - - m_SelectedImageNode->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeRemoved ) ); - - this->GetDataStorage()->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeAddedInDataStorage ) ); - -} - -void QmitkMeasurementView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, - const QList &nodes) -{ - if ( nodes.isEmpty() ) return; - - m_SelectedImageNode->RemoveAllNodes(); - - mitk::BaseData* _BaseData; - mitk::PlanarFigure* _PlanarFigure; - mitk::Image* selectedImage; - m_SelectedPlanarFigures->RemoveAllNodes(); - - foreach (mitk::DataNode::Pointer _DataNode, nodes) - { - _PlanarFigure = 0; - - if (!_DataNode) - continue; - - _BaseData = _DataNode->GetData(); - - if (!_BaseData) - continue; - - // planar figure selected - if ((_PlanarFigure = dynamic_cast (_BaseData))) - { - // add to the selected planar figures - m_SelectedPlanarFigures->AddNode(_DataNode); - // take parent image as the selected image - mitk::DataStorage::SetOfObjects::ConstPointer parents = - this->GetDataStorage()->GetSources(_DataNode); - if (parents->size() > 0) - { - mitk::DataNode::Pointer parent = parents->front(); - if ((selectedImage = dynamic_cast (parent->GetData()))) - { - *m_SelectedImageNode = parent; - } - } - - } - else if ((selectedImage = dynamic_cast (_BaseData))) - { - *m_SelectedImageNode = _DataNode; - //mitk::RenderingManager::GetInstance()->InitializeViews( - //selectedImage->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); - } - } // end for - - this->PlanarFigureSelectionChanged(); -} - -void QmitkMeasurementView::PlanarFigureSelectionChanged() -{ - if ( !this->m_Activated ) return; - - if (m_SelectedImageNode->GetNode().IsNotNull()) - { - mitk::Image* selectedImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); - if(selectedImage && selectedImage->GetDimension() > 3) - { - m_SelectedImageNode->RemoveAllNodes(); - m_SelectedImage->setText( "4D images are not supported." ); - m_DrawActionsToolBar->setEnabled(false); - } - else - { - m_SelectedImage->setText(QString::fromStdString( - m_SelectedImageNode->GetNode()->GetName())); - m_DrawActionsToolBar->setEnabled(true); - } - } - else - { - m_SelectedImage->setText( - "None. Please select an image."); - - m_DrawActionsToolBar->setEnabled(false); - } - - if (m_SelectedPlanarFigures->GetSize() == 0 && this->GetRenderWindowPart() != 0) - { - foreach (QmitkRenderWindow* renderWindow, this->GetRenderWindowPart()->GetRenderWindows().values()) - { - this->SetMeasurementInfoToRenderWindow("", renderWindow); - } - } - - unsigned int j = 1; - mitk::PlanarFigure* _PlanarFigure = 0; - mitk::PlanarAngle* planarAngle = 0; - mitk::PlanarFourPointAngle* planarFourPointAngle = 0; - mitk::DataNode::Pointer node = 0; - m_SelectedPlanarFiguresText->clear(); - QString infoText; - QString plainInfoText; - std::vector nodes = m_SelectedPlanarFigures->GetNodes(); - - for (std::vector::iterator it = nodes.begin(); it - != nodes.end(); ++it, ++j) - { - plainInfoText.clear(); - node = *it; - if(j>1) - infoText.append("
"); - - infoText.append(QString("%1
").arg(QString::fromStdString( - node->GetName()))); - plainInfoText.append(QString("%1").arg(QString::fromStdString( - node->GetName()))); - - _PlanarFigure = dynamic_cast (node->GetData()); - - planarAngle = dynamic_cast (_PlanarFigure); - if(!planarAngle) - { - planarFourPointAngle = dynamic_cast (_PlanarFigure); - } - - if(!_PlanarFigure) - continue; - - double featureQuantity = 0.0; - for (unsigned int i = 0; i < _PlanarFigure->GetNumberOfFeatures(); ++i) - { - if ( !_PlanarFigure->IsFeatureActive( i ) ) continue; - - featureQuantity = _PlanarFigure->GetQuantity(i); - if ((planarAngle && i == planarAngle->FEATURE_ID_ANGLE) - || (planarFourPointAngle && i == planarFourPointAngle->FEATURE_ID_ANGLE)) - featureQuantity = featureQuantity * 180 / vnl_math::pi; - - infoText.append( - QString("%1: %2 %3") .arg(QString( - _PlanarFigure->GetFeatureName(i))) .arg(featureQuantity, 0, 'f', - 2) .arg(QString(_PlanarFigure->GetFeatureUnit(i)))); - - plainInfoText.append( - QString("\n%1: %2 %3") .arg(QString(_PlanarFigure->GetFeatureName(i))) .arg( - featureQuantity, 0, 'f', 2) .arg(QString( - _PlanarFigure->GetFeatureUnit(i)))); - - if(i+1 != _PlanarFigure->GetNumberOfFeatures()) - infoText.append("
"); - } - - if (j != nodes.size()) - infoText.append("
"); - } - - m_SelectedPlanarFiguresText->setHtml(infoText); - - // for the last selected planar figure ... - if (_PlanarFigure) - { - const mitk::PlaneGeometry - * _PlaneGeometry = - dynamic_cast (_PlanarFigure->GetGeometry2D()); - - QmitkRenderWindow* selectedRenderWindow = 0; - bool PlanarFigureInitializedWindow = false; - mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); - if (renderPart) - { - foreach(QmitkRenderWindow* renderWindow, renderPart->GetRenderWindows().values()) - { - if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, - renderWindow->GetRenderer())) - { - selectedRenderWindow = renderWindow; - break; - } - } - } - - // make node visible - if (selectedRenderWindow) - { - mitk::Point3D centerP = _PlaneGeometry->GetOrigin(); - //selectedRenderWindow->GetSliceNavigationController()->ReorientSlices( - //centerP, _PlaneGeometry->GetNormal()); - selectedRenderWindow->GetSliceNavigationController()->SelectSliceByPoint( - centerP); - - // now paint infos also on renderwindow - this->SetMeasurementInfoToRenderWindow(plainInfoText, selectedRenderWindow); - } - } - // no last planarfigure - else - this->SetMeasurementInfoToRenderWindow("", 0); - - this->RequestRenderWindowUpdate(); -} - -void QmitkMeasurementView::NodeAddedInDataStorage(const mitk::DataNode* node) -{ - if(!m_Visible) - return; - mitk::DataNode* nonConstNode = const_cast(node); - mitk::PlanarFigure* figure = dynamic_cast(nonConstNode->GetData()); - if(figure) - { - mitk::PlanarFigureInteractor::Pointer figureInteractor - = dynamic_cast(node->GetInteractor()); - - if(figureInteractor.IsNull()) - figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); - - // remove old interactor if present - if( m_CurrentFigureNode.IsNotNull() && m_CurrentFigureNodeInitialized == false ) - { - mitk::Interactor::Pointer oldInteractor = m_CurrentFigureNode->GetInteractor(); - if(oldInteractor.IsNotNull()) - mitk::GlobalInteraction::GetInstance()->RemoveInteractor(oldInteractor); - - this->RemoveEndPlacementObserverTag(); - this->GetDataStorage()->Remove(m_CurrentFigureNode); - } - - mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); - } -} - - -void QmitkMeasurementView::PlanarFigureInitialized() -{ - if(m_CurrentFigureNode.IsNull()) - return; + MEASUREMENT_DEBUG << "EnableCrosshairNavigation"; - m_CurrentFigureNodeInitialized = true; - - this->PlanarFigureSelectionChanged(); - - m_DrawLine->setChecked(false); - m_DrawPath->setChecked(false); - m_DrawAngle->setChecked(false); - m_DrawFourPointAngle->setChecked(false); - m_DrawEllipse->setChecked(false); - m_DrawRectangle->setChecked(false); - m_DrawPolygon->setChecked(false); // enable the crosshair navigation - this->EnableCrosshairNavigation(); -} - - -void QmitkMeasurementView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) -{ - // Mark to-be-edited PlanarFigure as selected - mitk::PlanarFigure* figure = dynamic_cast< mitk::PlanarFigure* >( object ); - if ( figure != NULL ) - { - // Get node corresponding to PlanarFigure - mitk::DataNode::Pointer figureNode = this->GetDataStorage()->GetNode( - mitk::NodePredicateData::New( figure ) ); - - // Select this node (and deselect all others) - QList< mitk::DataNode::Pointer > selectedNodes = this->GetDataManagerSelection(); - for ( int i = 0; i < selectedNodes.size(); i++ ) - { - selectedNodes[i]->SetSelected( false ); - } - std::vector< mitk::DataNode* > selectedNodes2 = m_SelectedPlanarFigures->GetNodes(); - for ( unsigned int i = 0; i < selectedNodes2.size(); i++ ) - { - selectedNodes2[i]->SetSelected( false ); - } - figureNode->SetSelected( true ); - - this->RemoveEndPlacementObserverTag(); - m_CurrentFigureNode = figureNode; - - *m_SelectedPlanarFigures = figureNode; - - // Re-initialize after selecting new PlanarFigure - this->PlanarFigureSelectionChanged(); - } -} - -void QmitkMeasurementView::RemoveEndPlacementObserverTag() -{ - - if(m_CurrentFigureNode.IsNotNull()) - { - mitk::PlanarFigure* figure = dynamic_cast(m_CurrentFigureNode->GetData()); - if( figure != 0 ) - figure->RemoveObserver( m_EndPlacementObserverTag ); - } -} - -mitk::DataNode::Pointer QmitkMeasurementView::DetectTopMostVisibleImage() -{ - // get all images from the data storage - mitk::DataStorage::SetOfObjects::ConstPointer Images = this->GetDataStorage()->GetSubset( mitk::NodePredicateDataType::New("Image") ); - - mitk::DataNode::Pointer currentNode( m_SelectedImageNode->GetNode() ); - int maxLayer = itk::NumericTraits::min(); - - // iterate over selection - for (mitk::DataStorage::SetOfObjects::ConstIterator sofIt = Images->Begin(); sofIt != Images->End(); ++sofIt) - { - mitk::DataNode::Pointer node = sofIt->Value(); - if ( node.IsNull() ) - continue; - if (node->IsVisible(NULL) == false) - continue; - int layer = 0; - node->GetIntProperty("layer", layer); - if ( layer < maxLayer ) - continue; - - currentNode = node; - } - - return currentNode; -} - -void QmitkMeasurementView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, - const char *propertyKey, mitk::BaseProperty *property ) -{ - if ( m_CurrentFigureNode.IsNotNull() ) - { - m_CurrentFigureNode->GetData()->RemoveObserver( m_EndPlacementObserverTag ); - } - - mitk::DataNode::Pointer newNode = mitk::DataNode::New(); - newNode->SetName(name.toStdString()); - newNode->SetData(figure); - - // Add custom property, if available - if ( (propertyKey != NULL) && (property != NULL) ) - { - newNode->AddProperty( propertyKey, property ); - } - - // add observer for event when figure has been placed - typedef itk::SimpleMemberCommand< QmitkMeasurementView > SimpleCommandType; - SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); - initializationCommand->SetCallbackFunction( this, &QmitkMeasurementView::PlanarFigureInitialized ); - m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); - - // add observer for event when figure is picked (selected) - typedef itk::MemberCommand< QmitkMeasurementView > MemberCommandType; - MemberCommandType::Pointer selectCommand = MemberCommandType::New(); - selectCommand->SetCallbackFunction( this, &QmitkMeasurementView::PlanarFigureSelected ); - m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); - - // add observer for event when interaction with figure starts - SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); - startInteractionCommand->SetCallbackFunction( this, &QmitkMeasurementView::DisableCrosshairNavigation); - m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); - - // add observer for event when interaction with figure starts - SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); - endInteractionCommand->SetCallbackFunction( this, &QmitkMeasurementView::EnableCrosshairNavigation); - m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); - - // figure drawn on the topmost layer / image - this->GetDataStorage()->Add(newNode, this->DetectTopMostVisibleImage() ); - QList selectedNodes = GetDataManagerSelection(); - for(int i = 0; i < selectedNodes.size(); i++) - { - selectedNodes[i]->SetSelected(false); - } - std::vector selectedNodes2 = m_SelectedPlanarFigures->GetNodes(); - for(unsigned int i = 0; i < selectedNodes2.size(); i++) - { - selectedNodes2[i]->SetSelected(false); - } - newNode->SetSelected(true); - - - m_CurrentFigureNodeInitialized = false; - m_CurrentFigureNode = newNode; - - *m_SelectedPlanarFigures = newNode; - - this->RequestRenderWindowUpdate(); -} - -bool QmitkMeasurementView::AssertDrawingIsPossible(bool checked) -{ - if (m_SelectedImageNode->GetNode().IsNull()) - { - checked = false; - this->HandleException("Please select an image!", this->m_Parent, true); - m_DrawLine->setChecked(false); - return false; - } - - mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart()); - if (linkedRenderWindow) - { - linkedRenderWindow->EnableSlicingPlanes(false); - } - // disable the crosshair navigation during the drawing - this->DisableCrosshairNavigation(); - - return checked; -} - -void QmitkMeasurementView::ActionDrawLineTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - mitk::PlanarLine::Pointer figure = mitk::PlanarLine::New(); - QString qString; - if(m_CurrentFigureNode.IsNull() || m_LineCounter == 0 || m_CurrentFigureNodeInitialized){ - qString = QString("Line%1").arg(++m_LineCounter); - } - else{ - qString = QString("Line%1").arg(m_LineCounter); - } - this->AddFigureToDataStorage(figure, qString); - - MITK_DEBUG << "PlanarLine initialized..."; -} - -void QmitkMeasurementView::ActionDrawPathTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); - figure->ClosedOff(); - - mitk::BoolProperty::Pointer closedProperty = mitk::BoolProperty::New( false ); - - QString qString; - if(m_CurrentFigureNode.IsNull() || m_PathCounter == 0 || m_CurrentFigureNodeInitialized){ - qString = QString("Path%1").arg(++m_PathCounter); - } - else{ - qString = QString("Path%1").arg(m_PathCounter); - } - this->AddFigureToDataStorage(figure, qString, - "ClosedPlanarPolygon", closedProperty); - - MITK_DEBUG << "PlanarPath initialized..."; -} - -void QmitkMeasurementView::ActionDrawAngleTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - mitk::PlanarAngle::Pointer figure = mitk::PlanarAngle::New(); - QString qString; - if(m_CurrentFigureNode.IsNull() || m_AngleCounter == 0 || m_CurrentFigureNodeInitialized){ - qString = QString("Angle%1").arg(++m_AngleCounter); - } - else{ - qString = QString("Angle%1").arg(m_AngleCounter); - } - this->AddFigureToDataStorage(figure, qString); - - MITK_DEBUG << "PlanarAngle initialized..."; -} - -void QmitkMeasurementView::ActionDrawFourPointAngleTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - mitk::PlanarFourPointAngle::Pointer figure = - mitk::PlanarFourPointAngle::New(); - QString qString; - if(m_CurrentFigureNode.IsNull() || m_FourPointAngleCounter == 0 || m_CurrentFigureNodeInitialized){ - qString = QString("Four Point Angle%1").arg(++m_FourPointAngleCounter); - } - else{ - qString = QString("Four Point Angle%1").arg(m_FourPointAngleCounter); - } - this->AddFigureToDataStorage(figure, qString); - - MITK_DEBUG << "PlanarFourPointAngle initialized..."; -} - -void QmitkMeasurementView::ActionDrawEllipseTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); - QString qString; - if(m_CurrentFigureNode.IsNull() || m_EllipseCounter == 0 || m_CurrentFigureNodeInitialized){ - qString = QString("Circle%1").arg(++m_EllipseCounter); - } - else{ - qString = QString("Circle%1").arg(m_EllipseCounter); - } - this->AddFigureToDataStorage(figure, qString); - - MITK_DEBUG << "PlanarCircle initialized..."; -} - -void QmitkMeasurementView::ActionDrawRectangleTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - mitk::PlanarRectangle::Pointer figure = mitk::PlanarRectangle::New(); - QString qString; - if(m_CurrentFigureNode.IsNull() || m_RectangleCounter == 0 || m_CurrentFigureNodeInitialized){ - qString = QString("Rectangle%1").arg(++m_RectangleCounter); - } - else{ - qString = QString("Rectangle%1").arg(m_RectangleCounter); - } - this->AddFigureToDataStorage(figure, qString); - - MITK_DEBUG << "PlanarRectangle initialized..."; -} - -void QmitkMeasurementView::ActionDrawPolygonTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); - figure->ClosedOn(); - QString qString; - if(m_CurrentFigureNode.IsNull() || m_PolygonCounter == 0 || m_CurrentFigureNodeInitialized){ - qString = QString("Polygon%1").arg(++m_PolygonCounter); - } - else{ - qString = QString("Polygon%1").arg(m_PolygonCounter); - } - this->AddFigureToDataStorage(figure, qString); - - MITK_DEBUG << "PlanarPolygon initialized..."; -} - -void QmitkMeasurementView::ActionDrawArrowTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - MITK_WARN << "Draw Arrow not implemented yet."; -} - -void QmitkMeasurementView::ActionDrawTextTriggered(bool checked) -{ - if(!this->AssertDrawingIsPossible(checked)) - return; - - MITK_WARN << "Draw Text not implemented yet."; -} - -void QmitkMeasurementView::Activated() -{ - m_Activated = true; - MITK_DEBUG << "QmitkMeasurementView::Activated"; - - if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart())) - { - linkedRenderWindow->EnableSlicingPlanes(false); - } - - mitk::TNodePredicateDataType::Pointer isPlanarFigure - = mitk::TNodePredicateDataType::New(); - - mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); - mitk::DataNode* node = 0; - mitk::PlanarFigure* figure = 0; - mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; - // finally add all nodes to the model - for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() - ; it++) - { - node = const_cast(it->Value().GetPointer()); - figure = dynamic_cast(node->GetData()); - if(figure) - { - figureInteractor = dynamic_cast(node->GetInteractor()); - - if(figureInteractor.IsNull()) - figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); - - mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); - } - } - - m_Visible = true; - -} - -void QmitkMeasurementView::Deactivated() -{ - MITK_DEBUG << "QmitkMeasurementView::Deactivated"; -} - -void QmitkMeasurementView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer ) -{ if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { + MEASUREMENT_DEBUG << "enabling linked navigation"; + //linkedRenderWindow->EnableLinkedNavigation(true); linkedRenderWindow->EnableSlicingPlanes(true); } - - this->SetMeasurementInfoToRenderWindow("", m_LastRenderWindow); - this->EnableCrosshairNavigation(); - - mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); - mitk::DataNode* node = 0; - mitk::PlanarFigure* figure = 0; - mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; - // finally add all nodes to the model - for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() - ; it++) - { - node = const_cast(it->Value().GetPointer()); - figure = dynamic_cast(node->GetData()); - if(figure) - { - - figure->RemoveAllObservers(); - figureInteractor = dynamic_cast(node->GetInteractor()); - - if(figureInteractor) - mitk::GlobalInteraction::GetInstance()->RemoveInteractor(figureInteractor); - } - } - - m_Activated = false; -} - -void QmitkMeasurementView::Visible() -{ - m_Visible = true; - MITK_DEBUG << "QmitkMeasurementView::Visible"; -} - -void QmitkMeasurementView::Hidden() -{ - m_Visible = false; - MITK_DEBUG << "QmitkMeasurementView::Hidden"; -} - -void QmitkMeasurementView::PropertyChanged(const mitk::DataNode*, const mitk::BaseProperty*) -{ - this->PlanarFigureSelectionChanged(); -} - -void QmitkMeasurementView::NodeChanged(const mitk::DataNode* /*node* /) -{ - this->PlanarFigureSelectionChanged(); -} - -void QmitkMeasurementView::NodeRemoved(const mitk::DataNode* /*node* /) -{ - this->PlanarFigureSelectionChanged(); -} - -void QmitkMeasurementView::CopyToClipboard(bool) -{ - std::vector headerRow; - std::vector > rows; - QString featureName; - QString featureQuantity; - std::vector newRow; - headerRow.push_back("Name"); - - std::vector nodes = m_SelectedPlanarFigures->GetNodes(); - - for (std::vector::iterator it = nodes.begin(); it - != nodes.end(); ++it) - { - mitk::PlanarFigure* planarFigure = - dynamic_cast ((*it)->GetData()); - if (!planarFigure) - continue; - - newRow.clear(); - newRow.push_back(QString::fromStdString((*it)->GetName())); - newRow.resize(headerRow.size()); - for (unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i) - { - if ( !planarFigure->IsFeatureActive( i ) ) continue; - - featureName = planarFigure->GetFeatureName(i); - featureName.append(QString(" [%1]").arg(planarFigure->GetFeatureUnit(i))); - std::vector::iterator itColumn = std::find(headerRow.begin(), - headerRow.end(), featureName); - - featureQuantity - = QString("%1").arg(planarFigure->GetQuantity(i)).replace(QChar('.'), - ","); - if (itColumn == headerRow.end()) - { - headerRow.push_back(featureName); - newRow.push_back(featureQuantity); - } else - { - newRow[std::distance(headerRow.begin(), itColumn)] = featureQuantity; - } - - } - rows.push_back(newRow); - } - - QString clipboardText; - for (std::vector::iterator it = headerRow.begin(); it - != headerRow.end(); ++it) - clipboardText.append(QString("%1 \t").arg(*it)); - - for (std::vector >::iterator it = rows.begin(); it - != rows.end(); ++it) - { - clipboardText.append("\n"); - for (std::vector::iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) - { - clipboardText.append(QString("%1 \t").arg(*it2)); - } - } - - QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); - -} - -void QmitkMeasurementView::SetMeasurementInfoToRenderWindow(const QString& text, - QmitkRenderWindow* _RenderWindow) -{ - if(m_LastRenderWindow != _RenderWindow) - { - - if(m_LastRenderWindow) - { - QObject::disconnect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) - , this, SLOT( OnRenderWindowDelete(QObject*) ) ); - } - m_LastRenderWindow = _RenderWindow; - if(m_LastRenderWindow) - { - QObject::connect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) - , this, SLOT( OnRenderWindowDelete(QObject*) ) ); - } - } - - if(m_LastRenderWindow) - { - if (!text.isEmpty() && m_SelectedPlanarFigures->GetNode()->IsSelected()) - { - m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); - mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->InsertForegroundRenderer( - m_MeasurementInfoRenderer, true); - } - else - { - if (mitk::VtkLayerController::GetInstance( - m_LastRenderWindow->GetRenderWindow()) ->IsRendererInserted( - m_MeasurementInfoRenderer)) - mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->RemoveRenderer( - m_MeasurementInfoRenderer); - } - } -} - -void QmitkMeasurementView::EnableCrosshairNavigation() -{ - // enable the crosshair navigation - if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart())) - { - linkedRenderWindow->EnableLinkedNavigation(true); - } } void QmitkMeasurementView::DisableCrosshairNavigation() { + MEASUREMENT_DEBUG << "DisableCrosshairNavigation"; + // disable the crosshair navigation during the drawing if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { - linkedRenderWindow->EnableLinkedNavigation(false); - } -} - -void QmitkMeasurementView::SetFocus() -{ - -} - -void QmitkMeasurementView::OnRenderWindowDelete(QObject * obj) -{ - if(obj == m_LastRenderWindow) - m_LastRenderWindow = 0; -} - -void QmitkMeasurementView::ReproducePotentialBug(bool) -{ - std::vector nodes = m_SelectedPlanarFigures->GetNodes(); - QString output; - - for (std::vector::iterator it = nodes.begin(); it - != nodes.end(); ++it) - { - mitk::DataNode* node = *it; - if (!node) continue; - - mitk::PlanarFigure* pf = dynamic_cast( node->GetData() ); - if (!pf) continue; - - output.append("huhu"); - output.append( QString::fromStdString( node->GetName() ) ); - - /** - Bug reproduction: - - 1. get geometry of planar figure from object - - 2. use this geometry to initialize rendering manager via InitializeViews - - 3. see what is produced. the DisplayGeometry of the render window will NOT contain the planar figure nicely. - - * / - - mitk::PlaneGeometry::Pointer planarFigureGeometry = dynamic_cast( pf->GetGeometry() ); - if (planarFigureGeometry.IsNull()) continue; // not expected - - - mitk::PlaneGeometry::Pointer geometryForRendering = dynamic_cast( planarFigureGeometry->Clone().GetPointer() ); - - bool applyWorkaround(true); - geometryForRendering->SetImageGeometry( applyWorkaround ); - - - std::cout << "==== with" << (applyWorkaround?"":"OUT") << " workaround ====================================" << std::endl; - std::cout << "--- PlanarFigure geometry --------------" << std::endl; - planarFigureGeometry->Print(std::cout); - std::cout << "----------------------------------------" << std::endl; - - mitk::RenderingManager::GetInstance()->InitializeViews( geometryForRendering, mitk::RenderingManager::REQUEST_UPDATE_ALL, false ); - - QmitkRenderWindow* renderWindow = this->GetRenderWindowPart()->GetRenderWindows().values().front(); - if (renderWindow == 0) - { - std::cout << "** No QmitkkRenderWindow available **" << std::endl; - return; - } - - std::cout << "--- Renderer->GetDisplayGeometry() ------------" << std::endl; - - renderWindow->GetRenderer()->GetDisplayGeometry()->Print(std::cout); - std::cout << "--- Renderer->GetCurrentWorldGeometry2D() -----" << std::endl; - renderWindow->GetRenderer()->GetCurrentWorldGeometry2D()->Print(std::cout); - std::cout << "--- Renderer->GetWorldGeometry() --------------" << std::endl; - renderWindow->GetRenderer()->GetWorldGeometry()->Print(std::cout); + MEASUREMENT_DEBUG << "disabling linked navigation"; + //linkedRenderWindow->EnableLinkedNavigation(false); + linkedRenderWindow->EnableSlicingPlanes(false); } - - m_SelectedPlanarFiguresText->setText(output); - } -*/ -