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