]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageSliceActors.cxx
...
[cpPlugins.git] / lib / cpExtensions / Visualization / ImageSliceActors.cxx
1 #include <cpExtensions/Visualization/ImageSliceActors.h>
2
3 #include <sstream>
4 #include <vtkCamera.h>
5 #include <vtkImageData.h>
6 #include <vtkImageProperty.h>
7 #include <vtkPlane.h>
8 #include <vtkProperty.h>
9 #include <vtkRenderer.h>
10 #include <vtkRenderWindow.h>
11 #include <vtkTextProperty.h>
12
13 // -------------------------------------------------------------------------
14 cpExtensions::Visualization::ImageSliceActors::
15 Self* cpExtensions::Visualization::ImageSliceActors::
16 New( )
17 {
18   return( new Self( ) );
19 }
20
21 // -------------------------------------------------------------------------
22 void cpExtensions::Visualization::ImageSliceActors::
23 Clear( )
24 {
25   this->RemoveAllItems( );
26
27   // Main image
28   this->m_Mapper = vtkSmartPointer< vtkImageSliceMapper >::New( );
29   this->m_Actor = vtkSmartPointer< vtkImageActor >::New( );
30   this->m_Actor->SetMapper( this->m_Mapper );
31
32   // Cursor
33   this->m_Cursor.Create( );
34   this->m_Cursor.Actor->GetProperty( )->SetColor( 1, 1, 0 );
35
36   // Text
37   this->m_TextBuffer[ 0 ] = '\0';
38   this->m_TextActor = vtkSmartPointer< vtkTextActor >::New( );
39   this->m_TextActor->SetTextScaleModeToNone( );
40   vtkTextProperty* textprop = this->m_TextActor->GetTextProperty( );
41   textprop->SetColor( 1, 1, 0 );
42   textprop->SetFontFamilyToCourier( );
43   textprop->SetFontSize( 18 );
44   textprop->BoldOff( );
45   textprop->ItalicOff( );
46   textprop->ShadowOff( );
47   textprop->SetJustificationToLeft( );
48   textprop->SetVerticalJustificationToBottom( );
49   vtkCoordinate* coord = this->m_TextActor->GetPositionCoordinate( );
50   coord->SetCoordinateSystemToNormalizedViewport( );
51   coord->SetValue( 0.01, 0.05 );
52
53   // Configure style
54   vtkSmartPointer< TStyle > st = vtkSmartPointer< TStyle >::New( );
55   st->SetAssociatedObject( this );
56   st->AddMouseMoveCommand( Self::_MouseMoveCommand, this );
57   st->AddMouseClickCommand( Self::_MouseClickCommand, this );
58   st->AddMouseWheelCommand( Self::_MouseWheelCommand, this );
59   st->AddKeyCommand( Self::_KeyCommand, this );
60   st->AddEnterCommand( Self::_EnterCommand, this );
61   st->AddLeaveCommand( Self::_LeaveCommand, this );
62   this->m_Style = st;
63 }
64
65 // -------------------------------------------------------------------------
66 void cpExtensions::Visualization::ImageSliceActors::
67 SetInputConnection( vtkAlgorithmOutput* aout, int orientation )
68 {
69   if( aout == NULL )
70     return;
71   this->m_Mapper->SetInputConnection( aout );
72   this->_ConfigureInput( orientation );
73 }
74
75 // -------------------------------------------------------------------------
76 void cpExtensions::Visualization::ImageSliceActors::
77 SetInputData( vtkImageData* data, int orientation )
78 {
79   if( data == NULL )
80     return;
81   this->m_Mapper->SetInputData( data );
82   this->_ConfigureInput( orientation );
83 }
84
85 // -------------------------------------------------------------------------
86 vtkImageData* cpExtensions::Visualization::ImageSliceActors::
87 GetInputData( )
88 {
89   if( this->m_Mapper.GetPointer( ) != NULL )
90     return( this->m_Mapper->GetInput( ) );
91   else
92     return( NULL );
93 }
94
95 // -------------------------------------------------------------------------
96 void cpExtensions::Visualization::ImageSliceActors::
97 AddMesh( vtkPolyData* mesh )
98 {
99   SourceActor< vtkCutter > a;
100   a.Create( );
101   a.Source->SetInputData( mesh );
102   a.Source->SetCutFunction( this->m_Mapper->GetSlicePlane( ) );
103   a.Source->SetValue( 0, 0 );
104   a.Source->GenerateTrianglesOff( );
105   a.Source->Update( );
106   a.Modified( );
107   this->m_Meshes[ mesh ] = a;
108   this->AddItem( a.Actor );
109
110   auto ren = this->m_Style->GetCurrentRenderer( );
111   if( ren != NULL )
112     if( ren->HasViewProp( this->m_Actor ) )
113       ren->AddViewProp( a.Actor );
114 }
115
116 // -------------------------------------------------------------------------
117 void cpExtensions::Visualization::ImageSliceActors::
118 AssociateSlice( Self* slice )
119 {
120   this->m_AssociatedSlices.push_back( slice );
121   this->Modified( );
122 }
123
124 // -------------------------------------------------------------------------
125 void cpExtensions::Visualization::ImageSliceActors::
126 CleanAssociatedSlices( )
127 {
128   this->m_AssociatedSlices.clear( );
129   this->Modified( );
130 }
131
132 // -------------------------------------------------------------------------
133 cpExtensions::Interaction::ImageInteractorStyle*
134 cpExtensions::Visualization::ImageSliceActors::
135 GetStyle( )
136 {
137   return( dynamic_cast< TStyle* >( this->m_Style.GetPointer( ) ) );
138 }
139
140 // -------------------------------------------------------------------------
141 void cpExtensions::Visualization::ImageSliceActors::
142 SetStyle( vtkInteractorStyle* st )
143 {
144   this->m_Style = st;
145   this->Modified( );
146 }
147
148 // -------------------------------------------------------------------------
149 void cpExtensions::Visualization::ImageSliceActors::
150 PushInto( vtkRenderer* ren )
151 {
152   this->InitTraversal( );
153   vtkProp* prop;
154   while( ( prop = this->GetNextProp( ) ) != NULL )
155     ren->AddViewProp( prop );
156 }
157
158 // -------------------------------------------------------------------------
159 void cpExtensions::Visualization::ImageSliceActors::
160 PopFrom( vtkRenderer* ren )
161 {
162   this->InitTraversal( );
163   vtkProp* prop;
164   while( ( prop = this->GetNextProp( ) ) != NULL )
165     ren->RemoveViewProp( prop );
166 }
167
168 // -------------------------------------------------------------------------
169 long cpExtensions::Visualization::ImageSliceActors::
170 GetSliceNumber( ) const
171 {
172   if( this->m_Mapper.GetPointer( ) != NULL )
173     return( this->m_Mapper->GetSliceNumber( ) );
174   else
175     return( -1 );
176 }
177
178 // -------------------------------------------------------------------------
179 void cpExtensions::Visualization::ImageSliceActors::
180 SetSliceNumber( long slice )
181 {
182   if( this->m_Mapper.GetPointer( ) == NULL )
183     return;
184
185   // Get orientation
186   int a = this->m_Mapper->GetOrientation( );
187
188   // Check extent
189   int ext[ 6 ];
190   this->m_Mapper->GetInput( )->GetExtent( ext );
191   long rs = slice;
192   rs = ( rs > ext[ a << 1 ] )? rs: ext[ a << 1 ];
193   rs = ( rs < ext[ ( a << 1 ) + 1 ] )? rs: ext[ ( a << 1 ) + 1 ];
194
195   // Update pipeline
196   this->m_Mapper->SetSliceNumber( rs );
197
198   // Update display extent (this isn't done automatically)
199   ext[ a << 1 ] = ext[ ( a << 1 ) + 1 ] = rs;
200   this->m_Actor->SetDisplayExtent( ext );
201
202   this->m_Mapper->Modified( );
203   this->m_Actor->Modified( );
204   this->_ConfigureCursor( );
205   this->Modified( );
206 }
207
208 // -------------------------------------------------------------------------
209 void cpExtensions::Visualization::ImageSliceActors::
210 ShowPixelText( double* pos )
211 {
212   if( this->m_Mapper.GetPointer( ) != NULL )
213   {
214     char axis;
215     int axId = this->m_Mapper->GetOrientation( );
216     if     ( axId == 0 ) axis = 'X';
217     else if( axId == 1 ) axis = 'Y';
218     else if( axId == 2 ) axis = 'Z';
219     long slice = this->GetSliceNumber( );
220
221     vtkImageData* image = this->m_Actor->GetInput( );
222     int ijk[ 3 ];
223     double pcoords[ 3 ];
224     image->ComputeStructuredCoordinates( pos, ijk, pcoords );
225     ijk[ axId ] = slice;
226
227     int ext[ 6 ];
228     image->GetExtent( ext );
229     if(
230       ext[ 0 ] <= ijk[ 0 ] && ijk[ 0 ] <= ext[ 1 ] &&
231       ext[ 2 ] <= ijk[ 1 ] && ijk[ 1 ] <= ext[ 3 ] &&
232       ext[ 4 ] <= ijk[ 2 ] && ijk[ 2 ] <= ext[ 5 ]
233       )
234     {
235       int nScl = image->GetNumberOfScalarComponents( );
236       std::stringstream str;
237       str
238         << "[" << ijk[ 0 ]
239         << "," << ijk[ 1 ]
240         << "," << ijk[ 2 ] << "]=(";
241       str <<
242         image->GetScalarComponentAsFloat( ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], 0 );
243       for( int n = 1; n < nScl; ++n )
244         str
245           << " "
246           << image->GetScalarComponentAsFloat(
247             ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], n
248             );
249       str << ")";
250
251 #if defined(WIN32)
252       sprintf_s(
253         this->m_TextBuffer, MAX_TEXT_BUFFER, "Axis: %c (%d)\nPixel %s",
254         axis, slice, str.str( ).c_str( )
255         );
256 #else // defined(WIN32)
257       std::sprintf(
258         this->m_TextBuffer, "Axis: %c (%ld)\nPixel %s",
259         axis, slice, str.str( ).c_str( )
260         );
261 #endif // defined(WIN32)
262     } // fi
263   }
264   else
265     this->m_TextBuffer[ 0 ] = '\0';
266   this->m_TextActor->SetInput( this->m_TextBuffer );
267   this->m_TextActor->Modified( );
268   this->Modified( );
269 }
270
271 // -------------------------------------------------------------------------
272 void cpExtensions::Visualization::ImageSliceActors::
273 GetScalarRange( double r[ 2 ] ) const
274 {
275   r[ 0 ] = this->m_ScalarRange[ 0 ];
276   r[ 1 ] = this->m_ScalarRange[ 1 ];
277 }
278
279 // -------------------------------------------------------------------------
280 void cpExtensions::Visualization::ImageSliceActors::
281 SetScalarRange( const double& a, const double& b )
282 {
283   this->m_ManualScalarRange = true;
284   this->m_ScalarRange[ 0 ] = a;
285   this->m_ScalarRange[ 1 ] = b;
286   this->SetWindowLevel( 1, 0.5 );
287 }
288
289 // -------------------------------------------------------------------------
290 void cpExtensions::Visualization::ImageSliceActors::
291 UnsetScalarRange( )
292 {
293   auto image = this->m_Actor->GetInput( );
294   if( image != NULL )
295   {
296     double r[ 2 ];
297     image->GetScalarRange( r );
298     this->SetScalarRange( r[ 0 ], r[ 1 ] );
299
300   } // fi
301   this->m_ManualScalarRange = false;
302 }
303
304 // -------------------------------------------------------------------------
305 void cpExtensions::Visualization::ImageSliceActors::
306 SetWindowLevel( const double& w, const double& l )
307 {
308   static const double _0 = double( 0 );
309   static const double _1 = double( 1 );
310
311   double rw = ( w < _0 )? _0: ( ( w > _1 )? _1: w );
312   double rl = ( l < _0 )? _0: ( ( l > _1 )? _1: l );
313
314   double d = this->m_ScalarRange[ 1 ] - this->m_ScalarRange[ 0 ];
315   rw *= d;
316   rl *= d;
317   rl += this->m_ScalarRange[ 0 ];
318
319   if( this->m_Actor.GetPointer( ) != NULL )
320   {
321     this->m_Actor->GetProperty( )->SetColorWindow( rw );
322     this->m_Actor->GetProperty( )->SetColorLevel( rl );
323     this->Modified( );
324
325   } // fi
326 }
327
328 // -------------------------------------------------------------------------
329 double cpExtensions::Visualization::ImageSliceActors::
330 GetWindow( ) const
331 {
332   if( this->m_Actor.GetPointer( ) != NULL )
333     return( this->m_Actor->GetProperty( )->GetColorWindow( ) );
334   else
335     return( double( 0 ) );
336 }
337
338 // -------------------------------------------------------------------------
339 double cpExtensions::Visualization::ImageSliceActors::
340 GetLevel( ) const
341 {
342   if( this->m_Actor.GetPointer( ) != NULL )
343     return( this->m_Actor->GetProperty( )->GetColorLevel( ) );
344   else
345     return( double( 0 ) );
346 }
347
348 // -------------------------------------------------------------------------
349 void cpExtensions::Visualization::ImageSliceActors::
350 Render( )
351 {
352   auto ren = this->m_Style->GetCurrentRenderer( );
353   if( ren == NULL )
354     return;
355   auto win = ren->GetRenderWindow( );
356   if( win == NULL )
357     return;
358   win->Render( );
359 }
360
361 // -------------------------------------------------------------------------
362 cpExtensions::Visualization::ImageSliceActors::
363 ImageSliceActors( )
364   : Superclass( ),
365     m_ManualScalarRange( false )
366 {
367   this->Clear( );
368 }
369
370 // -------------------------------------------------------------------------
371 cpExtensions::Visualization::ImageSliceActors::
372 ~ImageSliceActors( )
373 {
374 }
375
376 // -------------------------------------------------------------------------
377 void cpExtensions::Visualization::ImageSliceActors::
378 _ConfigureInput( int orientation )
379 {
380   // Prepare main image
381   this->m_Mapper->SetOrientation( orientation );
382   this->m_Mapper->Update( );
383   this->m_Actor->GetProperty( )->SetOpacity( 0.8 );
384   this->m_Actor->Modified( );
385   auto st = this->GetStyle( );
386   if( st != NULL )
387     st->AssociateImageActor( this->m_Actor );
388   this->AddItem( this->m_Actor );
389
390   // Prepare main cursor
391   this->_ConfigureCursor( );
392   this->AddItem( this->m_Cursor.Actor );
393
394   // Prepare window/level
395   if( !( this->m_ManualScalarRange ) )
396     this->UnsetScalarRange( );
397
398   // Add all other actors
399   this->AddItem( this->m_TextActor );
400
401   // Put it in the first slice
402   auto image = this->m_Mapper->GetInput( );
403   int ext[ 6 ];
404   image->GetExtent( ext );
405   this->SetSliceNumber( ext[ orientation << 1 ] );
406
407   /*
408     if( this->m_Style.GetPointer( ) != NULL )
409     this->AddItem( this->m_Actor );
410
411     this->SetSliceNumber( this->GetSliceNumberMinValue( ) );
412     this->ResetCursor( );
413     this->Modified( );
414
415     // Reset cursors
416     this->ResetCursor( );
417     this->ResetAxesCursor( );
418
419     // Update window/level ranges
420     vtkImageData* data = this->GetInputImage( );
421     if( data != NULL )
422     {
423     double r[ 2 ];
424     data->GetScalarRange( r );
425     this->m_WLRange[ 0 ] = double( 0 );
426     this->m_WLRange[ 1 ] = r[ 1 ] - r[ 0 ];
427     this->m_WLRange[ 2 ] = r[ 0 ];
428     this->m_WLRange[ 3 ] = r[ 1 ];
429     this->ResetWindowLevel( );
430
431     // Configure blender
432     this->m_BlenderBase = vtkSmartPointer< vtkImageData >::New( );
433     this->m_BlenderBase->ShallowCopy( data );
434     this->m_BlenderBase->AllocateScalars( VTK_UNSIGNED_CHAR, 1 );
435     std::memset(
436     this->m_BlenderBase->GetScalarPointer( ), 0,
437     this->m_BlenderBase->GetActualMemorySize( )
438     );
439     this->m_Blender->AddInputData( this->m_BlenderBase );
440
441     } // fi
442   */
443 }
444
445 // -------------------------------------------------------------------------
446 void cpExtensions::Visualization::ImageSliceActors::
447 _ConfigureCursor( )
448 {
449   int a = this->m_Mapper->GetOrientation( );
450   double bounds[ 6 ];
451   this->m_Actor->GetBounds( bounds );
452   bounds[   a << 1       ] += 1e-5;
453   bounds[ ( a << 1 ) + 1 ] += 1e-5;
454
455   this->m_Cursor.Source->SetModelBounds( bounds );
456   this->m_Cursor.Source->AllOn( );
457   this->m_Cursor.Actor->GetProperty( )->SetOpacity( 1 );
458   this->m_Cursor.Actor->GetProperty( )->SetLineWidth( 3 );
459   this->m_Cursor.Modified( );
460 }
461
462 // -------------------------------------------------------------------------
463 void cpExtensions::Visualization::ImageSliceActors::
464 _MouseMoveCommand(
465   void* data,
466   const TStyle::ButtonID& btn,
467   int* idx, double* pos,
468   bool alt, bool ctr, bool sft
469   )
470 {
471   ImageSliceActors* self = reinterpret_cast< ImageSliceActors* >( data );
472   if( self == NULL )
473     return;
474
475   if( btn == TStyle::ButtonID_None )
476   {
477     self->ShowPixelText( pos );
478     self->m_Cursor.Source->SetFocalPoint( pos );
479     self->m_Cursor.Source->Modified( );
480     self->m_Cursor.Modified( );
481     self->Render( );
482   }
483   else if( btn == TStyle::ButtonID_Right )
484   {
485     if( !alt && !ctr && sft )
486     {
487       int a0 = self->m_Mapper->GetOrientation( );
488       int a1 = ( a0 + 1 ) % 3;
489       int a2 = ( a0 + 2 ) % 3;
490       double dx = pos[ a1 ] - self->m_StartMouseEvent[ a1 ];
491       double dy = pos[ a2 ] - self->m_StartMouseEvent[ a2 ];
492       double bounds[ 6 ];
493       self->m_Actor->GetBounds( bounds );
494       dx /= bounds[ ( a1 << 1 ) + 1 ] - bounds[ a1 << 1 ];
495       dy /= bounds[ ( a2 << 1 ) + 1 ] - bounds[ a2 << 1 ];
496       double w = self->m_StartWindow + dx;
497       double l = self->m_StartLevel + dy;
498
499       self->SetWindowLevel( w, l );
500       self->Render( );
501       for(
502         auto aIt = self->m_AssociatedSlices.begin( );
503         aIt != self->m_AssociatedSlices.end( );
504         ++aIt
505         )
506       {
507         ( *aIt )->SetWindowLevel( w, l );
508         ( *aIt )->Render( );
509
510       } // rof
511
512     } // fi
513
514   } // fi
515 }
516
517 // -------------------------------------------------------------------------
518 void cpExtensions::Visualization::ImageSliceActors::
519 _MouseClickCommand(
520   void* data,
521   const TStyle::ButtonID& btn,
522   int* idx, double* pos,
523   bool alt, bool ctr, bool sft
524   )
525 {
526   ImageSliceActors* self = reinterpret_cast< ImageSliceActors* >( data );
527   if( self == NULL )
528     return;
529
530   self->m_StartMouseEvent[ 0 ] = pos[ 0 ];
531   self->m_StartMouseEvent[ 1 ] = pos[ 1 ];
532   self->m_StartMouseEvent[ 2 ] = pos[ 2 ];
533
534   if( btn == TStyle::ButtonID_Right )
535   {
536     if( !alt && !ctr && sft )
537     {
538       double r[ 2 ];
539       self->GetScalarRange( r );
540       double d = r[ 1 ] - r[ 0 ];
541       self->m_StartWindow = self->GetWindow( ) / d;
542       self->m_StartLevel = ( self->GetLevel( ) - r[ 0 ] ) / d;
543
544     } // fi
545
546   } // fi
547 }
548
549 // -------------------------------------------------------------------------
550 void cpExtensions::Visualization::ImageSliceActors::
551 _MouseWheelCommand(
552   void* data,
553   const int& dir, bool alt, bool ctr, bool sft
554   )
555 {
556   ImageSliceActors* self = reinterpret_cast< ImageSliceActors* >( data );
557   if( self == NULL )
558     return;
559   auto ren = self->m_Style->GetCurrentRenderer( );
560   if( ren == NULL )
561     return;
562   auto cam = ren->GetActiveCamera( );
563   if( cam == NULL )
564     return;
565   auto win = ren->GetRenderWindow( );
566   if( win == NULL )
567     return;
568
569   // Get previous values
570   int a = self->m_Mapper->GetOrientation( );
571   double bounds[ 6 ];
572   self->m_Actor->GetBounds( bounds );
573   double prev_pos = bounds[ a << 1 ];
574
575   // Move slice
576   long slice = self->GetSliceNumber( ) + dir * ( ( sft )? 10: 1 );
577   self->SetSliceNumber( slice );
578   self->m_Actor->GetBounds( bounds );
579
580   // Reset camera
581   double cam_pos[ 3 ];
582   cam->GetPosition( cam_pos );
583   cam_pos[ a ] += bounds[ a << 1 ] - prev_pos;
584   cam->SetPosition( cam_pos );
585
586   // Update text
587   self->ShowPixelText( self->m_Cursor.Source->GetFocalPoint( ) );
588
589   // Update all
590   win->Render( );
591   for(
592     auto aIt = self->m_AssociatedSlices.begin( );
593     aIt != self->m_AssociatedSlices.end( );
594     ++aIt
595     )
596   {
597     if( ( *aIt )->m_Mapper->GetOrientation( ) == a )
598     {
599       ( *aIt )->SetSliceNumber( slice );
600       ( *aIt )->Render( );
601
602     } // fi
603
604   } // fi
605 }
606
607 // -------------------------------------------------------------------------
608 void cpExtensions::Visualization::ImageSliceActors::
609 _KeyCommand(
610   void* data,
611   const char& key
612   )
613 {
614 }
615
616 // -------------------------------------------------------------------------
617 void cpExtensions::Visualization::ImageSliceActors::
618 _EnterCommand( void* data )
619 {
620 }
621
622 // -------------------------------------------------------------------------
623 void cpExtensions::Visualization::ImageSliceActors::
624 _LeaveCommand( void* data )
625 {
626 }
627
628 // eof - $RCSfile$