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