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