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