]> Creatis software - cpPlugins.git/blobdiff - lib/cpPlugins/Extensions/Visualization/ImageInteractorStyle.cxx
Major refactoring: API-HCI bug corrected.
[cpPlugins.git] / lib / cpPlugins / Extensions / Visualization / ImageInteractorStyle.cxx
index d017cb2c3a8148f1aac4b43eed5def93db266643..d69d1e3958a57dda651cf69a66dfdd06cb577096 100644 (file)
@@ -1,10 +1,15 @@
 #include <cpPlugins/Extensions/Visualization/ImageInteractorStyle.h>
 
+#include <cmath>
+#include <ctime>
+
 #include <vtkAnnotatedCubeActor.h>
 #include <vtkAxesActor.h>
 #include <vtkCallbackCommand.h>
 #include <vtkCamera.h>
+#include <vtkCellArray.h>
 #include <vtkCommand.h>
+#include <vtkMatrix4x4.h>
 #include <vtkPropAssembly.h>
 #include <vtkProperty.h>
 #include <vtkRendererCollection.h>
 
 // -------------------------------------------------------------------------
 const int cpPlugins::Extensions::Visualization::
-ImageInteractorStyle::SliceEvent = vtkCommand::UserEvent + 1;
+ImageInteractorStyle::CursorEvent = vtkCommand::UserEvent + 1;
+const int cpPlugins::Extensions::Visualization::
+ImageInteractorStyle::RadiusEvent = vtkCommand::UserEvent + 2;
+const int cpPlugins::Extensions::Visualization::
+ImageInteractorStyle::DoubleClickEvent = vtkCommand::UserEvent + 3;
 
 // -------------------------------------------------------------------------
 cpPlugins::Extensions::Visualization::ImageInteractorStyle::
@@ -73,8 +82,6 @@ SetInteractor( vtkRenderWindowInteractor* interactor, const int& axis )
   if( interactor == NULL )
     return;
 
-  // TODO: interactor->SetPicker( this->PropPicker );
-
   // Get camera, avoiding segfaults
   vtkRenderer* ren =
     interactor->GetRenderWindow( )->GetRenderers( )->GetFirstRenderer( );
@@ -114,19 +121,47 @@ SetInteractor( vtkRenderWindowInteractor* interactor, const int& axis )
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnMouseMove( )
 {
-  double pos[ 3 ];
-  if( this->CursorMoving && this->m_MPRActors != NULL )
+  if( this->m_MPRActors == NULL )
+    return;
+  
+  if( this->CursorMoving )
   {
-    bool picked = this->_PickPosition( pos );
+    bool picked = this->_PickPosition( this->Cursor );
     if( picked )
     {
       for( int i = 0; i < 3; ++i )
         if( this->m_SliceActors->GetAxis( ) != i )
-          this->m_MPRActors->SetSlice( i, pos[ i ] );
+          this->m_MPRActors->SetSlice( i, this->Cursor[ i ] );
+      this->InvokeEvent( Self::CursorEvent, this->Cursor );
       this->Interactor->Render( );
       this->_RenderAssociateInteractors( );
 
     } // fi
+  }
+  else if( this->RadiusMoving )
+  {
+    bool picked = this->_PickPosition( this->Radius );
+    if( picked )
+    {
+      this->InvokeEvent( Self::RadiusEvent, this->Radius );
+      this->_UpdateRadius( );
+
+    } // fi
+  }
+  else
+  {
+    switch( this->State )
+    {
+    case VTKIS_WINDOW_LEVEL:
+      this->WindowLevel( );
+      break;
+    case VTKIS_DOLLY:
+      this->Dolly( );
+      break;
+    case VTKIS_PAN:
+      this->Pan( );
+      break;
+    } // hctiws
 
   } // fi
 }
