Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes

mitk::SlicesSwiveller Class Reference
[Navigation Control Classes]

Enables arbitrary rotation of visible slices around a swivel point (for sliced geometries).This class takes care of several SliceNavigationControllers and handles slice selection / slice rotation. It is added as listener to GlobalInteraction by QmitkStdMultiWidget. More...

#include <mitkSlicesSwiveller.h>

Inheritance diagram for mitk::SlicesSwiveller:
Inheritance graph
[legend]
Collaboration diagram for mitk::SlicesSwiveller:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 mitkClassMacro (SlicesSwiveller, SlicesCoordinator)
 mitkNewMacro1Param (Self, const char *)
 New Macro with one parameter for creating this object with static New(..) method.
virtual void SetGeometry (const itk::EventObject &EventObject)
 Is called whenever a SliceNavigationController invokes an event. Will.

Static Public Member Functions

static Pointer New ()

Protected Member Functions

 SlicesSwiveller (const char *machine)
virtual ~SlicesSwiveller ()
virtual void OnSliceControllerAdded (SliceNavigationController *snc)
virtual void OnSliceControllerRemoved (SliceNavigationController *snc)
virtual void UpdateRelevantSNCs ()
 Updates the list of SliceNavigationControllers that can handle rotation.
virtual bool ExecuteAction (Action *action, StateEvent const *stateEvent)

Protected Attributes

SNCVector m_RelevantSNCs
SNCVector m_SNCsToBeRotated
Point3D m_LastCursorPosition
Point3D m_CenterOfRotation
Point2D m_ReferenceCursor
Vector3D m_RotationPlaneNormal
Vector3D m_RotationPlaneXVector
Vector3D m_RotationPlaneYVector
Vector3D m_PreviousRotationAxis
ScalarType m_PreviousRotationAngle

Detailed Description

Enables arbitrary rotation of visible slices around a swivel point (for sliced geometries).

This class takes care of several SliceNavigationControllers and handles slice selection / slice rotation. It is added as listener to GlobalInteraction by QmitkStdMultiWidget.

The SlicesSwiveller class adds the possibility of slice rotation to the "normal" behaviour of SliceNavigationControllers. This additional class is needed, because one has to be aware of several "visible slices" (selected Geometry2Ds of some SliceNavigationControllers) in order to choose between rotation and slice selection.

Rotation is achieved by modifying (rotating) the generated TimeSlicedGeometry of the corresponding SliceNavigationController.

With SlicesSwiveller, slice rotation works as follows: the user clicks onto a 2D view (2D plane) and drags the mouse; the relative direction and angle of the dragged mouse movement directly effects the rotation axis and angle. If "LinkPlanes" is set to true, the rotation is applied to the planes of all registered SNCs, not only of the one associated with the plane clicked on.

In contrast to the situation without the SlicesRotator, the SliceNavigationControllers are now not directly registered as listeners to GlobalInteraction. SlicesRotator is registered as a listener and decides whether something should be rotated or whether another slice should be selected. In the latter case, a PositionEvent is just forwarded to the SliceNavigationController.

See also:
SlicesRotator

Definition at line 63 of file mitkSlicesSwiveller.h.


Constructor & Destructor Documentation

mitk::SlicesSwiveller::SlicesSwiveller ( const char *  machine ) [protected]

Definition at line 27 of file mitkSlicesSwiveller.cpp.

               {
mitk::SlicesSwiveller::~SlicesSwiveller (  ) [protected, virtual]

Definition at line 33 of file mitkSlicesSwiveller.cpp.

               {

Member Function Documentation

bool mitk::SlicesSwiveller::ExecuteAction ( Action action,
StateEvent const *  stateEvent 
) [protected, virtual]

for implementation in subclasses

Reimplemented from mitk::SlicesCoordinator.

Definition at line 131 of file mitkSlicesSwiveller.cpp.

    {
      if ( fabs(direction1[i] - direction2[i]) > eps ) 
      {
        equal = false;
      }
    }

    if (equal) // equal direction vectors
    {
      m_RelevantSNCs.push_back( *iter );
    }
  }
}

