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 f893b6b51b..3229b590a3 100644 --- a/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml +++ b/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml @@ -1,3867 +1,3838 @@ - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - + - - + + - + - + + + diff --git a/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml b/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml.orig similarity index 96% copy from Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml copy to Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml.orig index f893b6b51b..1392fa4f37 100644 --- a/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml +++ b/Plugins/org.mitk.gui.qt.application/resources/StateMachine.xml.orig @@ -1,3867 +1,3942 @@ +<<<<<<< HEAD +======= + + + +>>>>>>> bug-11950-RedesignMeasurementToolBox +<<<<<<< HEAD +======= + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>>>>>>> bug-11950-RedesignMeasurementToolBox +<<<<<<< HEAD +======= + +>>>>>>> bug-11950-RedesignMeasurementToolBox +<<<<<<< HEAD +======= + + + + + +>>>>>>> bug-11950-RedesignMeasurementToolBox +<<<<<<< HEAD +======= + +>>>>>>> bug-11950-RedesignMeasurementToolBox +<<<<<<< HEAD +======= + + + + + + +>>>>>>> bug-11950-RedesignMeasurementToolBox - + - + + + 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 d72a14b1c1..d9e6375fc4 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp @@ -1,1099 +1,658 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#include -#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" +#define MEASUREMENT_DEBUG MITK_DEBUG("QmitkMeasurementView") << __LINE__ << ": " #include "QmitkMeasurementView.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) -{ +#include -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -QmitkMeasurementView::~QmitkMeasurementView() +struct QmitkPlanarFigureData { - 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 ) ); + QmitkPlanarFigureData() + : m_Figure(0), m_EndPlacementObserverTag(0), m_SelectObserverTag(0), m_StartInteractionObserverTag(0), m_EndInteractionObserverTag(0) + { + } - m_SelectedImageNode->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkMeasurementView::PropertyChanged ) ); + mitk::PlanarFigure* m_Figure; + unsigned int m_EndPlacementObserverTag; + unsigned int m_SelectObserverTag; + unsigned int m_StartInteractionObserverTag; + unsigned int m_EndInteractionObserverTag; +}; - if(this->m_LastRenderWindow != NULL) +struct QmitkMeasurementViewData +{ + QmitkMeasurementViewData() + : m_LineCounter(0), m_PathCounter(0), m_AngleCounter(0), + m_FourPointAngleCounter(0), m_EllipseCounter(0), + m_RectangleCounter(0), m_PolygonCounter(0) { - this->SetMeasurementInfoToRenderWindow("",m_LastRenderWindow); - mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->RemoveRenderer( - m_MeasurementInfoRenderer); } - this->m_MeasurementInfoRenderer->Delete(); -} + // 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) { - m_Parent = parent; - m_MeasurementInfoRenderer = vtkRenderer::New(); - m_MeasurementInfoAnnotation = vtkCornerAnnotation::New(); - vtkTextProperty *textProp = vtkTextProperty::New(); + d->m_Parent = parent; - m_MeasurementInfoAnnotation->SetMaximumFontSize(12); - textProp->SetColor(1.0, 1.0, 1.0); - m_MeasurementInfoAnnotation->SetTextProperty(textProp); + // image label + QLabel* selectedImageLabel = new QLabel("Reference Image: "); + d->m_SelectedImageLabel = new QLabel; + d->m_SelectedImageLabel->setStyleSheet("font-weight: bold;"); - m_MeasurementInfoRenderer->AddActor(m_MeasurementInfoAnnotation); - m_DrawActionsToolBar = new QToolBar; - m_DrawActionsGroup = new QActionGroup(this); - m_DrawActionsGroup->setExclusive(true); + d->m_DrawActionsToolBar = new QToolBar; + d->m_DrawActionsGroup = new QActionGroup(this); + d->m_DrawActionsGroup->setExclusive(true); //# add actions - QAction* currentAction = m_DrawActionsToolBar->addAction(QIcon( + MEASUREMENT_DEBUG << "Draw Line"; + QAction* currentAction = d->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->setCheckable(true); + d->m_DrawLine = currentAction; + d->m_DrawActionsToolBar->addAction(currentAction); + d->m_DrawActionsGroup->addAction(currentAction); - currentAction = m_DrawActionsToolBar->addAction(QIcon( + MEASUREMENT_DEBUG << "Draw Path"; + currentAction = d->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->setCheckable(true); + d->m_DrawPath = currentAction; + d->m_DrawActionsToolBar->addAction(currentAction); + d->m_DrawActionsGroup->addAction(currentAction); - currentAction = m_DrawActionsToolBar->addAction(QIcon( + MEASUREMENT_DEBUG << "Draw Angle"; + currentAction = d->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->setCheckable(true); + d->m_DrawAngle = currentAction; + d->m_DrawActionsToolBar->addAction(currentAction); + d->m_DrawActionsGroup->addAction(currentAction); - currentAction = m_DrawActionsToolBar->addAction(QIcon( + MEASUREMENT_DEBUG << "Draw Four Point Angle"; + currentAction = d->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->setCheckable(true); + d->m_DrawFourPointAngle = currentAction; + d->m_DrawActionsToolBar->addAction(currentAction); + d->m_DrawActionsGroup->addAction(currentAction); - currentAction = m_DrawActionsToolBar->addAction(QIcon( + MEASUREMENT_DEBUG << "Draw Circle"; + currentAction = d->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->setCheckable(true); + d->m_DrawEllipse = currentAction; + d->m_DrawActionsToolBar->addAction(currentAction); + d->m_DrawActionsGroup->addAction(currentAction); - currentAction = m_DrawActionsToolBar->addAction(QIcon( + MEASUREMENT_DEBUG << "Draw Rectangle"; + currentAction = d->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->setCheckable(true); + d->m_DrawRectangle = currentAction; + d->m_DrawActionsToolBar->addAction(currentAction); + d->m_DrawActionsGroup->addAction(currentAction); - currentAction = m_DrawActionsToolBar->addAction(QIcon( + MEASUREMENT_DEBUG << "Draw Polygon"; + currentAction = d->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 ) ); + currentAction->setCheckable(true); + d->m_DrawPolygon = currentAction; + d->m_DrawActionsToolBar->addAction(currentAction); + d->m_DrawActionsGroup->addAction(currentAction); - m_SelectedPlanarFigures->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkMeasurementView::PropertyChanged ) ); + // planar figure details text + d->m_SelectedPlanarFiguresText = new QTextBrowser; - m_SelectedImageNode = mitk::DataStorageSelection::New(this->GetDataStorage(), false); + // copy to clipboard button + d->m_CopyToClipboard = new QPushButton("Copy to Clipboard"); - m_SelectedImageNode->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkMeasurementView::PropertyChanged ) ); + 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); - m_SelectedImageNode->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeChanged ) ); + d->m_Parent->setLayout(d->m_Layout); - m_SelectedImageNode->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeRemoved ) ); - - this->GetDataStorage()->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkMeasurementView::NodeAddedInDataStorage ) ); + // create connections + this->CreateConnections(); + // readd interactors and observers + this->AddAllInteractors(); } - -void QmitkMeasurementView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, - const QList &nodes) +void QmitkMeasurementView::CreateConnections() { - 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(); + 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::PlanarFigureSelectionChanged() +void QmitkMeasurementView::NodeAdded( const mitk::DataNode* node ) { - if ( !this->m_Activated ) return; - - if (m_SelectedImageNode->GetNode().IsNotNull()) + // add observer for selection in renderwindow + mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); + if( figure ) { - mitk::Image* selectedImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); - if(selectedImage && selectedImage->GetDimension() > 3) + 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()) { - m_SelectedImageNode->RemoveAllNodes(); - m_SelectedImage->setText( "4D images are not supported." ); - m_DrawActionsToolBar->setEnabled(false); + figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); } else { - m_SelectedImage->setText(QString::fromStdString( - m_SelectedImageNode->GetNode()->GetName())); - m_DrawActionsToolBar->setEnabled(true); + // just to be sure that the interactor is not added twice + mitk::GlobalInteraction::GetInstance()->RemoveInteractor(figureInteractor); } - } - 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); - } - } + MEASUREMENT_DEBUG << "adding interactor to globalinteraction"; + mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); - 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(); + MEASUREMENT_DEBUG << "will now add observers for planarfigure"; + QmitkPlanarFigureData data; + data.m_Figure = figure; - for (std::vector::iterator it = nodes.begin(); it - != nodes.end(); ++it, ++j) - { - plainInfoText.clear(); - node = *it; - if(j>1) - infoText.append("
"); + // 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 ); - infoText.append(QString("%1
").arg(QString::fromStdString( - node->GetName()))); - plainInfoText.append(QString("%1").arg(QString::fromStdString( - node->GetName()))); + // 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 ); - _PlanarFigure = dynamic_cast (node->GetData()); + // 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 ); - planarAngle = dynamic_cast (_PlanarFigure); - if(!planarAngle) - { - planarFourPointAngle = dynamic_cast (_PlanarFigure); - } + // 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 ); - if(!_PlanarFigure) - continue; + // adding to the map of tracked planarfigures + d->m_DataNodeToPlanarFigureData[nonConstNode] = data; + } + this->CheckForTopMostVisibleImage(); +} - double featureQuantity = 0.0; - for (unsigned int i = 0; i < _PlanarFigure->GetNumberOfFeatures(); ++i) +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) ) { - 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("
"); + renewText = true; + break; } + } - if (j != nodes.size()) - infoText.append("
"); + if(renewText) + { + MEASUREMENT_DEBUG << "Selected nodes changed. Refreshing text."; + this->UpdateMeasurementText(); } - m_SelectedPlanarFiguresText->setHtml(infoText); + this->CheckForTopMostVisibleImage(); +} - // 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; - } - } - } +void QmitkMeasurementView::CheckForTopMostVisibleImage(mitk::DataNode* _NodeToNeglect) +{ + d->m_SelectedImageNode = this->DetectTopMostVisibleImage().GetPointer(); + if( d->m_SelectedImageNode.GetPointer() == _NodeToNeglect ) + d->m_SelectedImageNode = 0; - // 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); - } + if( d->m_SelectedImageNode.IsNotNull() ) + { + MEASUREMENT_DEBUG << "Reference image found"; + d->m_SelectedImageLabel->setText( QString::fromStdString( d->m_SelectedImageNode->GetName() ) ); + d->m_DrawActionsToolBar->setEnabled(true); + MEASUREMENT_DEBUG << "Updating Measurement text"; } - // no last planarfigure else - this->SetMeasurementInfoToRenderWindow("", 0); - - this->RequestRenderWindowUpdate(); + { + 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::NodeAddedInDataStorage(const mitk::DataNode* node) +void QmitkMeasurementView::NodeRemoved(const mitk::DataNode* node) { - if(!m_Visible) - return; + MEASUREMENT_DEBUG << "node removed from data storage"; + mitk::DataNode* nonConstNode = const_cast(node); - mitk::PlanarFigure* figure = dynamic_cast(nonConstNode->GetData()); - if(figure) - { - mitk::PlanarFigureInteractor::Pointer figureInteractor - = dynamic_cast(node->GetInteractor()); + std::map::iterator it = + d->m_DataNodeToPlanarFigureData.find(nonConstNode); - if(figureInteractor.IsNull()) - figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); + if( it != d->m_DataNodeToPlanarFigureData.end() ) + { + QmitkPlanarFigureData& data = it->second; - // 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); + MEASUREMENT_DEBUG << "removing figure interactor to globalinteraction"; + mitk::Interactor::Pointer oldInteractor = node->GetInteractor(); + if(oldInteractor.IsNotNull()) + mitk::GlobalInteraction::GetInstance()->RemoveInteractor(oldInteractor); - this->GetDataStorage()->Remove(m_CurrentFigureNode); - } + // 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::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); + MEASUREMENT_DEBUG << "removing from the list of tracked planar figures"; + d->m_DataNodeToPlanarFigureData.erase( it ); } -} - - -void QmitkMeasurementView::PlanarFigureInitialized() -{ - if(m_CurrentFigureNode.IsNull()) - return; - - 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(); + this->CheckForTopMostVisibleImage(nonConstNode); } -void QmitkMeasurementView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& /*event*/ ) +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 ) + MEASUREMENT_DEBUG << "planar figure " << object << " selected"; + std::map::iterator it = + d->m_DataNodeToPlanarFigureData.begin(); + + d->m_CurrentSelection.clear(); + while( it != d->m_DataNodeToPlanarFigureData.end()) { - // Get node corresponding to PlanarFigure - mitk::DataNode::Pointer figureNode = this->GetDataStorage()->GetNode( - mitk::NodePredicateData::New( figure ) ); + mitk::DataNode* node = it->first; + QmitkPlanarFigureData& data = it->second; - // Select this node (and deselect all others) - QList< mitk::DataNode::Pointer > selectedNodes = this->GetDataManagerSelection(); - for ( int i = 0; i < selectedNodes.size(); i++ ) + if( data.m_Figure == object ) { - selectedNodes[i]->SetSelected( false ); + MITK_DEBUG << "selected node found. enabling selection"; + node->SetSelected(true); + d->m_CurrentSelection.push_back( node ); } - std::vector< mitk::DataNode* > selectedNodes2 = m_SelectedPlanarFigures->GetNodes(); - for ( unsigned int i = 0; i < selectedNodes2.size(); i++ ) + else { - selectedNodes2[i]->SetSelected( false ); + node->SetSelected(false); } - figureNode->SetSelected( true ); - - m_CurrentFigureNode = figureNode; - *m_SelectedPlanarFigures = figureNode; - - // Re-initialize after selecting new PlanarFigure - this->PlanarFigureSelectionChanged(); + ++it; } + this->UpdateMeasurementText(); + this->RequestRenderWindowUpdate(); } - -mitk::DataNode::Pointer QmitkMeasurementView::DetectTopMostVisibleImage() +void QmitkMeasurementView::PlanarFigureInitialized() { - // 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(); + MEASUREMENT_DEBUG << "planar figure initialized"; + d->m_DrawActionsToolBar->setEnabled(true); - // 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; + d->m_DrawLine->setChecked(false); + d->m_DrawPath->setChecked(false); + d->m_DrawAngle->setChecked(false); + d->m_DrawFourPointAngle->setChecked(false); + d->m_DrawEllipse->setChecked(false); + d->m_DrawRectangle->setChecked(false); + d->m_DrawPolygon->setChecked(false); } -void QmitkMeasurementView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, - const char *propertyKey, mitk::BaseProperty *property ) +void QmitkMeasurementView::SetFocus() { - 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(); + d->m_SelectedImageLabel->setFocus(); } -bool QmitkMeasurementView::AssertDrawingIsPossible(bool checked) +void QmitkMeasurementView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, + const QList &nodes) { - if (m_SelectedImageNode->GetNode().IsNull()) - { - checked = false; - this->HandleException("Please select an image!", this->m_Parent, true); - m_DrawLine->setChecked(false); - return false; - } + MEASUREMENT_DEBUG << "Determine the top most visible image"; + MEASUREMENT_DEBUG << "The PlanarFigure interactor will take the currently visible PlaneGeometry from the slice navigation controller"; - mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart()); - if (linkedRenderWindow) - { - linkedRenderWindow->EnableSlicingPlanes(false); - } - // disable the crosshair navigation during the drawing - this->DisableCrosshairNavigation(); + this->CheckForTopMostVisibleImage(); - return checked; + MEASUREMENT_DEBUG << "refreshing selection and detailed text"; + d->m_CurrentSelection = nodes; + this->UpdateMeasurementText(); + this->RequestRenderWindowUpdate(); } 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); - } + QString qString = QString("Line%1").arg(++d->m_LineCounter); this->AddFigureToDataStorage(figure, qString); - MITK_INFO << "PlanarLine initialized..."; + MEASUREMENT_DEBUG << "PlanarLine initialized..."; } void QmitkMeasurementView::ActionDrawPathTriggered(bool checked) { - if(!this->AssertDrawingIsPossible(checked)) - return; - 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); - 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_INFO << "PlanarPath initialized..."; + MEASUREMENT_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); - } + QString qString = QString("Angle%1").arg(++d->m_AngleCounter); this->AddFigureToDataStorage(figure, qString); - MITK_INFO << "PlanarAngle initialized..."; + MEASUREMENT_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); - } + mitk::PlanarFourPointAngle::New(); + QString qString = QString("Four Point Angle%1").arg(++d->m_FourPointAngleCounter); this->AddFigureToDataStorage(figure, qString); - MITK_INFO << "PlanarFourPointAngle initialized..."; + MEASUREMENT_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); - } + QString qString = QString("Circle%1").arg(++d->m_EllipseCounter); this->AddFigureToDataStorage(figure, qString); - MITK_INFO << "PlanarCircle initialized..."; + MEASUREMENT_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); - } + QString qString = QString("Rectangle%1").arg(++d->m_RectangleCounter); this->AddFigureToDataStorage(figure, qString); - MITK_INFO << "PlanarRectangle initialized..."; + MEASUREMENT_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); - } + QString qString = QString("Polygon%1").arg(++d->m_PolygonCounter); this->AddFigureToDataStorage(figure, qString); - MITK_INFO << "PlanarPolygon initialized..."; + MEASUREMENT_DEBUG << "PlanarPolygon initialized..."; } -void QmitkMeasurementView::ActionDrawArrowTriggered(bool checked) +void QmitkMeasurementView::CopyToClipboard( bool checked ) { - if(!this->AssertDrawingIsPossible(checked)) - return; - - MITK_WARN << "Draw Arrow not implemented yet."; + MEASUREMENT_DEBUG << "Copying current Text to clipboard..."; + QString clipboardText = d->m_SelectedPlanarFiguresText->toPlainText(); + QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } -void QmitkMeasurementView::ActionDrawTextTriggered(bool checked) +mitk::DataNode::Pointer QmitkMeasurementView::AddFigureToDataStorage( + mitk::PlanarFigure* figure, const QString& name) { - if(!this->AssertDrawingIsPossible(checked)) - return; + // add as + MEASUREMENT_DEBUG << "Adding new figure to datastorage..."; + if( d->m_SelectedImageNode.IsNull() ) + { + MITK_ERROR << "No reference image available"; + return 0; + } - MITK_WARN << "Draw Text not implemented yet."; + mitk::DataNode::Pointer newNode = mitk::DataNode::New(); + newNode->SetName(name.toStdString()); + newNode->SetData(figure); + // set as selected + 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(); + d->m_DrawActionsToolBar->setEnabled(false); + return newNode; } -void QmitkMeasurementView::Activated() +void QmitkMeasurementView::UpdateMeasurementText() { - m_Activated = true; - MITK_INFO << "QmitkMeasurementView::Activated"; + d->m_SelectedPlanarFiguresText->clear(); - if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart())) + 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) { - linkedRenderWindow->EnableSlicingPlanes(false); - } + plainInfoText.clear(); + node = d->m_CurrentSelection.at(i); + _PlanarFigure = dynamic_cast (node->GetData()); - mitk::TNodePredicateDataType::Pointer isPlanarFigure - = mitk::TNodePredicateDataType::New(); + if( !_PlanarFigure ) + continue; - 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(j>1) + infoText.append("
"); - if(figureInteractor.IsNull()) - figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); + infoText.append(QString("%1
").arg(QString::fromStdString( + node->GetName()))); + plainInfoText.append(QString("%1").arg(QString::fromStdString( + node->GetName()))); - mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); + planarAngle = dynamic_cast (_PlanarFigure); + if(!planarAngle) + { + planarFourPointAngle = dynamic_cast (_PlanarFigure); } - } - m_Visible = true; + 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; -void QmitkMeasurementView::Deactivated() -{ - MITK_INFO << "QmitkMeasurementView::Deactivated"; -} + infoText.append( + QString("%1: %2 %3") .arg(QString( + _PlanarFigure->GetFeatureName(k))) .arg(featureQuantity, 0, 'f', + 2) .arg(QString(_PlanarFigure->GetFeatureUnit(k)))); -void QmitkMeasurementView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer /*newZombiePart*/) -{ - if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = - dynamic_cast(this->GetRenderWindowPart())) - { - linkedRenderWindow->EnableSlicingPlanes(true); + 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("
"); } - this->SetMeasurementInfoToRenderWindow("", m_LastRenderWindow); - this->EnableCrosshairNavigation(); + d->m_SelectedPlanarFiguresText->setHtml(infoText); +} + +void QmitkMeasurementView::AddAllInteractors() +{ + MEASUREMENT_DEBUG << "Adding interactors to all planar figures"; 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 + const mitk::DataNode* node = 0; + 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); - } + this->NodeAdded( node ); } - - m_Activated = false; } -void QmitkMeasurementView::Visible() +void QmitkMeasurementView::RemoveAllInteractors() { - m_Visible = true; - MITK_INFO << "QmitkMeasurementView::Visible"; -} - -void QmitkMeasurementView::Hidden() -{ - m_Visible = false; - MITK_INFO << "QmitkMeasurementView::Hidden"; -} - -void QmitkMeasurementView::PropertyChanged(const mitk::DataNode* /*node*/, const mitk::BaseProperty* /*prop*/) -{ - this->PlanarFigureSelectionChanged(); -} + MEASUREMENT_DEBUG << "Removing interactors and observers from all planar figures"; -void QmitkMeasurementView::NodeChanged(const mitk::DataNode* /*node*/) -{ - this->PlanarFigureSelectionChanged(); -} + mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); + const mitk::DataNode* node = 0; -void QmitkMeasurementView::NodeRemoved(const mitk::DataNode* /*node*/) -{ - this->PlanarFigureSelectionChanged(); + for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() + ; it++) + { + node = const_cast(it->Value().GetPointer()); + this->NodeRemoved( node ); + } } -void QmitkMeasurementView::CopyToClipboard(bool) +mitk::DataNode::Pointer QmitkMeasurementView::DetectTopMostVisibleImage() { - std::vector headerRow; - std::vector > rows; - QString featureName; - QString featureQuantity; - std::vector newRow; - headerRow.push_back("Name"); + // get all images from the data storage + mitk::DataStorage::SetOfObjects::ConstPointer Images + = this->GetDataStorage()->GetSubset( mitk::NodePredicateDataType::New("Image") ); - std::vector nodes = m_SelectedPlanarFigures->GetNodes(); + mitk::DataNode::Pointer currentNode; + int maxLayer = itk::NumericTraits::min(); - for (std::vector::iterator it = nodes.begin(); it - != nodes.end(); ++it) + // iterate over selection + for (mitk::DataStorage::SetOfObjects::ConstIterator sofIt = Images->Begin(); sofIt != Images->End(); ++sofIt) { - mitk::PlanarFigure* planarFigure = - dynamic_cast ((*it)->GetData()); - if (!planarFigure) + 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; - 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*) ) ); - } + currentNode = node; } - 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); - } - } + return currentNode; } void QmitkMeasurementView::EnableCrosshairNavigation() { + MEASUREMENT_DEBUG << "EnableCrosshairNavigation"; + // enable the crosshair navigation if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { - linkedRenderWindow->EnableLinkedNavigation(true); + MEASUREMENT_DEBUG << "enabling linked navigation"; + //linkedRenderWindow->EnableLinkedNavigation(true); + linkedRenderWindow->EnableSlicingPlanes(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); - } - diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h index 048bec3f80..5423827e34 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h @@ -1,221 +1,270 @@ /*=================================================================== 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. ===================================================================*/ #ifndef QMITK_MEASUREMENT_H__INCLUDED #define QMITK_MEASUREMENT_H__INCLUDED +/* #include #include #include #include #include #include #include #include #include #include #include -#include - class QmitkPlanarFiguresTableModel; class QGridLayout; class QMainWindow; class QToolBar; class QLabel; class QTableView; class QTextBrowser; class QActionGroup; class QPushButton; class vtkRenderer; class vtkCornerAnnotation; +*/ +#include +#include + +/// forward declarations +struct QmitkMeasurementViewData; +namespace mitk +{ + class PlanarFigure; +} /// /// A view for doing measurements in digital images by means of /// mitk::Planarfigures which can represent drawing primitives (Lines, circles, ...). /// The view consists of only three main elements: /// 1. A toolbar for activating PlanarFigure drawing /// 2. A textbrowser which shows details for the selected PlanarFigures /// 3. A button for copying all details to the clipboard /// -class QmitkMeasurementView : public QmitkAbstractView, public mitk::IZombieViewPart +class QmitkMeasurementView : public QmitkAbstractView { Q_OBJECT + + public: + + static const std::string VIEW_ID; + QmitkMeasurementView(); + virtual ~QmitkMeasurementView(); + + void CreateQtPartControl(QWidget* parent); + void SetFocus(); + + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, + const QList &nodes); + void NodeAdded(const mitk::DataNode* node); + void NodeChanged(const mitk::DataNode* node); + void NodeRemoved(const mitk::DataNode* node); + + void PlanarFigureSelected( itk::Object* object, const itk::EventObject& ); + protected slots: + ///# draw actions + void ActionDrawLineTriggered( bool checked = false ); + void ActionDrawPathTriggered( bool checked = false ); + void ActionDrawAngleTriggered( bool checked = false ); + void ActionDrawFourPointAngleTriggered( bool checked = false ); + void ActionDrawEllipseTriggered( bool checked = false ); + void ActionDrawRectangleTriggered( bool checked = false ); + void ActionDrawPolygonTriggered( bool checked = false ); + void CopyToClipboard( bool checked = false ); + + private: + void CreateConnections(); + mitk::DataNode::Pointer AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name); + void UpdateMeasurementText(); + void AddAllInteractors(); + void RemoveAllInteractors(); + mitk::DataNode::Pointer DetectTopMostVisibleImage(); + void EnableCrosshairNavigation(); + void DisableCrosshairNavigation(); + void PlanarFigureInitialized(); + void CheckForTopMostVisibleImage(mitk::DataNode* _NodeToNeglect=0); + + QmitkMeasurementViewData* d; +}; + +/* public: /// /// Just a shortcut /// typedef std::vector DataNodes; /// /// Initialize pointers to 0. The rest is done in CreateQtPartControl() /// QmitkMeasurementView(); /// /// Remove all event listener from DataStorage, DataStorageSelection, Selection Service /// virtual ~QmitkMeasurementView(); - static const std::string VIEW_ID; public: /// /// Initializes all variables. /// Builds up GUI. /// void CreateQtPartControl(QWidget* parent); /// /// Set widget planes visibility to false. /// Show only transversal view. /// Add an interactor to all PlanarFigures in the DataStorage (if they dont have one yet). /// Add their interactor to the global interaction. /// virtual void Activated(); virtual void Deactivated(); virtual void Visible(); virtual void Hidden(); /// /// Show widget planes and all renderwindows again. /// Remove all planar figure interactors from the global interaction. /// virtual void ActivatedZombieView(berry::IWorkbenchPartReference::Pointer zombieView); /// /// Invoked from a DataStorage selection /// virtual void NodeChanged(const mitk::DataNode* node); virtual void PropertyChanged(const mitk::DataNode* node, const mitk::BaseProperty* prop); virtual void NodeRemoved(const mitk::DataNode* node); virtual void NodeAddedInDataStorage(const mitk::DataNode* node); virtual void PlanarFigureInitialized(); virtual void PlanarFigureSelected( itk::Object* object, const itk::EventObject& event ); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); /// /// Invoked when the DataManager selection changed. /// If an image is in the selection it will be set as the selected one for measurement, /// If a planarfigure is in the selection its parent image will be set as the selected one for measurement. /// All selected planarfigures will be added to m_SelectedPlanarFigures. /// Then PlanarFigureSelectionChanged is called /// virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes); public slots: /// /// Called when the renderwindow gets deleted /// void OnRenderWindowDelete(QObject * obj = 0); protected: /// /// Prints all features of the selected PlanarFigures into the TextBrowser. /// For the last figure in the selection list: /// - Go to the corresponding slice and show figure /// - Draw info text on the bottom right side of the corresponding renderwindow /// void PlanarFigureSelectionChanged(); /// Draws a string on the bottom left side of the render window /// void SetMeasurementInfoToRenderWindow(const QString& text, QmitkRenderWindow* _RenderWindow); bool AssertDrawingIsPossible(bool checked); void EnableCrosshairNavigation(); void DisableCrosshairNavigation(); void SetFocus(); protected slots: ///# draw actions void ActionDrawLineTriggered( bool checked = false ); void ActionDrawPathTriggered( bool checked = false ); void ActionDrawAngleTriggered( bool checked = false ); void ActionDrawFourPointAngleTriggered( bool checked = false ); void ActionDrawEllipseTriggered( bool checked = false ); void ActionDrawRectangleTriggered( bool checked = false ); void ActionDrawPolygonTriggered( bool checked = false ); void ActionDrawArrowTriggered( bool checked = false ); void ActionDrawTextTriggered( bool checked = false ); void CopyToClipboard( bool checked = false ); void ReproducePotentialBug(bool); // fields // widgets protected: - QWidget* m_Parent; - QGridLayout* m_Layout; - QLabel* m_SelectedImage; 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; vtkRenderer * m_MeasurementInfoRenderer; vtkCornerAnnotation *m_MeasurementInfoAnnotation; // Selection service /// berry::SelectionChangedAdapter must be a friend to call friend struct berry::SelectionChangedAdapter; berry::ISelectionListener::Pointer m_SelectionListener; mitk::DataStorageSelection::Pointer m_SelectedPlanarFigures; /// Selected image on which measurements will be performed /// mitk::DataStorageSelection::Pointer m_SelectedImageNode; mitk::DataNode::Pointer m_CurrentFigureNode; /// Counter variables to give a newly created Figure a unique name. /// 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; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; bool m_Visible; bool m_CurrentFigureNodeInitialized; bool m_Activated; /// /// Saves the last renderwindow any info data was inserted /// QmitkRenderWindow* m_LastRenderWindow; private: + void RemoveEndPlacementObserverTag(); mitk::DataNode::Pointer DetectTopMostVisibleImage(); - -}; + */ #endif // QMITK_MEASUREMENT_H__INCLUDED