]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageSliceActors.cxx
Merge branch 'master' of ssh://git.creatis.insa-lyon.fr/cpPlugins
[cpPlugins.git] / lib / cpExtensions / Visualization / ImageSliceActors.cxx
1 #include <cpExtensions/Visualization/ImageSliceActors.h>
2
3 #include <cmath>
4 #include <sstream>
5
6 #include <vtkAlgorithmOutput.h>
7 #include <vtkCamera.h>
8 #include <vtkCellArray.h>
9 #include <vtkImageData.h>
10 #include <vtkInformation.h>
11 #include <vtkPlane.h>
12 #include <vtkPoints.h>
13 #include <vtkProperty.h>
14 #include <vtkRenderer.h>
15 #include <vtkRendererCollection.h>
16 #include <vtkRenderWindow.h>
17 #include <vtkRenderWindowInteractor.h>
18 #include <vtkStreamingDemandDrivenPipeline.h>
19 #include <vtkTextProperty.h>
20 #include <vtkWindowLevelLookupTable.h>
21
22 // -------------------------------------------------------------------------
23 cpExtensions::Visualization::ImageSliceActors*
24 cpExtensions::Visualization::ImageSliceActors::
25 New( )
26 {
27   return( new Self( ) );
28 }
29
30 // -------------------------------------------------------------------------
31 void cpExtensions::Visualization::ImageSliceActors::
32 AddInputConnection( vtkAlgorithmOutput* aout, int axis, LUTType lut )
33 {
34   vtkImageData* data = dynamic_cast< vtkImageData* >(
35     aout->GetProducer( )->GetOutputDataObject( aout->GetIndex( ) )
36     );
37   if( data == NULL )
38     return;
39
40   vtkImageMapToColors* new_map =
41     dynamic_cast< vtkImageMapToColors* >( aout->GetProducer( ) );
42   if( new_map == NULL )
43   {
44     // Configure LUT
45     this->_ConfigureNewLUT( data, lut );
46     new_map = *( this->ImageMaps.rbegin( ) );
47     if( new_map != NULL )
48     {
49       new_map->SetInputConnection( aout );
50       new_map->Update( );
51
52     } // fi
53   }
54   else
55     this->ImageMaps.push_back( new_map );
56   
57   // Create mapper and actors
58   vtkSmartPointer< vtkImageSliceMapper > mapper =
59     vtkSmartPointer< vtkImageSliceMapper >::New( );
60   if( new_map != NULL )
61     mapper->SetInputConnection( new_map->GetOutputPort( ) );
62   else
63     mapper->SetInputConnection( aout );
64   this->SliceMappers.push_back( mapper );
65   this->_ConfigureNewInput( axis );
66 }
67
68 // -------------------------------------------------------------------------
69 void cpExtensions::Visualization::ImageSliceActors::
70 AddInputData( vtkImageData* data, int axis, LUTType lut )
71 {
72   // Configure LUT
73   this->_ConfigureNewLUT( data, lut );
74   vtkImageMapToColors* new_map = *( this->ImageMaps.rbegin( ) );
75   if( new_map != NULL )
76   {
77     new_map->SetInputData( data );
78     new_map->Update( );
79
80   } // fi
81
82   // Create mapper and actors
83   vtkSmartPointer< vtkImageSliceMapper > mapper =
84     vtkSmartPointer< vtkImageSliceMapper >::New( );
85   if( new_map != NULL )
86     mapper->SetInputConnection( new_map->GetOutputPort( ) );
87   else
88     mapper->SetInputData( data );
89   this->SliceMappers.push_back( mapper );
90   this->_ConfigureNewInput( axis );
91 }
92
93 // -------------------------------------------------------------------------
94 void cpExtensions::Visualization::ImageSliceActors::
95 Clear( )
96 {
97   // Unbind from container
98   this->RemoveAllItems( );
99
100   // Delete all images
101   this->ImageMaps.clear( );
102   this->SliceMappers.clear( );
103   this->ImageActors.clear( );
104   this->AssociatedActors.clear( );
105
106   // Reconfigure unique objects
107   this->Cursor        = vtkSmartPointer< vtkPolyData >::New( );
108   this->CursorMapper  = vtkSmartPointer< vtkPolyDataMapper >::New( );
109   this->CursorActor   = vtkSmartPointer< vtkActor >::New( );
110   this->PlaneFunction = vtkSmartPointer< vtkPlane >::New( );
111   this->PlaneSource   = vtkSmartPointer< vtkPolyData >::New( );
112   this->PlaneMapper   = vtkSmartPointer< vtkPolyDataMapper >::New( );
113   this->TextActor     = vtkSmartPointer< vtkTextActor >::New( );
114   this->PlaneActor    = vtkSmartPointer< vtkActor >::New( );
115   this->TextBuffer[ 0 ] = '\0';
116
117   // Unique objects configuration
118   vtkSmartPointer< vtkPoints > cursor_points =
119     vtkSmartPointer< vtkPoints >::New( );
120   vtkSmartPointer< vtkCellArray > cursor_lines =
121     vtkSmartPointer< vtkCellArray >::New( );
122   cursor_points->InsertNextPoint( 0, 0, 0 );
123   cursor_points->InsertNextPoint( 0, 0, 0 );
124   cursor_points->InsertNextPoint( 0, 0, 0 );
125   cursor_points->InsertNextPoint( 0, 0, 0 );
126   cursor_points->InsertNextPoint( 0, 0, 0 );
127   cursor_points->InsertNextPoint( 0, 0, 0 );
128   cursor_points->InsertNextPoint( 0, 0, 0 );
129   cursor_points->InsertNextPoint( 0, 0, 0 );
130   cursor_lines->InsertNextCell( 2 );
131   cursor_lines->InsertCellPoint( 0 );
132   cursor_lines->InsertCellPoint( 1 );
133   cursor_lines->InsertNextCell( 2 );
134   cursor_lines->InsertCellPoint( 2 );
135   cursor_lines->InsertCellPoint( 3 );
136   cursor_lines->InsertNextCell( 2 );
137   cursor_lines->InsertCellPoint( 4 );
138   cursor_lines->InsertCellPoint( 5 );
139   cursor_lines->InsertNextCell( 2 );
140   cursor_lines->InsertCellPoint( 6 );
141   cursor_lines->InsertCellPoint( 7 );
142   this->Cursor->SetPoints( cursor_points );
143   this->Cursor->SetLines( cursor_lines );
144   this->CursorMapper->SetInputData( this->Cursor );
145   this->CursorActor->SetMapper( this->CursorMapper );
146
147   vtkSmartPointer< vtkPoints > plane_points =
148     vtkSmartPointer< vtkPoints >::New( );
149   vtkSmartPointer< vtkCellArray > plane_lines =
150     vtkSmartPointer< vtkCellArray >::New( );
151
152   plane_points->InsertNextPoint( 0, 0, 0 );
153   plane_points->InsertNextPoint( 0, 1, 0 );
154   plane_points->InsertNextPoint( 1, 1, 0 );
155   plane_points->InsertNextPoint( 1, 0, 0 );
156   plane_lines->InsertNextCell( 5 );
157   plane_lines->InsertCellPoint( 0 );
158   plane_lines->InsertCellPoint( 1 );
159   plane_lines->InsertCellPoint( 2 );
160   plane_lines->InsertCellPoint( 3 );
161   plane_lines->InsertCellPoint( 0 );
162   this->PlaneSource->SetPoints( plane_points );
163   this->PlaneSource->SetLines( plane_lines );
164
165   this->PlaneMapper->SetInputData( this->PlaneSource );
166   this->PlaneActor->SetMapper( this->PlaneMapper );
167
168   this->TextActor->SetTextScaleModeToNone( );
169   vtkTextProperty* textprop = this->TextActor->GetTextProperty( );
170   textprop->SetColor( 1, 1, 1 );
171   textprop->SetFontFamilyToCourier( );
172   textprop->SetFontSize( 18 );
173   textprop->BoldOff( );
174   textprop->ItalicOff( );
175   textprop->ShadowOff( );
176   textprop->SetJustificationToLeft( );
177   textprop->SetVerticalJustificationToBottom( );
178   vtkCoordinate* coord = this->TextActor->GetPositionCoordinate( );
179   coord->SetCoordinateSystemToNormalizedViewport( );
180   coord->SetValue( 0.01, 0.01 );
181 }
182
183 // -------------------------------------------------------------------------
184 vtkInteractorStyle* cpExtensions::Visualization::ImageSliceActors::
185 GetStyle( )
186 {
187   return( this->Style.GetPointer( ) );
188 }
189
190 // -------------------------------------------------------------------------
191 const vtkInteractorStyle* cpExtensions::Visualization::ImageSliceActors::
192 GetStyle( ) const
193 {
194   return( this->Style.GetPointer( ) );
195 }
196
197 // -------------------------------------------------------------------------
198 void cpExtensions::Visualization::ImageSliceActors::
199 PushActorsInto( vtkRenderWindow* window, bool force_style )
200 {
201   vtkRenderWindowInteractor* rwi = window->GetInteractor( );
202   vtkRenderer* renderer = window->GetRenderers( )->GetFirstRenderer( );
203
204   // Update style
205   if( rwi != NULL && force_style )
206   {
207     if( rwi->GetInteractorStyle( ) != this->Style.GetPointer( ) )
208     {
209       rwi->SetInteractorStyle( this->Style );
210
211     } // fi
212
213   } // fi
214
215   if( renderer != NULL )
216   {
217     // Update actors
218     unsigned int N = this->GetNumberOfImageActors( );
219     for( unsigned int n = 0; n < N; ++n )
220       renderer->AddActor( this->GetImageActor( n ) );
221     renderer->AddActor( this->CursorActor );
222     renderer->AddActor( this->PlaneActor );
223     renderer->AddActor( this->TextActor );
224     renderer->Modified( );
225
226     // Configure camera
227     vtkCamera* camera = renderer->GetActiveCamera( );
228     if( camera == NULL )
229       return;
230
231     // Parallel projections are better when displaying 2D images
232     if( force_style )
233     {
234       int axis = this->GetAxis( );
235       camera->ParallelProjectionOn( );
236       camera->SetFocalPoint( double( 0 ), double( 0 ), double( 0 ) );
237       if( axis == 0 )
238       {
239         camera->SetPosition( double( 1 ), double( 0 ), double( 0 ) );
240         camera->SetViewUp  ( double( 0 ), double( 1 ), double( 0 ) );
241       }
242       else if( axis == 1 )
243       {
244         camera->SetPosition( double( 0 ), double( 1 ), double(  0 ) );
245         camera->SetViewUp  ( double( 0 ), double( 0 ), double( -1 ) );
246       }
247       else // if( axis == 2 )
248       {
249         camera->SetPosition( double( 0 ), double( 0 ), double( 1 ) );
250         camera->SetViewUp  ( double( 0 ), double( 1 ), double( 0 ) );
251
252       } // fi
253
254     } // fi
255     renderer->ResetCamera( );
256     rwi->Render( );
257
258   } // fi
259 }
260
261 // -------------------------------------------------------------------------
262 void cpExtensions::Visualization::ImageSliceActors::
263 PopActorsFrom( vtkRenderWindow* window )
264 {
265   vtkRenderWindowInteractor* rwi = window->GetInteractor( );
266   vtkRenderer* renderer = window->GetRenderers( )->GetFirstRenderer( );
267
268   if( renderer != NULL )
269   {
270     // Update actors
271     unsigned int N = this->GetNumberOfImageActors( );
272     for( unsigned int n = 0; n < N; ++n )
273       renderer->RemoveActor( this->GetImageActor( n ) );
274     renderer->RemoveActor( this->CursorActor );
275     renderer->RemoveActor( this->PlaneActor );
276     renderer->RemoveActor( this->TextActor );
277     renderer->Modified( );
278
279   } // fi
280 }
281
282 // -------------------------------------------------------------------------
283 unsigned int cpExtensions::Visualization::ImageSliceActors::
284 GetNumberOfImageActors( ) const
285 {
286   return( this->ImageActors.size( ) );
287 }
288
289 // -------------------------------------------------------------------------
290 vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
291 GetImageActor( unsigned int id )
292 {
293   if( id < this->ImageActors.size( ) )
294     return( this->ImageActors[ id ] );
295   else
296     return( NULL );
297 }
298
299 // -------------------------------------------------------------------------
300 const vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
301 GetImageActor( unsigned int id ) const
302 {
303   if( id < this->ImageActors.size( ) )
304     return( this->ImageActors[ id ] );
305   else
306     return( NULL );
307 }
308
309 // -------------------------------------------------------------------------
310 vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
311 GetTextActor( )
312 {
313   return( this->TextActor );
314 }
315
316 // -------------------------------------------------------------------------
317 const vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
318 GetTextActor( ) const
319 {
320   return( this->TextActor );
321 }
322
323 // -------------------------------------------------------------------------
324 vtkActor* cpExtensions::Visualization::ImageSliceActors::
325 GetPlaneActor( )
326 {
327   return( this->PlaneActor );
328 }
329
330 // -------------------------------------------------------------------------
331 const vtkActor* cpExtensions::Visualization::ImageSliceActors::
332 GetPlaneActor( ) const
333 {
334   return( this->PlaneActor );
335 }
336
337 // -------------------------------------------------------------------------
338 vtkPlane* cpExtensions::Visualization::ImageSliceActors::
339 GetPlaneFunction( )
340 {
341   return( this->PlaneFunction );
342 }
343
344 // -------------------------------------------------------------------------
345 const vtkPlane* cpExtensions::Visualization::ImageSliceActors::
346 GetPlaneFunction( ) const
347 {
348   return( this->PlaneFunction );
349 }
350
351 // -------------------------------------------------------------------------
352 void cpExtensions::Visualization::ImageSliceActors::
353 AddActor( vtkAlgorithm* algorithm, vtkActor* actor )
354 {
355   this->AssociatedActors.push_back( TAssociatedActor( algorithm, actor ) );
356   this->AddItem( actor );
357 }
358
359 // -------------------------------------------------------------------------
360 void cpExtensions::Visualization::ImageSliceActors::
361 AddActor( vtkActor* actor )
362 {
363   this->AddActor( NULL, actor );
364 }
365
366 // -------------------------------------------------------------------------
367 void cpExtensions::Visualization::ImageSliceActors::
368 SetInterpolate( bool v )
369 {
370   if( this->Interpolate != v )
371   {
372     for( unsigned int i = 0; i < this->ImageActors.size( ); ++i )
373       this->ImageActors[ i ]->SetInterpolate( v );
374     this->Interpolate = v;
375     this->Modified( );
376
377   } // fi
378 }
379
380 // -------------------------------------------------------------------------
381 void cpExtensions::Visualization::ImageSliceActors::
382 InterpolateOn( )
383 {
384   this->SetInterpolate( true );
385 }
386
387 // -------------------------------------------------------------------------
388 void cpExtensions::Visualization::ImageSliceActors::
389 InterpolateOff( )
390 {
391   this->SetInterpolate( false );
392 }
393
394 // -------------------------------------------------------------------------
395 double* cpExtensions::Visualization::ImageSliceActors::
396 GetDisplayBounds( ) const
397 {
398   if( this->ImageActors.size( ) > 0 )
399     return( this->ImageActors[ 0 ]->GetDisplayBounds( ) );
400   else
401     return( NULL );
402 }
403
404 // -------------------------------------------------------------------------
405 void cpExtensions::Visualization::ImageSliceActors::
406 GetDisplayBounds( double bounds[ 6 ] ) const
407 {
408   if( this->ImageActors.size( ) == 0 )
409   {
410     bounds[ 0 ] = bounds[ 2 ] = bounds[ 4 ] = double( -1 );
411     bounds[ 1 ] = bounds[ 3 ] = bounds[ 5 ] = double( -1 );
412   }
413   else
414     this->ImageActors[ 0 ]->GetDisplayBounds( bounds );
415 }
416
417 // -------------------------------------------------------------------------
418 void cpExtensions::Visualization::ImageSliceActors::
419 ResetCursor( )
420 {
421   vtkPoints* points = this->Cursor->GetPoints( );
422   points->SetPoint( 0, 0, 0, 0 );
423   points->SetPoint( 1, 0, 0, 0 );
424   points->SetPoint( 2, 0, 0, 0 );
425   points->SetPoint( 3, 0, 0, 0 );
426   points->SetPoint( 4, 0, 0, 0 );
427   points->SetPoint( 5, 0, 0, 0 );
428   points->SetPoint( 6, 0, 0, 0 );
429   points->SetPoint( 7, 0, 0, 0 );
430   this->Cursor->Modified( );
431   this->CursorMapper->Modified( );
432   this->CursorActor->Modified( );
433 }
434
435 // -------------------------------------------------------------------------
436 void cpExtensions::Visualization::ImageSliceActors::
437 SetCursor( double pos[ 3 ] )
438 {
439   if( this->SliceMappers.size( ) == 0 )
440     return;
441
442   // Get ordered axes
443   int a0 = this->GetAxis( );
444   int a1 = ( a0 + 1 ) % 3;
445   int a2 = ( a0 + 2 ) % 3;
446   int ma0 = a0 << 1;
447   int ma1 = a1 << 1;
448   int ma2 = a2 << 1;
449
450   double bounds[ 6 ];
451   this->SliceMappers[ 0 ]->GetInput( )->GetBounds( bounds );
452
453   double
454     p0[ 3 ], p1[ 3 ], p2[ 3 ], p3[ 3 ],
455     p4[ 3 ], p5[ 3 ], p6[ 3 ], p7[ 3 ];
456
457   p0[ a2 ] = p1[ a2 ] = p4[ a2 ] = p5[ a2 ] = pos[ a2 ];
458   p2[ a1 ] = p3[ a1 ] = p6[ a1 ] = p7[ a1 ] = pos[ a1 ];
459   p0[ a0 ] = p1[ a0 ] = p2[ a0 ] = p3[ a0 ] = bounds[ ma0 ];
460   p4[ a0 ] = p5[ a0 ] = p6[ a0 ] = p7[ a0 ] = bounds[ ma0 + 1 ];
461   p0[ a1 ] = p4[ a1 ] = bounds[ ma1 ];
462   p1[ a1 ] = p5[ a1 ] = bounds[ ma1 + 1 ];
463   p2[ a2 ] = p6[ a2 ] = bounds[ ma2 ];
464   p3[ a2 ] = p7[ a2 ] = bounds[ ma2 + 1 ];
465
466   vtkPoints* points = this->Cursor->GetPoints( );
467   points->SetPoint( 0, p0 );
468   points->SetPoint( 1, p1 );
469   points->SetPoint( 2, p2 );
470   points->SetPoint( 3, p3 );
471   points->SetPoint( 4, p4 );
472   points->SetPoint( 5, p5 );
473   points->SetPoint( 6, p6 );
474   points->SetPoint( 7, p7 );
475   this->Cursor->Modified( );
476   this->CursorMapper->Modified( );
477   this->CursorActor->Modified( );
478 }
479
480 // -------------------------------------------------------------------------
481 vtkImageMapToColors* cpExtensions::Visualization::ImageSliceActors::
482 GetImageMap( unsigned int id )
483 {
484   if( id < this->ImageMaps.size( ) )
485     return( this->ImageMaps[ id ].GetPointer( ) );
486   else
487     return( NULL );
488 }
489
490 // -------------------------------------------------------------------------
491 const vtkImageMapToColors* cpExtensions::Visualization::ImageSliceActors::
492 GetImageMap( unsigned int id ) const
493 {
494   if( id < this->ImageMaps.size( ) )
495     return( this->ImageMaps[ id ].GetPointer( ) );
496   else
497     return( NULL );
498 }
499
500 // -------------------------------------------------------------------------
501 double cpExtensions::Visualization::ImageSliceActors::
502 GetWindow( unsigned int id ) const
503 {
504   if( this->ImageMaps[ id ].GetPointer( ) != NULL )
505   {
506     vtkWindowLevelLookupTable* lut =
507       dynamic_cast< vtkWindowLevelLookupTable* >(
508         this->ImageMaps[ id ]->GetLookupTable( )
509         );
510     if( lut != NULL )
511       return( lut->GetWindow( ) );
512     else
513       return( double( 0 ) );
514   }
515   else
516     return( double( 0 ) );
517 }
518
519 // -------------------------------------------------------------------------
520 double cpExtensions::Visualization::ImageSliceActors::
521 GetLevel( unsigned int id ) const
522 {
523   if( this->ImageMaps[ id ].GetPointer( ) != NULL )
524   {
525     vtkWindowLevelLookupTable* lut =
526       dynamic_cast< vtkWindowLevelLookupTable* >(
527         this->ImageMaps[ id ]->GetLookupTable( )
528         );
529     if( lut != NULL )
530       return( lut->GetLevel( ) );
531     else
532       return( double( 0 ) );
533   }
534   else
535     return( double( 0 ) );
536 }
537
538 // -------------------------------------------------------------------------
539 void cpExtensions::Visualization::ImageSliceActors::
540 SetWindow( unsigned int id, double w )
541 {
542   if( this->ImageMaps[ id ].GetPointer( ) != NULL )
543   {
544     vtkWindowLevelLookupTable* lut =
545       dynamic_cast< vtkWindowLevelLookupTable* >(
546         this->ImageMaps[ id ]->GetLookupTable( )
547         );
548     if( lut != NULL )
549     {
550       lut->SetWindow( w );
551       lut->Build( );
552       this->ImageMaps[ id ]->Modified( );
553       this->Modified( );
554
555     } // fi
556
557   } // fi
558 }
559
560 // -------------------------------------------------------------------------
561 void cpExtensions::Visualization::ImageSliceActors::
562 SetLevel( unsigned int id, double l )
563 {
564   if( this->ImageMaps[ id ].GetPointer( ) != NULL )
565   {
566     vtkWindowLevelLookupTable* lut =
567       dynamic_cast< vtkWindowLevelLookupTable* >(
568         this->ImageMaps[ id ]->GetLookupTable( )
569         );
570     if( lut != NULL )
571     {
572       lut->SetLevel( l );
573       lut->Build( );
574       this->ImageMaps[ id ]->Modified( );
575       this->Modified( );
576
577     } // fi
578
579   } // fi
580 }
581
582 // -------------------------------------------------------------------------
583 void cpExtensions::Visualization::ImageSliceActors::
584 SetWindowLevel( unsigned int id, double w, double l )
585 {
586   if( this->ImageMaps[ id ].GetPointer( ) != NULL )
587   {
588     vtkWindowLevelLookupTable* lut =
589       dynamic_cast< vtkWindowLevelLookupTable* >(
590         this->ImageMaps[ id ]->GetLookupTable( )
591         );
592     if( lut != NULL )
593     {
594       lut->SetWindow( w );
595       lut->SetLevel( l );
596       lut->Build( );
597       this->ImageMaps[ id ]->Modified( );
598       this->UpdateText( w, l );
599       this->Modified( );
600
601     } // fi
602
603   } // fi
604 }
605
606 // -------------------------------------------------------------------------
607 void cpExtensions::Visualization::ImageSliceActors::
608 ResetWindowLevel( unsigned int id )
609 {
610 }
611
612 // -------------------------------------------------------------------------
613 int cpExtensions::Visualization::ImageSliceActors::
614 GetAxis( ) const
615 {
616   if( this->SliceMappers.size( ) > 0 )
617     return( this->SliceMappers[ 0 ]->GetOrientation( ) );
618   else
619     return( -1 );
620 }
621
622 // -------------------------------------------------------------------------
623 int cpExtensions::Visualization::ImageSliceActors::
624 GetSliceNumber( ) const
625 {
626   if( this->SliceMappers.size( ) > 0 )
627     return( this->SliceMappers[ 0 ]->GetSliceNumber( ) );
628   else
629     return( -1 );
630 }
631
632 // -------------------------------------------------------------------------
633 int cpExtensions::Visualization::ImageSliceActors::
634 GetSliceNumberMinValue( ) const
635 {
636   if( this->SliceMappers.size( ) > 0 )
637     return( this->SliceMappers[ 0 ]->GetSliceNumberMinValue( ) );
638   else
639     return( -1 );
640 }
641
642 // -------------------------------------------------------------------------
643 int cpExtensions::Visualization::ImageSliceActors::
644 GetSliceNumberMaxValue( ) const
645 {
646   if( this->SliceMappers.size( ) > 0 )
647     return( this->SliceMappers[ 0 ]->GetSliceNumberMaxValue( ) );
648   else
649     return( -1 );
650 }
651
652 // -------------------------------------------------------------------------
653 void cpExtensions::Visualization::ImageSliceActors::
654 SetSliceNumber( const int& slice )
655 {
656   unsigned int nImages = this->SliceMappers.size( );
657   if( nImages == 0 )
658     return;
659
660   // Change visualization extent
661   for( unsigned int i = 0; i < nImages; ++i )
662   {
663     this->SliceMappers[ i ]->SetSliceNumber( slice );
664     this->SliceMappers[ i ]->Modified( );
665     this->ImageActors[ i ]->Modified( );
666     this->SliceMappers[ i ]->Update( );
667
668   } // rof
669
670   // Compute plane
671   vtkAlgorithm* algo = this->SliceMappers[ 0 ]->GetInputAlgorithm( );
672   vtkInformation* info = algo->GetOutputInformation( 0 );
673   int ext[ 6 ];
674   double ori[ 3 ], spac[ 3 ], pos[ 3 ];
675   info->Get( vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT( ), ext );
676   info->Get( vtkDataObject::ORIGIN( ), ori );
677   info->Get( vtkDataObject::SPACING( ), spac );
678   this->SliceMappers[ 0 ]->GetSlicePlane( )->GetOrigin( pos );
679
680   // Prevent obscuring voxels by offsetting the plane geometry
681   double xbnds[ ] =
682     {
683       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 0 ] ) ),
684       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 1 ] ) )
685     };
686   double ybnds[ ] =
687     {
688       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 2 ] ) ),
689       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 3 ] ) )
690     };
691   double zbnds[ ] =
692     {
693       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 4 ] ) ),
694       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 5 ] ) )
695     };
696
697   if( spac[ 0 ] < double( 0 ) )
698   {
699     double t = xbnds[ 0 ];
700     xbnds[ 0 ] = xbnds[ 1 ];
701     xbnds[ 1 ] = t;
702
703   } // fi
704   if( spac[ 1 ] < double( 0 ) )
705   {
706     double t = ybnds[ 0 ];
707     ybnds[ 0 ] = ybnds[ 1 ];
708     ybnds[ 1 ] = t;
709
710   } // fi
711   if( spac[ 2 ] < double( 0 ) )
712   {
713     double t = zbnds[ 0 ];
714     zbnds[ 0 ] = zbnds[ 1 ];
715     zbnds[ 1 ] = t;
716
717   } // fi
718
719   // Plane function origin
720   this->PlaneFunction->SetOrigin( pos );
721
722   // Configure visualization and implicit plane orientation
723   int axis = this->SliceMappers[ 0 ]->GetOrientation( );
724   this->PlaneActor->GetProperty( )->SetRepresentationToWireframe( );
725   this->PlaneActor->GetProperty( )->SetLineWidth( 2 );
726   vtkPoints* plane_points = this->PlaneSource->GetPoints( );
727   if( axis == 0 ) // YZ, x-normal
728   {
729     this->PlaneFunction->SetNormal( 1, 0, 0 );
730     plane_points->SetPoint( 0, pos[ 0 ], ybnds[ 0 ], zbnds[ 0 ] );
731     plane_points->SetPoint( 1, pos[ 0 ], ybnds[ 1 ], zbnds[ 0 ] );
732     plane_points->SetPoint( 2, pos[ 0 ], ybnds[ 1 ], zbnds[ 1 ] );
733     plane_points->SetPoint( 3, pos[ 0 ], ybnds[ 0 ], zbnds[ 1 ] );
734     this->PlaneActor->GetProperty( )->SetColor( 1, 0, 0 );
735   }
736   else if( axis == 1 ) // ZX, y-normal
737   {
738     this->PlaneFunction->SetNormal( 0, 1, 0 );
739     plane_points->SetPoint( 0, xbnds[ 0 ], pos[ 1 ], zbnds[ 0 ] );
740     plane_points->SetPoint( 1, xbnds[ 0 ], pos[ 1 ], zbnds[ 1 ] );
741     plane_points->SetPoint( 2, xbnds[ 1 ], pos[ 1 ], zbnds[ 1 ] );
742     plane_points->SetPoint( 3, xbnds[ 1 ], pos[ 1 ], zbnds[ 0 ] );
743     this->PlaneActor->GetProperty( )->SetColor( 0, 1, 0 );
744   }
745   else // XY, z-normal
746   {
747     this->PlaneFunction->SetNormal( 0, 0, 1 );
748     plane_points->SetPoint( 0, xbnds[ 0 ], ybnds[ 0 ], pos[ 2 ] );
749     plane_points->SetPoint( 1, xbnds[ 1 ], ybnds[ 0 ], pos[ 2 ] );
750     plane_points->SetPoint( 2, xbnds[ 1 ], ybnds[ 1 ], pos[ 2 ] );
751     plane_points->SetPoint( 3, xbnds[ 0 ], ybnds[ 1 ], pos[ 2 ] );
752     this->PlaneActor->GetProperty( )->SetColor( 0, 0, 1 );
753
754   } // fi
755   this->PlaneFunction->Modified( );
756   this->PlaneSource->Modified( );
757   this->PlaneMapper->Modified( );
758   this->PlaneActor->Modified( );
759
760   // Prepare other actors to update
761   /* TODO
762      for( unsigned int i = 0; i < this->OtherActors.size( ); ++i )
763      {
764      if( this->OtherActors[ i ].first.GetPointer( ) != NULL )
765      {
766      this->OtherActors[ i ].first->Modified( );
767      this->OtherActors[ i ].first->Update( );
768
769      } // fi
770
771      if( this->OtherActors[ i ].second.GetPointer( ) != NULL )
772      {
773      this->OtherActors[ i ].second->GetMapper( )->Modified( );
774      this->OtherActors[ i ].second->Modified( );
775
776      } // fi
777
778      } // rof
779
780      if( this->m_UpdateCommand != NULL )
781      this->m_UpdateCommand( this->m_UpdateData );
782   */
783
784   // Update text
785   this->UpdateText( );
786 }
787
788 // -------------------------------------------------------------------------
789 void cpExtensions::Visualization::ImageSliceActors::
790 UpdateText( )
791 {
792   if( this->SliceMappers.size( ) > 0 )
793   {
794     char axis;
795     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
796     if     ( axId == 0 ) axis = 'X';
797     else if( axId == 1 ) axis = 'Y';
798     else if( axId == 2 ) axis = 'Z';
799
800     std::sprintf(
801       this->TextBuffer, "Axis: %c (%d)",
802       axis, this->SliceMappers[ 0 ]->GetSliceNumber( )
803       );
804   }
805   else
806     this->TextBuffer[ 0 ] = '\0';
807   this->TextActor->SetInput( this->TextBuffer );
808   this->TextActor->Modified( );
809   this->Modified( );
810 }
811
812 // -------------------------------------------------------------------------
813 void cpExtensions::Visualization::ImageSliceActors::
814 UpdateText( double pos[ 3 ] )
815 {
816   if( this->SliceMappers.size( ) > 0 )
817   {
818     char axis;
819     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
820     if     ( axId == 0 ) axis = 'X';
821     else if( axId == 1 ) axis = 'Y';
822     else if( axId == 2 ) axis = 'Z';
823     int slice = this->GetSliceNumber( );
824
825     vtkImageData* image;
826     if( this->ImageMaps[ 0 ] != NULL )
827       image =
828         dynamic_cast< vtkImageData* >( this->ImageMaps[ 0 ]->GetInput( ) );
829     else
830       image = this->SliceMappers[ 0 ]->GetInput( );
831
832     int ijk[ 3 ];
833     double pcoords[ 3 ];
834     image->ComputeStructuredCoordinates( pos, ijk, pcoords );
835     ijk[ axId ] = slice;
836
837     int ext[ 6 ];
838     image->GetExtent( ext );
839     if(
840       ext[ 0 ] <= ijk[ 0 ] && ijk[ 0 ] <= ext[ 1 ] &&
841       ext[ 2 ] <= ijk[ 1 ] && ijk[ 1 ] <= ext[ 3 ] &&
842       ext[ 4 ] <= ijk[ 2 ] && ijk[ 2 ] <= ext[ 5 ]
843       )
844     {
845       int nScl = image->GetNumberOfScalarComponents( );
846       std::stringstream str;
847       str
848         << "[" << ijk[ 0 ]
849         << "," << ijk[ 1 ]
850         << "," << ijk[ 2 ] << "]=(";
851       str <<
852         image->GetScalarComponentAsFloat( ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], 0 );
853       for( int n = 1; n < nScl; ++n )
854         str
855           << " "
856           << image->GetScalarComponentAsFloat(
857             ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], n
858             );
859       str << ")";
860       std::sprintf(
861         this->TextBuffer, "Axis: %c (%d) | Pixel %s",
862         axis, slice, str.str( ).c_str( )
863         );
864
865     } // fi
866   }
867   else
868     this->TextBuffer[ 0 ] = '\0';
869   this->TextActor->SetInput( this->TextBuffer );
870   this->TextActor->Modified( );
871   this->Modified( );
872 }
873
874 // -------------------------------------------------------------------------
875 void cpExtensions::Visualization::ImageSliceActors::
876 UpdateText( const double& w, const double& l )
877 {
878   if( this->SliceMappers.size( ) > 0 )
879   {
880     char axis;
881     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
882     if     ( axId == 0 ) axis = 'X';
883     else if( axId == 1 ) axis = 'Y';
884     else if( axId == 2 ) axis = 'Z';
885
886     std::sprintf(
887       this->TextBuffer, "Axis: %c (%d) | W/L (%.2f/%.2f)",
888       axis, this->SliceMappers[ 0 ]->GetSliceNumber( ), w, l
889       );
890   }
891   else
892     this->TextBuffer[ 0 ] = '\0';
893   this->TextActor->SetInput( this->TextBuffer );
894   this->TextActor->Modified( );
895   this->Modified( );
896 }
897
898 // -------------------------------------------------------------------------
899 cpExtensions::Visualization::ImageSliceActors::
900 ImageSliceActors( )
901   : Superclass( ),
902     Interpolate( false )
903 {
904   this->Clear( );
905
906   // Connect this view with a controller
907   this->Style = vtkSmartPointer< ImageInteractorStyle >::New( );
908   this->Style->AssociateView( this );
909   this->Style->SetMouseMoveCommand( Self::_MouseMoveCommand );
910   this->Style->SetMouseClickCommand( Self::_MouseClickCommand );
911   this->Style->SetMouseDoubleClickCommand( Self::_MouseDoubleClickCommand );
912   this->Style->SetMouseWheelCommand( Self::_MouseWheelCommand );
913   this->Style->SetKeyCommand( Self::_KeyCommand );
914 }
915
916 // -------------------------------------------------------------------------
917 cpExtensions::Visualization::ImageSliceActors::
918 ~ImageSliceActors( )
919 {
920 }
921
922 // -------------------------------------------------------------------------
923 void cpExtensions::Visualization::ImageSliceActors::
924 _ConfigureNewLUT( vtkImageData* data, LUTType lut_t )
925 {
926   static const double _0 = double( 0 );
927   static const double _1 = double( 1 );
928   static const double _2 = double( 2 );
929   static const double _4 = double( 4 );
930   static const double _6 = double( 6 );
931   static const double _OPACITY = double( 0.6 );
932
933   // Configure LUT
934   vtkSmartPointer< vtkImageMapToColors > new_map( NULL );
935   if( data->GetNumberOfScalarComponents( ) == 1 )
936   {
937     double range[ 2 ];
938     data->GetScalarRange( range );
939     if( lut_t == Self::LUTType_WindowLevel )
940     {
941       vtkSmartPointer< vtkWindowLevelLookupTable > lut =
942         vtkSmartPointer< vtkWindowLevelLookupTable >::New( );
943       lut->SetScaleToLinear( );
944       lut->SetTableRange( range );
945       lut->SetWindow( range[ 1 ] - range[ 0 ] );
946       lut->SetLevel( ( range[ 1 ] + range[ 0 ] ) / double( 2 ) );
947       lut->Build( );
948
949       new_map = vtkSmartPointer< vtkImageMapToColors >::New( );
950       new_map->SetLookupTable( lut );
951     }
952     else if( lut_t == LUTType_Colors )
953     {
954       // Get HSV from display color
955       double r = 1, g = 0, b = 0;
956       double cmax = ( r > g )? r: g; cmax = ( b > cmax )? b: cmax;
957       double cmin = ( r < g )? r: g; cmin = ( b < cmin )? b: cmin;
958       double d = cmax - cmin;
959
960       double saturation = ( std::fabs( cmax ) > _0 )? d / cmax: _0;
961       double value = cmax;
962       double hue = _0;
963       if( d > _0 )
964       {
965         if( r == cmax )
966           hue = std::fmod( ( g - b ) / d, _6 );
967         else if( g == cmax )
968           hue = ( ( b - r ) / d ) + _2;
969         else if( b == cmax )
970           hue = ( ( r - g ) / d ) + _4;
971         hue *= _1 / _6;
972
973       } // fi
974
975       // Define new lookup table
976       vtkSmartPointer< vtkLookupTable > lut =
977         vtkSmartPointer< vtkLookupTable >::New( );
978       lut->SetScaleToLinear( );
979       lut->SetNanColor( _0, _0, _0, _0 );
980       lut->SetTableRange( range[ 0 ], range[ 1 ] );
981       lut->SetAlphaRange( _0, _OPACITY );
982       lut->SetHueRange( _0, hue );
983       lut->SetSaturationRange( _0, saturation );
984       lut->SetValueRange( _0, value );
985       lut->Build( );
986
987       new_map = vtkSmartPointer< vtkImageMapToColors >::New( );
988       new_map->SetLookupTable( lut );
989
990     } // fi
991
992   } // fi
993   this->ImageMaps.push_back( new_map );
994 }
995
996 // -------------------------------------------------------------------------
997 void cpExtensions::Visualization::ImageSliceActors::
998 _ConfigureNewInput( int axis )
999 {
1000   unsigned int nImages = this->ImageActors.size( );
1001
1002   // Configure mapper
1003   vtkImageSliceMapper* mapper = this->SliceMappers[ nImages ];
1004   if( nImages == 0 )
1005     mapper->SetOrientation( axis );
1006   else
1007     mapper->SetOrientation( this->SliceMappers[ 0 ]->GetOrientation( ) );
1008   mapper->Update( );
1009
1010   // Create actor
1011   vtkSmartPointer< vtkImageActor > actor =
1012     vtkSmartPointer< vtkImageActor >::New( );
1013   this->ImageActors.push_back( actor );
1014   actor->SetMapper( mapper );
1015   actor->SetInterpolate( this->Interpolate );
1016   actor->Modified( );
1017
1018   if( nImages == 0 )
1019   {
1020     this->AddItem( this->CursorActor );
1021     this->AddItem( this->PlaneActor );
1022     this->AddItem( this->TextActor );
1023     this->Style->AssociateImageActor( actor );
1024
1025   } // fi
1026   this->AddItem( actor );
1027
1028   if( nImages > 1 )
1029     this->SetSliceNumber( this->GetSliceNumber( ) );
1030   this->Modified( );
1031 }
1032
1033 // -------------------------------------------------------------------------
1034 void cpExtensions::Visualization::ImageSliceActors::
1035 _MouseMoveCommand(
1036   void* data,
1037   const ImageInteractorStyle::ButtonID& btn, double* pos,
1038   bool alt, bool ctr, bool sft
1039   )
1040 {
1041   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1042   if( actors == NULL )
1043     return;
1044
1045   if( btn == ImageInteractorStyle::ButtonID_None )
1046   {
1047     actors->UpdateText( pos );
1048   }
1049   else if( btn == ImageInteractorStyle::ButtonID_Left )
1050   {
1051   }
1052   else if( btn == ImageInteractorStyle::ButtonID_Middle )
1053   {
1054   }
1055   else if( btn == ImageInteractorStyle::ButtonID_Right )
1056   {
1057     if( !alt && !ctr && sft )
1058     {
1059       double bounds[ 6 ];
1060       actors->SliceMappers[ 0 ]->GetBounds( bounds );
1061
1062       int a0 = actors->GetAxis( );
1063       int a1 = ( a0 + 1 ) % 3;
1064       int a2 = ( a0 + 2 ) % 3;
1065       double dx = pos[ a1 ] - actors->StartWindowLevelPos[ a1 ];
1066       double dy = pos[ a2 ] - actors->StartWindowLevelPos[ a2 ];
1067       dx /= bounds[ ( a1 << 1 ) + 1 ] - bounds[ a1 << 1 ];
1068       dy /= bounds[ ( a2 << 1 ) + 1 ] - bounds[ a2 << 1 ];
1069
1070       dx *= actors->StartWindowLevel[ 0 ];
1071       dy *= actors->StartWindowLevel[ 1 ];
1072       actors->SetWindowLevel(
1073         0,
1074         actors->StartWindowLevel[ 0 ] + dx,
1075         actors->StartWindowLevel[ 1 ] + dy
1076         );
1077
1078     } // fi
1079
1080   } // fi
1081 }
1082
1083 // -------------------------------------------------------------------------
1084 void cpExtensions::Visualization::ImageSliceActors::
1085 _MouseClickCommand(
1086   void* data,
1087   const ImageInteractorStyle::ButtonID& btn, double* pos,
1088   bool alt, bool ctr, bool sft
1089   )
1090 {
1091   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1092   if( actors == NULL )
1093     return;
1094
1095   actors->StartWindowLevelPos[ 0 ] = pos[ 0 ];
1096   actors->StartWindowLevelPos[ 1 ] = pos[ 1 ];
1097   actors->StartWindowLevelPos[ 2 ] = pos[ 2 ];
1098   actors->StartWindowLevel[ 0 ] = actors->GetWindow( 0 );
1099   actors->StartWindowLevel[ 1 ] = actors->GetLevel( 0 );
1100 }
1101
1102 // -------------------------------------------------------------------------
1103 void cpExtensions::Visualization::ImageSliceActors::
1104 _MouseDoubleClickCommand(
1105   void* data,
1106   const ImageInteractorStyle::ButtonID& btn, double* pos,
1107   bool alt, bool ctr, bool sft
1108   )
1109 {
1110   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1111   if( actors == NULL )
1112     return;
1113
1114   if( btn == ImageInteractorStyle::ButtonID_Left )
1115   {
1116     if( !alt && !ctr && !sft )
1117     {
1118       actors->SetCursor( pos );
1119
1120     } // fi
1121   }
1122   else if( btn == ImageInteractorStyle::ButtonID_Middle )
1123   {
1124   }
1125   else if( btn == ImageInteractorStyle::ButtonID_Right )
1126   {
1127   } // fi
1128 }
1129
1130 // -------------------------------------------------------------------------
1131 void cpExtensions::Visualization::ImageSliceActors::
1132 _MouseWheelCommand(
1133   void* data,
1134   const int& dir, bool alt, bool ctr, bool sft
1135   )
1136 {
1137   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1138   if( actors == NULL )
1139     return;
1140
1141   if( !alt && !ctr && !sft )
1142   {
1143     actors->SetSliceNumber( actors->GetSliceNumber( ) + dir );
1144   }
1145   else if( !alt && !ctr && sft )
1146   {
1147     actors->SetSliceNumber( actors->GetSliceNumber( ) + ( dir * 10 ) );
1148
1149   } // fi
1150 }
1151
1152 // -------------------------------------------------------------------------
1153 void cpExtensions::Visualization::ImageSliceActors::
1154 _KeyCommand(
1155   void* data,
1156   const char& key
1157   )
1158 {
1159 }
1160
1161 // eof - $RCSfile$