@@ -135,48 +170,32 @@ OnMouseMove( )
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnLeftButtonDown( )
 {
-  int x = this->Interactor->GetEventPosition( )[ 0 ];
-  int y = this->Interactor->GetEventPosition( )[ 1 ];
-
-  this->FindPokedRenderer( x, y );
+  static double pnt[ 3 ];
+  static int pos[ 2 ];
+  this->Interactor->GetEventPosition( pos );
+  this->FindPokedRenderer( pos[ 0 ], pos[ 1 ] );
   if( this->CurrentRenderer == NULL )
     return;
-
-  // Redefine this button to handle window/level
   this->GrabFocus( this->EventCallbackCommand );
 
-  if( this->Interactor->GetControlKey( ) )
-    this->StartCursorMoving( );
-
-  /* TODO
-     if (!this->Interactor->GetShiftKey() && !this->Interactor->GetControlKey())
-     {
-     this->WindowLevelStartPosition[0] = x;
-     this->WindowLevelStartPosition[1] = y;
-     this->StartWindowLevel();
-     }
-
-     // If shift is held down, do a rotation
-     else if (this->InteractionMode == VTKIS_IMAGE3D &&
-     this->Interactor->GetShiftKey())
-     {
-     this->StartRotate();
-     }
-
-     // If ctrl is held down in slicing mode, slice the image
-     else if (this->InteractionMode == VTKIS_IMAGE_SLICING &&
-     this->Interactor->GetControlKey())
-     {
-     this->StartSlice();
-     }
-
-     // The rest of the button + key combinations remain the same
-
-     else
-     {
-     this->Superclass::OnLeftButtonDown();
-     }
-  */
+  // TODO: check this code
+  // Manage double-click
+  static const long epsilon_time = 800;
+  static long last_click_time = -( epsilon_time << 1 );
+  long click_time = static_cast< long >( std::clock( ) );
+  if( ( click_time - last_click_time ) < epsilon_time )
+  {
+    last_click_time = -( epsilon_time << 1 );
+    if( this->_PickPosition( pnt ) )
+      this->InvokeEvent( Self::DoubleClickEvent, pnt );
+  }
+  else
+  {
+    last_click_time = click_time;
+    if( this->Interactor->GetControlKey( ) )
+      this->StartCursorMoving( );
+
+  } // fi
 }
 
 // -------------------------------------------------------------------------