bool SlicesSwiveller
::ExecuteAction(Action* action, StateEvent const* stateEvent)
{
  const ScalarType ThresholdDistancePixels = 6.0;
  
  bool ok = false;
  
  switch ( action->GetActionId() )
  {
    case AcMOVE:
    {
      // just reach through
      SNCVector::iterator iter;
      for ( iter = m_RelevantSNCs.begin(); 
            iter != m_RelevantSNCs.end(); 
            ++iter )
      {
        if ( !(*iter)->GetSliceRotationLocked()  )
        {
          (*iter)->ExecuteAction(action, stateEvent);
        }
      }
      
      ok = true;
      break;
    }
    case AcROTATE:
    {
      const DisplayPositionEvent *posEvent = 
        dynamic_cast<const DisplayPositionEvent*>(stateEvent->GetEvent());

      if (!posEvent) break;
      
      // Determine relative mouse movement projected onto world space
      Point2D cursor = posEvent->GetDisplayPosition();
      Vector2D relativeCursor = cursor - m_ReferenceCursor;
      Vector3D relativeCursorAxis = 
        m_RotationPlaneXVector * relativeCursor[0]
        + m_RotationPlaneYVector * relativeCursor[1];

      // Determine rotation axis (perpendicular to rotation plane and cursor 
      // movement)
      Vector3D rotationAxis = itk::CrossProduct( 
        m_RotationPlaneNormal, relativeCursorAxis );

      ScalarType rotationAngle = relativeCursor.GetNorm() / 2.0;

      // Restore the initial plane pose by undoing the previous rotation
      // operation
      RotationOperation op( OpROTATE, m_CenterOfRotation, 
        m_PreviousRotationAxis, -m_PreviousRotationAngle );

      SNCVector::iterator iter;
      for ( iter = m_SNCsToBeRotated.begin(); 
            iter != m_SNCsToBeRotated.end(); 
            ++iter )
      {
        if ( !(*iter)->GetSliceRotationLocked() )
        {
          const Geometry3D* geometry3D = (*iter)->GetCreatedWorldGeometry();
          const TimeSlicedGeometry* timeSlicedGeometry = 
            dynamic_cast<const TimeSlicedGeometry*>(geometry3D);
          if (!timeSlicedGeometry) continue;
          
          const_cast<TimeSlicedGeometry*>(timeSlicedGeometry)
            ->ExecuteOperation(&op);
          
          (*iter)->SendCreatedWorldGeometryUpdate();
        }
      } 

      // Apply new rotation operation to all relevant SNCs
      RotationOperation op2( OpROTATE, m_CenterOfRotation, 
        rotationAxis, rotationAngle );

      for ( iter = m_SNCsToBeRotated.begin(); 
            iter != m_SNCsToBeRotated.end(); 
            ++iter)
      {
        if ( !(*iter)->GetSliceRotationLocked() )
        {
          //BaseRenderer *renderer = (*iter)->GetRenderer();
          //DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry();

          //Point2D point2DWorld, point2DDisplayPre, point2DDisplayPost;
          //displayGeometry->Map( m_CenterOfRotation, point2DWorld );
          //displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPre );

          // Retrieve the TimeSlicedGeometry of this SliceNavigationController
          const Geometry3D* geometry3D = (*iter)->GetCreatedWorldGeometry();
          const TimeSlicedGeometry* timeSlicedGeometry = 
            dynamic_cast<const TimeSlicedGeometry*>(geometry3D);
          if (!timeSlicedGeometry) continue;

          // Execute the new rotation
          const_cast<TimeSlicedGeometry*>(timeSlicedGeometry)
            ->ExecuteOperation(&op2);

          //displayGeometry->Map( m_CenterOfRotation, point2DWorld );
          //displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPost );
          //Vector2D vector2DDisplayDiff = point2DDisplayPost - point2DDisplayPre;

          //Vector2D origin = displayGeometry->GetOriginInMM();
          //displayGeometry->MoveBy( vector2DDisplayDiff );


          // Notify listeners
          (*iter)->SendCreatedWorldGeometryUpdate();
        }
      } 

      m_PreviousRotationAxis = rotationAxis;
      m_PreviousRotationAngle = rotationAngle;


      RenderingManager::GetInstance()->RequestUpdateAll();
      
      this->InvokeEvent( SliceRotationEvent() ); // notify listeners
      
      ok = true;
      break;
    }
    case AcCHECKPOINT:
    {
      // Decide between moving and rotation: if we're close to the crossing
      // point of the planes, moving mode is entered, otherwise
      // rotation/swivel mode
      const DisplayPositionEvent *posEvent = 
        dynamic_cast<const DisplayPositionEvent*>(stateEvent->GetEvent());

      BaseRenderer *renderer = stateEvent->GetEvent()->GetSender();

      if ( !posEvent || !renderer ) 
      {
        break;
      }


      const Point3D &cursor = posEvent->GetWorldPosition();
      
      m_SNCsToBeRotated.clear();
      
      const PlaneGeometry *clickedGeometry( NULL );
      const PlaneGeometry *otherGeometry1( NULL );
      const PlaneGeometry *otherGeometry2( NULL );
      
      SNCVector::iterator iter;
      for ( iter = m_RelevantSNCs.begin(); iter != m_RelevantSNCs.end(); ++iter )
      {
        //unsigned int slice = (*iter)->GetSlice()->GetPos();
        //unsigned int time  = (*iter)->GetTime()->GetPos();
        
        const PlaneGeometry *planeGeometry = (*iter)->GetCurrentPlaneGeometry();
        if ( !planeGeometry ) continue;

        if ( *iter == renderer->GetSliceNavigationController() )
        {
          clickedGeometry = planeGeometry;
          m_SNCsToBeRotated.push_back(*iter);
        }
        else
        {
          if ( otherGeometry1 == NULL )
          {
            otherGeometry1 = planeGeometry;
          }
          else
          {
            otherGeometry2 = planeGeometry;
          }
          if ( m_LinkPlanes )
          {
            // If planes are linked, apply rotation to all planes
            m_SNCsToBeRotated.push_back(*iter);
          }
        }
      }

      StateEvent *newStateEvent( NULL );

      mitk::Line3D line;
      mitk::Point3D point;
      if ( (clickedGeometry != NULL) && (otherGeometry1 != NULL) 
        && (otherGeometry2 != NULL)
        && clickedGeometry->IntersectionLine( otherGeometry1, line )
        && otherGeometry2->IntersectionPoint( line, point ))
      {
        m_CenterOfRotation = point;
        if ( m_CenterOfRotation.EuclideanDistanceTo( cursor ) 
           < ThresholdDistancePixels )
        {
          newStateEvent = new StateEvent(EIDNO, stateEvent->GetEvent());
        }
        else
        {
          m_ReferenceCursor = posEvent->GetDisplayPosition();

          // Get main axes of rotation plane and store it for rotation step
          m_RotationPlaneNormal = clickedGeometry->GetNormal();

          ScalarType xVector[] = { 1.0, 0.0, 0.0 };
          ScalarType yVector[] = { 0.0, 1.0, 0.0 };
          clickedGeometry->Geometry3D::IndexToWorld( 
            Point3D(), Vector3D( xVector), m_RotationPlaneXVector );
          clickedGeometry->Geometry3D::IndexToWorld( 
            Point3D(), Vector3D( yVector), m_RotationPlaneYVector );

          m_RotationPlaneNormal.Normalize();
          m_RotationPlaneXVector.Normalize();
          m_RotationPlaneYVector.Normalize();

          m_PreviousRotationAxis.Fill( 0.0 );
          m_PreviousRotationAxis[2] = 1.0;
          m_PreviousRotationAngle = 0.0;

          newStateEvent = new StateEvent(EIDYES, stateEvent->GetEvent());
        }
      }
      else
      {
        newStateEvent = new StateEvent(EIDNO, stateEvent->GetEvent());
      }
    
      this->HandleEvent( newStateEvent );
      delete newStateEvent;
mitk::SlicesSwiveller::mitkClassMacro ( SlicesSwiveller  ,
SlicesCoordinator   
)
mitk::SlicesSwiveller::mitkNewMacro1Param ( Self  ,
const char *   
)

New Macro with one parameter for creating this object with static New(..) method.

Reimplemented from mitk::SlicesCoordinator.

SlicesSwiveller::Pointer mitk::SlicesSwiveller::New (  ) [static]
void mitk::SlicesSwiveller::OnSliceControllerAdded ( SliceNavigationController snc ) [protected, virtual]

for implementation in subclasses

Reimplemented from mitk::SlicesCoordinator.

Definition at line 40 of file mitkSlicesSwiveller.cpp.

References New().

void mitk::SlicesSwiveller::OnSliceControllerRemoved ( SliceNavigationController snc ) [protected, virtual]

for implementation in subclasses

Reimplemented from mitk::SlicesCoordinator.

Definition at line 49 of file mitkSlicesSwiveller.cpp.

void mitk::SlicesSwiveller::SetGeometry ( const itk::EventObject &  EventObject ) [virtual]

Is called whenever a SliceNavigationController invokes an event. Will.

Definition at line 57 of file mitkSlicesSwiveller.cpp.

{
void mitk::SlicesSwiveller::UpdateRelevantSNCs (  ) [protected, virtual]

Updates the list of SliceNavigationControllers that can handle rotation.

Definition at line 65 of file mitkSlicesSwiveller.cpp.

{
  if (!snc) return;
  // nothing to do
}

// update the list of SliceNavigationControllers that can handle rotation 
void SlicesSwiveller::SetGeometry(const itk::EventObject& /*EventObject*/)
{
  // there is no way to determine the sender?
  // ==> update whole list of SNCs
  UpdateRelevantSNCs();
}

void SlicesSwiveller::UpdateRelevantSNCs()
{
  m_RelevantSNCs.clear();

  SNCVector::iterator iter;
  for ( iter = m_SliceNavigationControllers.begin(); 
        iter != m_SliceNavigationControllers.end(); 
        ++iter)
  {
    const Geometry3D* geometry3D = (*iter)->GetCreatedWorldGeometry();
    const TimeSlicedGeometry* timeSlicedGeometry = 
      dynamic_cast<const TimeSlicedGeometry*>( geometry3D );
    
    if (!timeSlicedGeometry) continue;

    const SlicedGeometry3D* slicedGeometry = 
      dynamic_cast<const SlicedGeometry3D*>( 
        timeSlicedGeometry->GetGeometry3D(0) );
    if (!slicedGeometry) continue;

    Geometry2D *firstSlice( NULL );
    Geometry2D *secondSlice( NULL );
    
    if (slicedGeometry->IsValidSlice(0))
    {
      firstSlice = slicedGeometry->GetGeometry2D(0);
    }
    if (slicedGeometry->IsValidSlice(1)) 
    {
      secondSlice = slicedGeometry->GetGeometry2D(1);
    }
    
    // If the direction vector of these two slices is the same, then accept 
    // this slice stack as rotatable
    Vector3D right1 = firstSlice->GetAxisVector(0);
    Vector3D up1 = firstSlice->GetAxisVector(1);
    vnl_vector_fixed< ScalarType, 3 > vnlDirection1 = 
      vnl_cross_3d(right1.GetVnlVector(), up1.GetVnlVector());
    Vector3D direction1;
    direction1.SetVnlVector(vnlDirection1);
    
    Vector3D right2 = firstSlice->GetAxisVector(0);

Member Data Documentation

Definition at line 101 of file mitkSlicesSwiveller.h.

Definition at line 99 of file mitkSlicesSwiveller.h.

Definition at line 110 of file mitkSlicesSwiveller.h.

Definition at line 109 of file mitkSlicesSwiveller.h.

Definition at line 103 of file mitkSlicesSwiveller.h.

All SNCs that currently have CreatedWorldGeometries, that can be rotated

Definition at line 94 of file mitkSlicesSwiveller.h.

Definition at line 105 of file mitkSlicesSwiveller.h.

Definition at line 106 of file mitkSlicesSwiveller.h.

Definition at line 107 of file mitkSlicesSwiveller.h.

SNCs that will be rotated (clicked plane + all relevant others, if linked)

Definition at line 97 of file mitkSlicesSwiveller.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines