Index: Core/Code/Controllers/mitkSlicesRotatorMovement.cpp =================================================================== --- Core/Code/Controllers/mitkSlicesRotatorMovement.cpp (revision 0) +++ Core/Code/Controllers/mitkSlicesRotatorMovement.cpp (revision 0) @@ -0,0 +1,488 @@ +/* +* Copyright (c) 2009, +* Computational Image and Simulation Technologies in Biomedicine (CISTIB), +* Universitat Pompeu Fabra (UPF), Barcelona, Spain. All rights reserved. +* See license.txt file for details. +*/ + +#include "mitkSlicesRotatorMovement.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "rotate_cursor.xpm" +#include "move_cursor.xpm" +#include "move_single_plane_cursor.xpm" + +using namespace mitk; + +//! In pixels +const double ThreshHoldDistancePixelsMin = 20; +//! In pixels +const double ThreshHoldDistancePixelsMax = 80; + + +mitk::SlicesRotatorMovement::SlicesRotatorMovement(const char* machine) +: mitk::SlicesRotator(machine) +{ + m_vtkLastRenderWindow = NULL; +} + +SlicesRotatorMovement::~SlicesRotatorMovement() +{ + +} + + +bool mitk::SlicesRotatorMovement::ExecuteAction(Action* action, StateEvent const* stateEvent) +{ + + bool ok = false; + + //std::cout + // << "StateEventID: " << stateEvent->GetId() << ", " + // << "Action: " << action->GetActionId() << ", " + // << "Next State: " << GetCurrentState()->GetName() + // << std::endl; + + switch ( action->GetActionId() ) + { + case AcMOVE: + { + // just reach through + for (SNCVector::iterator iter = m_SNCsToBeMoved.begin(); iter != m_SNCsToBeMoved.end(); ++iter) + { + if ( !(*iter)->GetSliceRotationLocked() ) + { + (*iter)->ExecuteAction(action, stateEvent); + } + } + + ok = true; + break; + } + case AcROTATE: + { + const DisplayPositionEvent* posEvent = dynamic_cast(stateEvent->GetEvent()); + if (!posEvent) break; + + Point3D cursor = posEvent->GetWorldPosition(); + + Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation; + Vector3D toCursor = cursor - m_CenterOfRotation; + + // cross product: | A x B | = |A| * |B| * sin(angle) + Vector3D axisOfRotation; + vnl_vector_fixed< ScalarType, 3 > vnlDirection = vnl_cross_3d( toCursor.GetVnlVector(), toProjected.GetVnlVector() ); + axisOfRotation.SetVnlVector(vnlDirection); + + // scalar product: A * B = |A| * |B| * cos(angle) + // tan = sin / cos + ScalarType angle = - atan2( (double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected) ); + angle *= 180.0 / vnl_math::pi; + m_LastCursorPosition = cursor; + + // create RotationOperation and apply to all SNCs that should be rotated + RotationOperation op(OpROTATE, m_CenterOfRotation, axisOfRotation, angle); + + // TEST + int i = 0; + + for (SNCVector::iterator iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) + { + if ( !(*iter)->GetSliceRotationLocked() ) + { + BaseRenderer *renderer = (*iter)->GetRenderer(); + if ( renderer == NULL ) + { + break; + } + + DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry(); + + // std::cout << i << ":" << std::endl; + + Point2D point2DWorld, point2DDisplayPre, point2DDisplayPost; + displayGeometry->Map( m_CenterOfRotation, point2DWorld ); + displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPre ); + + // std::cout << " WorldPre: " << point2DWorld << " / DisplayPre: " << point2DDisplayPre << std::endl; + + const Geometry3D* geometry3D = (*iter)->GetCreatedWorldGeometry(); + const TimeSlicedGeometry* timeSlicedGeometry = dynamic_cast(geometry3D); + if (!timeSlicedGeometry) continue; + + const_cast(timeSlicedGeometry)->ExecuteOperation(&op); + + displayGeometry->Map( m_CenterOfRotation, point2DWorld ); + displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPost ); + Vector2D vector2DDisplayDiff = point2DDisplayPost - point2DDisplayPre; + + Vector2D origin = displayGeometry->GetOriginInMM(); + // std::cout << " WorldPost: " << point2DWorld << " / DisplayPost: " << point2DDisplayPost << std::endl; + // std::cout << " Diff - " << vector2DDisplayDiff << std::endl; + // std::cout << " Origin - " << origin << std::endl; + ++i; + + displayGeometry->MoveBy( vector2DDisplayDiff ); + + (*iter)->SendCreatedWorldGeometryUpdate(); + } + } + // std::cout << "--------------------------------" << std::endl; + + + + // TEST + //BaseRenderer* renderer = stateEvent->GetEvent()->GetSender(); // TODO this is NOT SNC-specific! Should be! + // + //DisplayGeometry* displayGeometry = renderer->GetDisplayGeometry(); + //if (!displayGeometry) break; + + //Point2D point2DWorld, point2DDisplay; + //displayGeometry->Map( m_CenterOfRotation, point2DWorld ); + //displayGeometry->WorldToDisplay( point2DWorld, point2DDisplay ); + + //std::cout << "RotationCenter: " << m_CenterOfRotation << std::endl; + //std::cout << "PointWorld: " << point2DWorld << std::endl; + //std::cout << "PointDisplay: " << point2DDisplay << std::endl; + //std::cout << "--------------------------------------------" << std::endl; + + + + RenderingManager::GetInstance()->RequestUpdateAll(); + + ok = true; + break; + } + case AcCHECKPOINT: + { + // decide between moving and rotation + // Configure next event + EActions action = AcDONOTHING; + + + // Alle SNCs (Anzahl N) nach dem Abstand von posEvent->GetWorldPosition() zur aktuellen Ebene fragen. + // Anzahl der Ebenen zaehlen, die naeher als ein gewisser Schwellwertwert sind -> nNah. + // Wenn nNah == N + // Generiere ein PointEvent und schicke das an alle SNCs -> bewege den kreuz-mittelpunkt + // Wenn nNah == 2 + // Streiche stateEvent->Sender aus der Liste der nahen Ebenen + // fuer die uebrigen generiere eine RotationOperation und fuehre die aus + // sonst + // + bool positionIsSet = false; + Point3D cursor; + + const DisplayPositionEvent* posEvent = dynamic_cast(stateEvent->GetEvent()); + if (posEvent) + { + cursor = posEvent->GetWorldPosition(); + positionIsSet = true; + } + const KeyEvent* keyEvent = dynamic_cast(stateEvent->GetEvent()); + if ( keyEvent && keyEvent->GetSender() ) + { + keyEvent->GetSender()->PickWorldPoint( keyEvent->GetDisplayPosition(), cursor ); + positionIsSet = true; + } + + if ( positionIsSet ) + { + //m_LastCursorPosition = cursor; + + m_SNCsToBeRotated.clear(); + m_SNCsToBeMoved.clear(); + std::vector geometryArray; + geometryArray.resize( GEOMETRY_MAX ); + + // TODO this is NOT SNC-specific! Should be! + BaseRenderer* renderer = stateEvent->GetEvent()->GetSender(); + if ( renderer != NULL ) + { + GetGeometries( + renderer, + cursor, + geometryArray ); + } + + action = ComputeMoveOrRotate( + renderer, + cursor, + geometryArray ); + } + + + // question in state machine is: "rotate or move?" + StateEvent* newStateEvent(NULL); + switch( action ) + { + case AcMOVE: + // Move + if ( m_SNCsToBeMoved.size() == 2 ) + { + newStateEvent = new StateEvent(EIDAXISCENTERMOVEMENT, stateEvent->GetEvent()); + } + else if ( m_SNCsToBeMoved.size() == 1 ) + { + newStateEvent = new StateEvent(EIDAIXSSINGLEMOVEMENT, stateEvent->GetEvent()); + } + break; + case AcROTATE: + { + // Rotate + newStateEvent = new StateEvent(EIDROTATE, stateEvent->GetEvent()); + } + break; + default: + // Nothing + newStateEvent = new StateEvent(EIDNO, stateEvent->GetEvent()); + break; + } + + this->HandleEvent( newStateEvent ); + delete newStateEvent; + + ok = true; + break; + } + case AcROTATESTART: + { + BaseRenderer* renderer = stateEvent->GetEvent()->GetSender(); + m_vtkLastRenderWindow = renderer->GetRenderWindow(); + ApplicationCursor::GetInstance( )->PushCursor( m_vtkLastRenderWindow, rotate_cursor_xpm, 0, 0); + break; + } + case AcROTATEEND: + { + ApplicationCursor::GetInstance()->PopCursor( m_vtkLastRenderWindow ); + break; + } + case AcSINGLEAXISMOVEMENTSTART: + { + BaseRenderer* renderer = stateEvent->GetEvent()->GetSender(); + m_vtkLastRenderWindow = renderer->GetRenderWindow(); + ApplicationCursor::GetInstance( )->PushCursor( + m_vtkLastRenderWindow, move_single_plane_cursor_xpm, 0, 0); + break; + } + case AcSINGLEAXISMOVEMENTEND: + { + ApplicationCursor::GetInstance()->PopCursor( m_vtkLastRenderWindow ); + break; + } + case AcAXISCENTERMOVEMENTSTART: + { + BaseRenderer* renderer = stateEvent->GetEvent()->GetSender(); + m_vtkLastRenderWindow = renderer->GetRenderWindow(); + ApplicationCursor::GetInstance( )->PushCursor( + m_vtkLastRenderWindow, move_cursor_xpm, 0, 0); + break; + } + case AcAXISCENTERMOVEMENTEND: + { + ApplicationCursor::GetInstance()->PopCursor( m_vtkLastRenderWindow ); + break; + } + default: + { + break; + } + } + + + return ok; +} + + +EActions mitk::SlicesRotatorMovement::ComputeMoveOrRotate( + mitk::BaseRenderer *renderer, + mitk::Point3D cursor, + std::vector &geometryArray ) +{ + + EActions action = AcDONOTHING; + + DisplayGeometry* displayGeometry = renderer->GetDisplayGeometry(); + if ( displayGeometry == NULL ) + { + return AcDONOTHING; + } + + bool isCenterOfRotationComputed = false; + ScalarType cursorCenterDistance = 0; + isCenterOfRotationComputed = ComputeCursorAndCenterOfRotation( + cursor, + displayGeometry, + geometryArray, + cursorCenterDistance ); + + if ( !isCenterOfRotationComputed ) + { + return AcDONOTHING; + } + + int iMinThresholdDistanceCount = 0; + int iMaxThresholdDistanceCount = 0; + double planesDistance = 0; + for ( size_t i = 0 ; i < geometryArray.size() ; i++ ) + { + ScalarType distanceMM = geometryArray[ 0 ]->Distance( cursor ); + + mitk::ScalarType distancePixels; + distancePixels = + distanceMM / displayGeometry->GetScaleFactorMMPerDisplayUnit(); + + planesDistance += pow ( distancePixels, 2 ); + if ( distancePixels < ThreshHoldDistancePixelsMin ) + { + iMinThresholdDistanceCount++; + } + else if ( distancePixels > ThreshHoldDistancePixelsMax ) + { + iMaxThresholdDistanceCount++; + } + } + + planesDistance = sqrt( planesDistance ); + if ( cursorCenterDistance < ThreshHoldDistancePixelsMin && + iMinThresholdDistanceCount > 2 ) + { + action = AcMOVE; + } + else if ( cursorCenterDistance > ThreshHoldDistancePixelsMin && + cursorCenterDistance < ThreshHoldDistancePixelsMax && + iMinThresholdDistanceCount > 1 ) + { + action = AcMOVE; + } + else if ( cursorCenterDistance > ThreshHoldDistancePixelsMax && + iMinThresholdDistanceCount > 1 ) + { + action = AcROTATE; + } + + + return action; +} + +bool mitk::SlicesRotatorMovement::ComputeCursorAndCenterOfRotation( + mitk::Point3D cursor, + DisplayGeometry* displayGeometry, + std::vector &geometryArray, + ScalarType &cursorCenterDistance ) +{ + cursorCenterDistance = 0; + + // determine center of rotation TODO requires two plane geometries... + PlaneGeometry* planeGeometry = dynamic_cast(geometryArray[ GEOMETRY_CLICKED ]); + PlaneGeometry* planeGeometry1 = dynamic_cast(geometryArray[ GEOMETRY_ROTATED ]); + PlaneGeometry* planeGeometry2 = dynamic_cast(geometryArray[ GEOMETRY_OTHER ]); + + if (!planeGeometry || !planeGeometry1 || !planeGeometry2) return false; + + Line3D intersection; + if (!planeGeometry->IntersectionLine( planeGeometry1, intersection )) return false; + m_LastCursorPosition = intersection.Project(cursor); + if (!planeGeometry2->IntersectionPoint(intersection, m_CenterOfRotation)) return false; + + // Compute distance from the cursor to the center of the three planes + cursorCenterDistance = 0; + for(int i=0; i<3; i++) cursorCenterDistance += pow(cursor[i] - m_CenterOfRotation[i],2); + cursorCenterDistance = sqrt( cursorCenterDistance ); + cursorCenterDistance /= displayGeometry->GetScaleFactorMMPerDisplayUnit(); + + return true; +} + +void mitk::SlicesRotatorMovement::GetGeometries( + BaseRenderer* renderer, + mitk::Point3D cursor, + std::vector &geometryArray ) +{ + DisplayGeometry* displayGeometry = renderer->GetDisplayGeometry(); + if ( displayGeometry == NULL ) + { + return; + } + + for (SNCVector::iterator iter = m_RelevantSNCs.begin(); iter != m_RelevantSNCs.end(); ++iter) + { + unsigned int slice = (*iter)->GetSlice()->GetPos(); + unsigned int time = (*iter)->GetTime()->GetPos(); + + const Geometry3D* geometry3D = (*iter)->GetCreatedWorldGeometry(); + const TimeSlicedGeometry* timeSlicedGeometry = dynamic_cast( geometry3D ); + if (!timeSlicedGeometry) continue; + + const SlicedGeometry3D* slicedGeometry = dynamic_cast( timeSlicedGeometry->GetGeometry3D(time) ); + if (!slicedGeometry) continue; + + Geometry2D* geometry2D = slicedGeometry->GetGeometry2D(slice); + if (!geometry2D) continue; // this is not necessary? + + ScalarType distanceMM = geometry2D->Distance( cursor ); + + mitk::ScalarType distancePixels; + distancePixels = + distanceMM / displayGeometry->GetScaleFactorMMPerDisplayUnit(); + + // don't rotate the one where the user clicked + if ( *iter == renderer->GetSliceNavigationController() ) + { + geometryArray[ GEOMETRY_CLICKED ] = geometry2D; + } + else + { + // The first plane found close to the cursor + if ( distancePixels <= ThreshHoldDistancePixelsMin && + geometryArray[ GEOMETRY_ROTATED ] == NULL ) + { + // this one is behind the clicked "line" + m_SNCsToBeRotated.push_back(*iter); + m_SNCsToBeMoved.push_back(*iter); + geometryArray[ GEOMETRY_ROTATED ] = geometry2D; + } + else + { + // This is another plane close to the cursor -> Add to move list + if ( distancePixels <= ThreshHoldDistancePixelsMin ) + { + m_SNCsToBeMoved.push_back(*iter); + } + + // The other plane far away from the cursor + geometryArray[ GEOMETRY_OTHER ] = geometry2D; + + if ( m_LinkPlanes ) + { + // All slices are rotated, i.e. the relative angles between + // slices remain fixed + m_SNCsToBeRotated.push_back(*iter); + } + } + } + + } + +} + + Property changes on: Core\Code\Controllers\mitkSlicesRotatorMovement.cpp ___________________________________________________________________ Added: svn:eol-style + native Index: Core/Code/Controllers/mitkSlicesRotatorMovement.h =================================================================== --- Core/Code/Controllers/mitkSlicesRotatorMovement.h (revision 0) +++ Core/Code/Controllers/mitkSlicesRotatorMovement.h (revision 0) @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2009, +* Computational Image and Simulation Technologies in Biomedicine (CISTIB), +* Universitat Pompeu Fabra (UPF), Barcelona, Spain. All rights reserved. +* See license.txt file for details. +*/ + +#ifndef __mitkSlicesRotatorMovement_H +#define __mitkSlicesRotatorMovement_H + +#include +#include +#include + +namespace mitk{ class Geometry2D; } + +class vtkRenderWindow; + +namespace mitk { + +typedef enum{ + GEOMETRY_CLICKED, + GEOMETRY_ROTATED, + GEOMETRY_OTHER, + GEOMETRY_MAX +} GEOMETRY_TYPE; + +/** + \brief Redefinition of mitk::SlicesRotator, unifying the rotation and + translation. The user needs to drag and drop the axis. The cursor + icon is automatically changed when the mouse pointer can perform + any of the actions. + + There are three states depending on the position of the mouse pointer + related to the axis: + - Center: Axis can be moved in any direction + - Middle: Axis can be translated + - Extremes: Axis can be rotated + + \ingroup NavigationControl + \date 19 09 08 + \author Xavi Planes + */ +class MITK_CORE_EXPORT SlicesRotatorMovement : public mitk::SlicesRotator +{ +public: + + mitkClassMacro(SlicesRotatorMovement, mitk::SlicesRotator); + + mitkNewMacro1Param(Self, const char*); + +protected: + + //! + SlicesRotatorMovement(const char* machine); + + //! Clear list of controllers + virtual ~SlicesRotatorMovement(); + + //! + virtual bool ExecuteAction(mitk::Action * action, mitk::StateEvent const* stateEvent); + + //! + mitk::EActions ComputeMoveOrRotate( + mitk::BaseRenderer *renderer, + mitk::Point3D cursor, + std::vector &geometryArray ); + + //! + bool ComputeCursorAndCenterOfRotation( + mitk::Point3D cursor, + mitk::DisplayGeometry* displayGeometry, + std::vector &geometryArray, + mitk::ScalarType &cursorCenterDistance ); + + //! + void GetGeometries( + mitk::BaseRenderer* renderer, + mitk::Point3D cursor, + std::vector &geometryArray ); + +protected: + + /** + \brief Last accessed vtkRenderWindow + We need to restore the cursor of the mouse when this interactor is + disabled from the global interactor + */ + vtkRenderWindow *m_vtkLastRenderWindow; + + + /// all SNCs that will be moved + SNCVector m_SNCsToBeMoved; + +}; + +} // namespace + +#endif // __mitkSlicesRotatorMovement_H + + Property changes on: Core\Code\Controllers\mitkSlicesRotatorMovement.h ___________________________________________________________________ Added: svn:eol-style + native Index: Core/Code/Controllers/move_cursor.xpm =================================================================== --- Core/Code/Controllers/move_cursor.xpm (revision 0) +++ Core/Code/Controllers/move_cursor.xpm (revision 0) @@ -0,0 +1,41 @@ +/* XPM */ +static const char * move_cursor_xpm[] = { +"32 32 6 1", +" c None", +"! c #000400", +"# c black", +"$ c #FFFFF7", +"% c #F7FFF7", +"& c white", +"!# ", +"!$# ", +"#%&! ", +"!&&&# ", +"!&%&%# ", +"#$&$&$# ", +"#&&$&%&! ", +"!&%&%&%&! ", +"#$&&&$&&%# ", +"#%&$&&!##! ", +"!&&!&$! ", +"#&! !&&! ", +"#! #&%# # ", +" #&&# #&# ", +" !$&! #&&&# ", +" #! #&&&&&# ", +" ##&## ", +" # #&# # ", +" #&# #&# #&# ", +" #&&####&####&&# ", +" #&&&&&&&&&&&&&&&# ", +" #&&####&####&&# ", +" #&# #&# #&# ", +" # #&# # ", +" ##&## ", +" #&&&&&# ", +" #&&&# ", +" #&## ", +" # ", +" ", +" ", +" "}; \ No newline at end of file Property changes on: Core\Code\Controllers\move_cursor.xpm ___________________________________________________________________ Added: svn:eol-style + native Index: Core/Code/Controllers/move_single_plane_cursor.xpm =================================================================== --- Core/Code/Controllers/move_single_plane_cursor.xpm (revision 0) +++ Core/Code/Controllers/move_single_plane_cursor.xpm (revision 0) @@ -0,0 +1,41 @@ +/* XPM */ +static const char * move_single_plane_cursor_xpm[] = { +"32 32 6 1", +" c None", +"! c #000400", +"# c black", +"$ c #FFFFF7", +"% c #F7FFF7", +"& c white", +"!# ", +"!$# ", +"#%&! ", +"!&&&# ", +"!&%&%# ", +"#$&$&$# ", +"#&&$&%&! ", +"!&%&%&%&! ", +"#$&&&$&&%# ", +"#%&$&&!##! ", +"!&&!&$! ", +"#&! !&&! ", +"#! #&%# ", +" #&&# ", +" !$&! ", +" #! #### ", +" #&&&&# ", +" #&&&# ", +" #&#&&# ", +" #&# #&# ", +" #&# # ", +" #&# ", +" # #&# ", +" #&#&# ", +" #&&# ", +" #&&&# ", +" #&&&&# ", +" #### ", +" ", +" ", +" ", +" "}; \ No newline at end of file Property changes on: Core\Code\Controllers\move_single_plane_cursor.xpm ___________________________________________________________________ Added: svn:eol-style + native Index: Core/Code/Interactions/mitkGlobalInteraction.cpp =================================================================== --- Core/Code/Interactions/mitkGlobalInteraction.cpp (revision 21081) +++ Core/Code/Interactions/mitkGlobalInteraction.cpp (working copy) @@ -81,6 +81,8 @@ if ( std::find(m_ListenerList.begin(), m_ListenerList.end(),listener) == m_ListenerList.end() ) { + // Enable this interactor + listener->Enable( true ); m_ListenerList.push_back(listener); } } @@ -111,6 +113,8 @@ StateMachineListIter foundPosition = std::find( m_ListenerList.begin(), m_ListenerList.end(), *it ); if (foundPosition != m_ListenerList.end()) { + // Disable this interactor + (*foundPosition)->Enable( false ); m_ListenerList.erase( foundPosition ); } } @@ -426,3 +430,12 @@ return true; } +void mitk::GlobalInteraction::OnTimeStepChanged( mitk::BaseRenderer* render ) +{ + for (StateMachineListIter it = m_ListenerList.begin(); it != m_ListenerList.end(); it++) + { + if((*it).IsNotNull()) + (*it)->OnTimeStepChanged( render ); + } +} + Index: Core/Code/Interactions/mitkGlobalInteraction.h =================================================================== --- Core/Code/Interactions/mitkGlobalInteraction.h (revision 21081) +++ Core/Code/Interactions/mitkGlobalInteraction.h (working copy) @@ -169,6 +169,9 @@ //so that the interactors can call AddToSelectedInteractors() and RemoveFromSelectedInteractors() friend class Interactor; + //! + void OnTimeStepChanged( mitk::BaseRenderer* render ); + protected: /** * @brief Default Constructor with type to load the StateMachinePattern of the StateMachine Index: Core/Code/Interactions/mitkInteractionConst.h =================================================================== --- Core/Code/Interactions/mitkInteractionConst.h (revision 21081) +++ Core/Code/Interactions/mitkInteractionConst.h (working copy) @@ -58,6 +58,7 @@ EIDLEFTMOUSEBTNANDMOUSEWHEEL = 521, EIDRIGHTMOUSEBTNANDMOUSEWHEEL = 522, EIDMIDDLEMOUSEBTNANDMOUSEWHEEL = 523, + EIDSHIFTANDMOUSEMOVE = 524, EIDLEFTMOUSEBTNANDMOUSEMOVE = 530, EIDRIGHTMOUSEBTNANDMOUSEMOVE = 531, EIDMIDDLEMOUSEBTNANDMOUSEMOVE = 533, @@ -80,7 +81,9 @@ EIDSHIFTANDMIDDLEMOUSEPRESS = 2003, EIDSHIFTANDMIDDLEMOUSEMOVE = 2004, EIDSHIFTANDMIDDLEMOUSERELEASE = 2005, - EIDTDMOUSEINPUT = 4001, // 3d Mouse, SpaceNavigator input + EIDWHEELMOUSEBUTTONUP = 50, // Wheel MouseButton Up + EIDWHEELMOUSEBUTTONDOWN = 51, // Wheel MouseButton Down + EIDTDMOUSEINPUT = 4001, EIDTDMOUSEKEYDOWN = 4002, // 3d Mouse, KeyDown EIDSTRGANDN = 10, EIDSTRGANDE = 11, @@ -105,6 +108,12 @@ EIDSTRGANDALTANDS = 40, EIDALT = 90, EIDSTRGANDB = 91, + EIDA = 92, // Key A + EIDZ = 93, // Key Z + EIDSHIFT = 94, // Shit key + EIDSHIFTRELEASED = 95, // Shit key released + EIDCTRLRELEASED = 96, // Ctrl key released + EIDCTRL = 97, // Ctrl key EIDNEW = 1000, EIDOLD = 1001, EIDFINISHED = 1002, @@ -127,6 +136,16 @@ EIDBODY = 1052, EIDCLEAR = 1100, EIDACTIVATETOOL = 1300, + EIDENABLE = 1400, + EIDDISABLE = 1401, + EIDTIMECHANGED = 1402, + EIDROTATE = 1014, // Rotation start + EIDTRANSLATION = 1015, // Translation start + EIDAIXSSINGLEMOVEMENT = 1016, // Single slice movement + EIDAXISCENTERMOVEMENT = 1017, // Move the center of the axis + EIDPOINTSETEMPTY = 50000, // PointSet is empty + EIDPOINTSETFULL = 50001, // PointSet is full + EIDPOINTSETSPACELEFT = 50002, // Space left in the pointset EIDPRINT = 3001, EV_INIT = 5551001, EV_PREVIOUS = 5551002, @@ -239,6 +258,7 @@ AcCHECKOPERATION = 37, // check if the operation is of one spectial type AcCHECKONESUBINTERACTOR = 38, AcCHECKSUBINTERACTORS = 39, + AcCHECKPOINTSETSIZE = 50000, // Check pointSetSize: empty, full, space left AcFINISHOBJECT = 40, AcFINISHGROUP = 41, AcFINISHMOVEMENT = 42, @@ -358,6 +378,10 @@ AcACCEPT = 49011, AcONTDMOUSEINPUT = 4001, // On input of 3D Mouse AcONTDMOUSEKEYDOWN = 4002, // On input of 3D Mouse + AcSINGLEAXISMOVEMENTSTART = 1013, // Single axis movement start + AcSINGLEAXISMOVEMENTEND = 1014, // Single axis movement end + AcAXISCENTERMOVEMENTSTART = 1015, // + AcAXISCENTERMOVEMENTEND = 1016, // AcCHECKPOSITION = 5000, AcINITIALIZECONTOUR = 5001, AcCALCULATENEWSEGMENTATION_SP= 5002, Index: Core/Code/Interactions/mitkStateMachine.cpp =================================================================== --- Core/Code/Interactions/mitkStateMachine.cpp (revision 21081) +++ Core/Code/Interactions/mitkStateMachine.cpp (working copy) @@ -26,6 +26,7 @@ #include "mitkUndoController.h" #include #include "mitkGlobalInteraction.h" +#include "mitkEventDescription.h" /** @@ -286,3 +287,46 @@ this->ExecuteOperation(doOp); } +void mitk::StateMachine::Enable( bool bValue ) +{ + mitk::StateEvent *newStateEvent( NULL ); + mitk::EventDescription mitkEvent( + mitk::Type_None, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_unknown, "", -1 ); + + // Send event EIDDISABLE + if ( bValue ) + { + newStateEvent = new mitk::StateEvent( EIDENABLE, &mitkEvent ); + } + else + { + newStateEvent = new mitk::StateEvent( EIDDISABLE, &mitkEvent ); + } + + HandleEvent( newStateEvent ); + delete newStateEvent; +} + + +void mitk::StateMachine::OnTimeStepChanged( mitk::BaseRenderer* render ) +{ + if ( render->GetTimeStep() == m_TimeStep ) + { + return; + } + + mitk::StateEvent *newStateEvent( NULL ); + mitk::Event mitkEvent( + render, mitk::Type_None, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_unknown ); + + // Send event EIDTIMECHANGED + newStateEvent = new mitk::StateEvent( EIDTIMECHANGED, &mitkEvent ); + + HandleEvent( newStateEvent ); + delete newStateEvent; +} + +unsigned int mitk::StateMachine::GetTimeStep() const +{ + return m_TimeStep; +} Index: Core/Code/Interactions/mitkStateMachine.h =================================================================== --- Core/Code/Interactions/mitkStateMachine.h (revision 21081) +++ Core/Code/Interactions/mitkStateMachine.h (working copy) @@ -31,6 +31,7 @@ class Action; class StateEvent; class UndoController; + class BaseRenderer; // base class of statem machine functors class MITK_CORE_EXPORT TStateMachineFunctor @@ -176,6 +177,25 @@ friend class GlobalInteraction; + /** + \brief Send the event EIDENABLE or EIDDISABLE to this state machine + when this state machine is added or removed from the mitk::GlobalInteraction + because some state machines needs to change the mouse cursor to the default + */ + void Enable( bool bValue ); + + /** + \brief Send the event EIDTIMECHANGED to this state machine to + notify that the Time step has changed. + This is needed in some state machines like mitk::PointSetInteractor + because the state 0 (no points or loaded points) or 4 (set full) + depends on the current TimeStep. + */ + void OnTimeStepChanged( mitk::BaseRenderer* render ); + + /** + */ + unsigned int GetTimeStep() const; protected: /** Index: Core/Code/Interactions/StateMachine.xml =================================================================== --- Core/Code/Interactions/StateMachine.xml (revision 21081) +++ Core/Code/Interactions/StateMachine.xml (working copy) @@ -68,10 +68,26 @@ + + + + + + + + + + + + + + + + @@ -88,6 +104,8 @@ + + @@ -163,6 +181,11 @@ + + + + + @@ -385,7 +408,7 @@ - - - - - + + + + + - - - - + + + + - - - - - - + + + + + + - - - - + + + + - - - - - - + + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - + + + + @@ -3064,106 +3086,106 @@ - + - + - - - - - - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - - + + - + - - + + - + - + - + - + - + - + - + - + - + - + - + @@ -3241,6 +3263,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: CoreUI/Bundles/org.mitk.gui.qt.common/resources/StateMachine.xml =================================================================== --- CoreUI/Bundles/org.mitk.gui.qt.common/resources/StateMachine.xml (revision 21081) +++ CoreUI/Bundles/org.mitk.gui.qt.common/resources/StateMachine.xml (working copy) @@ -68,10 +68,26 @@ + + + + + + + + + + + + + + + + @@ -88,6 +104,8 @@ + + @@ -163,6 +181,11 @@ + + + + + @@ -3303,6 +3326,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: CoreUI/Qmitk/QmitkRenderWindow.cpp =================================================================== --- CoreUI/Qmitk/QmitkRenderWindow.cpp (revision 21081) +++ CoreUI/Qmitk/QmitkRenderWindow.cpp (working copy) @@ -224,6 +224,21 @@ if (m_ResendQtEvents) ke->ignore(); } +void QmitkRenderWindow::keyReleaseEvent(QKeyEvent *ke) +{ + if (m_Renderer.IsNotNull()) + { + QPoint cp = mapFromGlobal(QCursor::pos()); + mitk::KeyEvent mke(QmitkEventAdapter::AdaptKeyEvent(m_Renderer, ke, cp)); + m_Renderer->KeyPressEvent(&mke); + ke->accept(); + } + + QVTKWidget::keyReleaseEvent(ke); + + if (m_ResendQtEvents) ke->ignore(); +} + void QmitkRenderWindow::enterEvent( QEvent *e ) { //show Menu Widget Index: CoreUI/Qmitk/QmitkRenderWindow.h =================================================================== --- CoreUI/Qmitk/QmitkRenderWindow.h (revision 21081) +++ CoreUI/Qmitk/QmitkRenderWindow.h (working copy) @@ -107,6 +107,8 @@ virtual void mouseReleaseEvent(QMouseEvent* event); // overloaded key press handler virtual void keyPressEvent(QKeyEvent* event); + // overloaded key release handler + virtual void keyReleaseEvent(QKeyEvent* event); // overloaded enter handler virtual void enterEvent(QEvent*); Index: CoreUI/Qmitk/QmitkStdMultiWidget.cpp =================================================================== --- CoreUI/Qmitk/QmitkStdMultiWidget.cpp (revision 21081) +++ CoreUI/Qmitk/QmitkStdMultiWidget.cpp (working copy) @@ -36,6 +36,7 @@ #include "mitkLine.h" #include "mitkInteractionConst.h" #include "mitkDataStorage.h" +#include "mitkSlicesRotatorMovement.h" #include "vtkTextProperty.h" #include "vtkCornerAnnotation.h" @@ -291,7 +292,7 @@ // m_SlicesRotator = mitk::SlicesRotator::New(); // @TODO next line causes sure memory leak // rotator will be created nonetheless (will be switched on and off) - m_SlicesRotator = mitk::SlicesRotator::New("slices-rotator"); + m_SlicesRotator = mitk::SlicesRotatorMovement::New("slices-rotator-and-movement"); m_SlicesRotator->AddSliceController( mitkWidget1->GetSliceNavigationController() ); m_SlicesRotator->AddSliceController( @@ -336,6 +337,8 @@ mitkWidget4->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + EnableTimeObserver( true ); + // instantiate display interactor m_MoveAndZoomInteractor = mitk::DisplayVectorInteractor::New( "moveNzoom", new mitk::DisplayInteractor() ); @@ -413,6 +416,8 @@ { DisablePositionTracking(); DisableNavigationControllerEventListening(); + EnableTimeObserver( false ); + } void QmitkStdMultiWidget::RemovePlanesFromDataStorage() @@ -1570,12 +1575,12 @@ break; case PLANE_MODE_ROTATION: - m_SlicesRotator->ResetMouseCursor(); + m_SlicesRotator->ResetMouseCursor( NULL ); gi->RemoveListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: - m_SlicesSwiveller->ResetMouseCursor(); + m_SlicesSwiveller->ResetMouseCursor( NULL ); gi->RemoveListener( m_SlicesSwiveller ); break; } @@ -1715,7 +1720,7 @@ // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeRotation( false ); - m_SlicesRotator->ResetMouseCursor(); + m_SlicesRotator->ResetMouseCursor( NULL ); gi->RemoveListener( m_SlicesRotator ); break; @@ -1723,7 +1728,7 @@ // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeSwivel( false ); - m_SlicesSwiveller->ResetMouseCursor(); + m_SlicesSwiveller->ResetMouseCursor( NULL ); gi->RemoveListener( m_SlicesSwiveller ); break; } @@ -1940,3 +1945,37 @@ m_RectangleRendering3->Disable(); m_RectangleRendering4->Disable(); } + + +void QmitkStdMultiWidget::EnableTimeObserver( bool enable ) +{ + + mitk::Stepper* timeStepper = m_TimeNavigationController->GetTime(); + + //! an observer to the stepper, in order to change de range dynamically + itk::SimpleMemberCommand::Pointer m_timeStepperChangedCommand; + + // Observer to time stepper + if ( enable ) + { + m_timeStepperChangedCommand = itk::SimpleMemberCommand::New(); + m_timeStepperChangedCommand->SetCallbackFunction(this, &QmitkStdMultiWidget::OnTimeStepperChanged); + + m_timeStepperChangedCommandTag = timeStepper->AddObserver + ( + itk::ModifiedEvent(), + m_timeStepperChangedCommand + ); + } + else + { + timeStepper->RemoveObserver( m_timeStepperChangedCommandTag ); + m_timeStepperChangedCommand = NULL; + } +} + +void QmitkStdMultiWidget::OnTimeStepperChanged( ) +{ + mitk::GlobalInteraction::GetInstance()->OnTimeStepChanged( + mitkWidget4->GetRenderer() ); +} Index: CoreUI/Qmitk/QmitkStdMultiWidget.h =================================================================== --- CoreUI/Qmitk/QmitkStdMultiWidget.h (revision 21081) +++ CoreUI/Qmitk/QmitkStdMultiWidget.h (working copy) @@ -193,6 +193,10 @@ void ResetCrosshair(); + void EnableTimeObserver( bool enable ); + + void OnTimeStepperChanged( ); + signals: void WheelMoved( QWheelEvent* ); @@ -280,6 +284,8 @@ QWidget *mitkWidget3Container; QWidget *mitkWidget4Container; + //! TAG for time stepper observer + unsigned long m_timeStepperChangedCommandTag; }; #endif /*QMITKSTDMULTIWIDGET_H_*/