@@ -184,35 +203,103 @@ void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnLeftButtonUp( )
 {
   if( this->CursorMoving )
+  {
     this->EndCursorMoving( );
+    if( this->Interactor )
+      this->ReleaseFocus( );
+
+  } // fi
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnMiddleButtonDown( )
 {
-  std::cout << "middown" << std::endl;
+  int x = this->Interactor->GetEventPosition( )[ 0 ];
+  int y = this->Interactor->GetEventPosition( )[ 1 ];
+
+  this->FindPokedRenderer( x, y );
+  if( this->CurrentRenderer == NULL )
+    return;
+  this->GrabFocus( this->EventCallbackCommand );
+
+  if( this->Interactor->GetAltKey( ) )
+  {
+  }
+  else if( this->Interactor->GetControlKey( ) )
+  {
+    this->StartRadiusMoving( );
+  }
+  else if( this->Interactor->GetShiftKey( ) )
+  {
+  }
+  else
+    this->StartPan( );
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnMiddleButtonUp( )
 {
-  std::cout << "midup" << std::endl;
+  if( this->RadiusMoving )
+  {
+    this->EndRadiusMoving( );
+    if( this->Interactor )
+      this->ReleaseFocus( );
+  }
+  else
+  {
+    switch( this->State )
+    {
+    case VTKIS_PAN:
+      this->EndPan( );
+      break;
+    } // hctiws
+
+  } // fi
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnRightButtonDown( )
 {
-  std::cout << "ridown" << std::endl;
+  int x = this->Interactor->GetEventPosition( )[ 0 ];
+  int y = this->Interactor->GetEventPosition( )[ 1 ];
+
+  this->FindPokedRenderer( x, y );
+  if( this->CurrentRenderer == NULL )
+    return;
+  this->GrabFocus( this->EventCallbackCommand );
+
+  if( this->Interactor->GetControlKey( ) )
+  {
+    this->WindowLevelStartPosition[ 0 ] = x;
+    this->WindowLevelStartPosition[ 1 ] = y;
+    this->StartWindowLevel( );
+  }
+  else
+  {
+    this->StartDolly( );
+  } // fi
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnRightButtonUp( )
 {
-  std::cout << "riup" << std::endl;
+  switch( this->State )
+  {
+  case VTKIS_WINDOW_LEVEL:
+  {
+    this->EndWindowLevel( );
+    if( this->Interactor )
+      this->ReleaseFocus( );
+  }
+  break;
+  case VTKIS_DOLLY:
+    this->EndDolly( );
+    break;
+  } // hctiws
 }
 
 // -------------------------------------------------------------------------
@@ -251,116 +338,160 @@ OnMouseWheelBackward( )
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 OnChar( )
 {
-  std::cout << "char" << std::endl;
-}
-
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-Rotate( )
-{
-  std::cout << "Rotate" << std::endl;
-}
-
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-Pan( )
-{
-  std::cout << "pan" << std::endl;
-}
-
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-Spin( )
-{
-  std::cout << "spin" << std::endl;
-}
+  switch( this->Interactor->GetKeyCode( ) )
+  {
+  case 'r': case 'R':
+  {
+    vtkRenderer* ren =
+      this->Interactor->GetRenderWindow( )->
+      GetRenderers( )->GetFirstRenderer( );
+    if( ren != NULL )
+      ren->ResetCamera( );
+    this->Interactor->Render( );
+  }
+  break;
+  case 'w': case 'W': case 'l': case 'L':
+  {
+    if( this->m_MPRActors != NULL )
+    {
+      this->m_MPRActors->ResetWindowLevel( );
+      this->Interactor->Render( );
+      this->_RenderAssociateInteractors( );
 
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-Zoom( )
-{
-  std::cout << "Zoom" << std::endl;
+    } // fi
+  }
+  break;
+  } // hctiws
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 WindowLevel( )
 {
-  std::cout << "wl" << std::endl;
-}
-
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-Pick( )
-{
-  std::cout << "Pick" << std::endl;
-}
+  if( this->Mode == Self::NavigationMode )
+  {
+    if( this->Interactor == NULL )
+      return;
+    vtkRenderer* ren =
+      this->Interactor->GetRenderWindow( )->
+      GetRenderers( )->GetFirstRenderer( );
+    if( ren == NULL )
+      return;
+
+    // Compute scales
+    this->WindowLevelCurrentPosition[ 0 ] =
+      this->Interactor->GetEventPosition( )[ 0 ];
+    this->WindowLevelCurrentPosition[ 1 ] =
+      this->Interactor->GetEventPosition( )[ 1 ];
+    int* size = ren->GetSize( );
+    double sw = double(
+      this->WindowLevelCurrentPosition[ 0 ] -
+      this->WindowLevelStartPosition[ 0 ]
+      ) / double( size[ 0 ] );
+    double sl = (
+      this->WindowLevelStartPosition[ 1 ] -
+      this->WindowLevelCurrentPosition[ 1 ]
+      ) / double( size[ 1 ] );
+
+    double w = this->WindowLevelInitial[ 0 ] * ( double( 1 ) + sw );
+    double l = this->WindowLevelInitial[ 1 ] * ( double( 1 ) + sl );
+    double minw = this->m_MPRActors->GetMinWindow( );
+    double maxw = this->m_MPRActors->GetMaxWindow( );
+    double minl = this->m_MPRActors->GetMinLevel( );
+    double maxl = this->m_MPRActors->GetMaxLevel( );
+
+    if( w < minw ) w = minw;
+    if( maxw < w ) w = maxw;
+    if( l < minl ) l = minl;
+    if( maxl < l ) l = maxl;
+
+    this->m_MPRActors->SetWindowLevel( w, l );
+    this->Interactor->Render( );
+    this->_RenderAssociateInteractors( );
+  }
+  else if( this->Mode == Self::DeformationMode )
+  {
+    // TODO
 
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-Slice( )
-{
-  std::cout << "Slice" << std::endl;
+  } // fi
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
 StartWindowLevel( )
 {
-  std::cout << "swl" << std::endl;
-}
+  if( this->State != VTKIS_NONE )
+    return;
+  if( this->Mode == Self::NavigationMode )
+  {
+    this->StartState( VTKIS_WINDOW_LEVEL );
 
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-EndWindowLevel( )
-{
-  std::cout << "ewl" << std::endl;
-}
+    this->WindowLevelInitial[ 0 ] = this->m_MPRActors->GetWindow( );
+    this->WindowLevelInitial[ 1 ] = this->m_MPRActors->GetLevel( );
+  }
+  else if( this->Mode == Self::DeformationMode )
+  {
+    // TODO
 
-// -------------------------------------------------------------------------
-void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-StartPick( )
-{
-  std::cout << "sp" << std::endl;
+  } // fi
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-EndPick( )
+EndWindowLevel( )
 {
-  std::cout << "ep" << std::endl;
+  if( this->Mode == Self::NavigationMode )
+  {
+    if( this->State != VTKIS_WINDOW_LEVEL )
+      return;
+    this->StopState( );
+  }
+  else
+  {
+    // TODO
+
+  } // fi
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-StartSlice( )
+StartCursorMoving( )
 {
-  std::cout << "ss" << std::endl;
+  if( this->CursorMoving )
+    return;
+  this->_PickPosition( this->Cursor );
+  this->CursorMoving = true;
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-EndSlice( )
+EndCursorMoving( )
 {
-  std::cout << "es" << std::endl;
+  if( !( this->CursorMoving ) )
+    return;
+  this->CursorMoving = false;
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-StartCursorMoving( )
+StartRadiusMoving( )
 {
-  if( this->CursorMoving )
+  if( this->RadiusMoving )
     return;
-  this->CursorMoving = true;
+  this->_PickPosition( this->Radius );
+  this->RadiusMoving = true;
+  this->_UpdateRadius( );
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
-EndCursorMoving( )
+EndRadiusMoving( )
 {
-  if( !( this->CursorMoving ) )
+  if( !( this->RadiusMoving ) )
     return;
-  this->CursorMoving = false;
+  this->RadiusMoving = false;
+  this->_UpdateRadius( );
+  this->InvokeEvent( Self::RadiusEvent, NULL );
 }
 
 // -------------------------------------------------------------------------
@@ -370,7 +501,8 @@ ImageInteractorStyle( )
     Mode( Self::NavigationMode ),
     m_SliceActors( NULL ),
     m_MPRActors( NULL ),
-    CursorMoving( false )
+    CursorMoving( false ),
+    RadiusMoving( false )
 {
   // Orientation marks
   vtkSmartPointer< vtkAnnotatedCubeActor > cube =
@@ -410,6 +542,36 @@ ImageInteractorStyle( )
   this->OrientationWidget->SetOrientationMarker( actors );
   this->OrientationWidget->SetViewport( 0.0, 0.0, 0.2, 0.2 );
 
+  // Circle
+  unsigned long circle_samples = 1000;
+  this->Circle = vtkSmartPointer< vtkPolyData >::New( );
+
+  vtkSmartPointer< vtkPoints > circle_points =
+    vtkSmartPointer< vtkPoints >::New( );
+  vtkSmartPointer< vtkCellArray > circle_lines =
+    vtkSmartPointer< vtkCellArray >::New( );
+  for( unsigned long s = 0; s < circle_samples; ++s )
+  {
+    double t = double( 6.2832 ) * double( s ) / double( circle_samples );
+    circle_points->InsertNextPoint(
+      std::cos( t ), std::sin( t ), double( 0 )
+      );
+
+    circle_lines->InsertNextCell( 2 );
+    circle_lines->InsertCellPoint( s );
+    circle_lines->InsertCellPoint( ( s + 1 ) % circle_samples );
+
+  } // rof
+  this->Circle->SetPoints( circle_points );
+  this->Circle->SetLines( circle_lines );
+
+  this->CircleMapper = vtkSmartPointer< vtkPolyDataMapper >::New( );
+  this->CircleMapper->SetInputData( this->Circle );
+  this->CircleActor = vtkSmartPointer< vtkActor >::New( );
+  this->CircleActor->SetMapper( this->CircleMapper );
+  this->CircleActor->GetProperty( )->SetColor( 1, 0, 1 );
+  this->CircleActor->GetProperty( )->SetLineWidth( 2 );
+
   this->PropPicker = vtkSmartPointer< vtkPropPicker >::New( );
   this->PropPicker->PickFromListOn( );
 }
@@ -445,6 +607,11 @@ _PickPosition( double pos[ 3 ] )
   if( success == 0 )
     return( false );
   this->PropPicker->GetPickPosition( pos );
+
+  int axis = this->m_SliceActors->GetAxis( );
+  double* bounds = this->m_SliceActors->GetDisplayBounds( );
+  pos[ axis ] = bounds[ axis << 1 ];
+
   return( true );
 }
 
@@ -455,4 +622,56 @@ _UpdateCursor( )
   std::cout << "upcur" << std::endl;
 }
 
+// -------------------------------------------------------------------------
+void cpPlugins::Extensions::Visualization::ImageInteractorStyle::
+_UpdateRadius( )
+{
+  vtkRenderer* ren =
+    this->Interactor->GetRenderWindow( )->
+    GetRenderers( )->GetFirstRenderer( );
+  if( ren == NULL )
+    return;
+  vtkCamera* cam = ren->GetActiveCamera( );
+  if( cam == NULL )
+    return;
+
+  if( this->RadiusMoving )
+  {
+    double x = this->Cursor[ 0 ] - this->Radius[ 0 ];
+    double y = this->Cursor[ 1 ] - this->Radius[ 1 ];
+    double z = this->Cursor[ 2 ] - this->Radius[ 2 ];
+    double r = std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
+
+    vtkMatrix4x4* cam_matrix = cam->GetModelViewTransformMatrix( );
+    vtkSmartPointer< vtkMatrix4x4 > circle_matrix =
+      this->CircleActor->GetUserMatrix( );
+    if( circle_matrix.GetPointer( ) == NULL )
+    {
+      circle_matrix = vtkSmartPointer< vtkMatrix4x4 >::New( );
+      this->CircleActor->SetUserMatrix( circle_matrix );
+
+    } // fi
+    for( int i = 0; i < 4; ++i )
+    {
+      for( int j = 0; j < 4; ++j )
+      {
+        double v = cam_matrix->GetElement( i, j );
+        if( i < 3 && j == 3 )
+          v = this->Cursor[ i ];
+        if( i < 3 && j < 3 )
+          v *= r;
+        circle_matrix->SetElement( i, j, v );
+
+      } // rof
+
+    } // rof
+    this->CircleActor->Modified( );
+    ren->AddActor( this->CircleActor );
+  }
+  else
+    ren->RemoveActor( this->CircleActor );
+
+  this->Interactor->Render( );
+}
+
 // eof - $RCSfile$