]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageSliceActors.cxx
I'm on the middle of something, NOT YET STABLE - Leo
[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 )
33 {
34   // Get input vtkImageData
35   if( aout == NULL )
36     return;
37   vtkAlgorithm* producer = aout->GetProducer( );
38   vtkImageData* data = dynamic_cast< vtkImageData* >(
39     producer->GetOutputDataObject( aout->GetIndex( ) )
40     );
41   if( data == NULL )
42     return;
43
44   // Try to infere if input comes from a color mapping filter
45   vtkImageMapToColors* new_map =
46     dynamic_cast< vtkImageMapToColors* >( producer );
47   if( new_map == NULL )
48   {
49     // Configure LUT, if possible (NULL is returned if not)
50     this->_ConfigureNewLUT( data );
51     new_map = *( this->m_ImageMaps.rbegin( ) );
52     if( new_map != NULL )
53     {
54       new_map->SetInputConnection( aout );
55       new_map->Update( );
56
57     } // fi
58   }
59   else
60     this->m_ImageMaps.push_back( new_map );
61
62   // Update window level values
63   if( new_map != NULL )
64   {
65     double range[ 2 ];
66     dynamic_cast< vtkImageData* >( new_map->GetInput( ) )->
67       GetScalarRange( range );
68     this->m_MinWindow = double( 0 );
69     this->m_MaxWindow = range[ 1 ] - range[ 0 ];
70     this->m_MinLevel = range[ 0 ];
71     this->m_MaxLevel = range[ 1 ];
72
73   } // fi
74
75   // Create mapper and actors
76   vtkSmartPointer< vtkImageSliceMapper > mapper =
77     vtkSmartPointer< vtkImageSliceMapper >::New( );
78   if( new_map != NULL )
79     mapper->SetInputConnection( new_map->GetOutputPort( ) );
80   else
81     mapper->SetInputConnection( aout );
82   this->m_SliceMappers.push_back( mapper );
83   this->_ConfigureNewInput( axis );
84 }
85
86 // -------------------------------------------------------------------------
87 void cpExtensions::Visualization::ImageSliceActors::
88 AddInputData( vtkImageData* data, int axis )
89 {
90   // Update window level values
91   if( this->m_ImageMaps.size( ) == 0 )
92   {
93     double range[ 2 ];
94     data->GetScalarRange( range );
95     this->m_MinWindow = double( 0 );
96     this->m_MaxWindow = range[ 1 ] - range[ 0 ];
97     this->m_MinLevel = range[ 0 ];
98     this->m_MaxLevel = range[ 1 ];
99
100   } // fi
101
102   // Configure LUT, if possible (NULL is returned if not)
103   this->_ConfigureNewLUT( data );
104   vtkImageMapToColors* new_map = *( this->m_ImageMaps.rbegin( ) );
105   if( new_map != NULL )
106   {
107     new_map->SetInputData( data );
108     new_map->Update( );
109
110   } // fi
111
112   // Create mapper and actors
113   vtkSmartPointer< vtkImageSliceMapper > mapper =
114     vtkSmartPointer< vtkImageSliceMapper >::New( );
115   if( new_map != NULL )
116     mapper->SetInputConnection( new_map->GetOutputPort( ) );
117   else
118     mapper->SetInputData( data );
119   this->m_SliceMappers.push_back( mapper );
120   this->_ConfigureNewInput( axis );
121 }
122
123 // -------------------------------------------------------------------------
124 void cpExtensions::Visualization::ImageSliceActors::
125 Clear( )
126 {
127   // Reset values
128   this->m_MinWindow = double( 0 );
129   this->m_MaxWindow = double( 0 );
130   this->m_MinLevel = double( 0 );
131   this->m_MaxLevel = double( 0 );
132   this->m_VisibleExtent[ 0 ] =
133     this->m_VisibleExtent[ 2 ] =
134     this->m_VisibleExtent[ 4 ] = -1;
135   this->m_VisibleExtent[ 1 ] =
136     this->m_VisibleExtent[ 3 ] =
137     this->m_VisibleExtent[ 5 ] = 0;
138   this->m_VisibleBounds[ 0 ] =
139     this->m_VisibleBounds[ 2 ] =
140     this->m_VisibleBounds[ 4 ] = double( 0 );
141   this->m_VisibleBounds[ 1 ] =
142     this->m_VisibleBounds[ 3 ] =
143     this->m_VisibleBounds[ 5 ] = double( 0 );
144
145   // Unbind from container
146   this->RemoveAllItems( );
147
148   // Delete all images
149   this->m_ImageMaps.clear( );
150   this->m_SliceMappers.clear( );
151   this->m_ImageActors.clear( );
152
153   // Reconfigure unique objects
154   this->m_Cursor               = vtkSmartPointer< vtkPolyData >::New( );
155   this->m_CursorMapper         = vtkSmartPointer< vtkPolyDataMapper >::New( );
156   this->m_CursorActor          = vtkSmartPointer< vtkActor >::New( );
157   this->m_HorizontalLine       = vtkSmartPointer< vtkPolyData >::New( );
158   this->m_HorizontalLineMapper = vtkSmartPointer< vtkPolyDataMapper >::New( );
159   this->m_HorizontalLineActor  = vtkSmartPointer< vtkActor >::New( );
160   this->m_VerticalLine         = vtkSmartPointer< vtkPolyData >::New( );
161   this->m_VerticalLineMapper   = vtkSmartPointer< vtkPolyDataMapper >::New( );
162   this->m_VerticalLineActor    = vtkSmartPointer< vtkActor >::New( );
163   this->m_Plane                = vtkSmartPointer< vtkPolyData >::New( );
164   this->m_PlaneMapper          = vtkSmartPointer< vtkPolyDataMapper >::New( );
165   this->m_TextActor            = vtkSmartPointer< vtkTextActor >::New( );
166   this->m_PlaneActor           = vtkSmartPointer< vtkActor >::New( );
167   this->m_TextBuffer[ 0 ] = '\0';
168
169   // Unique objects configuration
170   vtkSmartPointer< vtkPoints > cursor_points =
171     vtkSmartPointer< vtkPoints >::New( );
172   vtkSmartPointer< vtkCellArray > cursor_lines =
173     vtkSmartPointer< vtkCellArray >::New( );
174   cursor_points->InsertNextPoint( 0, 0, 0 );
175   cursor_points->InsertNextPoint( 0, 0, 0 );
176   cursor_points->InsertNextPoint( 0, 0, 0 );
177   cursor_points->InsertNextPoint( 0, 0, 0 );
178   cursor_points->InsertNextPoint( 0, 0, 0 );
179   cursor_points->InsertNextPoint( 0, 0, 0 );
180   cursor_points->InsertNextPoint( 0, 0, 0 );
181   cursor_points->InsertNextPoint( 0, 0, 0 );
182   cursor_lines->InsertNextCell( 2 );
183   cursor_lines->InsertCellPoint( 0 );
184   cursor_lines->InsertCellPoint( 1 );
185   cursor_lines->InsertNextCell( 2 );
186   cursor_lines->InsertCellPoint( 2 );
187   cursor_lines->InsertCellPoint( 3 );
188   cursor_lines->InsertNextCell( 2 );
189   cursor_lines->InsertCellPoint( 4 );
190   cursor_lines->InsertCellPoint( 5 );
191   cursor_lines->InsertNextCell( 2 );
192   cursor_lines->InsertCellPoint( 6 );
193   cursor_lines->InsertCellPoint( 7 );
194   this->m_Cursor->SetPoints( cursor_points );
195   this->m_Cursor->SetLines( cursor_lines );
196   this->m_CursorMapper->SetInputData( this->m_Cursor );
197   this->m_CursorActor->SetMapper( this->m_CursorMapper );
198
199   vtkSmartPointer< vtkPoints > h_points =
200     vtkSmartPointer< vtkPoints >::New( );
201   vtkSmartPointer< vtkCellArray > h_lines =
202     vtkSmartPointer< vtkCellArray >::New( );
203   h_points->InsertNextPoint( 0, 0, 0 );
204   h_points->InsertNextPoint( 0, 0, 0 );
205   h_lines->InsertNextCell( 2 );
206   h_lines->InsertCellPoint( 0 );
207   h_lines->InsertCellPoint( 1 );
208   this->m_HorizontalLine->SetPoints( h_points );
209   this->m_HorizontalLine->SetLines( h_lines );
210   this->m_HorizontalLineMapper->SetInputData( this->m_HorizontalLine );
211   this->m_HorizontalLineActor->SetMapper( this->m_HorizontalLineMapper );
212
213   vtkSmartPointer< vtkPoints > v_points =
214     vtkSmartPointer< vtkPoints >::New( );
215   vtkSmartPointer< vtkCellArray > v_lines =
216     vtkSmartPointer< vtkCellArray >::New( );
217   v_points->InsertNextPoint( 0, 0, 0 );
218   v_points->InsertNextPoint( 0, 0, 0 );
219   v_lines->InsertNextCell( 2 );
220   v_lines->InsertCellPoint( 0 );
221   v_lines->InsertCellPoint( 1 );
222   this->m_VerticalLine->SetPoints( v_points );
223   this->m_VerticalLine->SetLines( v_lines );
224   this->m_VerticalLineMapper->SetInputData( this->m_VerticalLine );
225   this->m_VerticalLineActor->SetMapper( this->m_VerticalLineMapper );
226
227   vtkSmartPointer< vtkPoints > plane_points =
228     vtkSmartPointer< vtkPoints >::New( );
229   vtkSmartPointer< vtkCellArray > plane_lines =
230     vtkSmartPointer< vtkCellArray >::New( );
231
232   plane_points->InsertNextPoint( 0, 0, 0 );
233   plane_points->InsertNextPoint( 0, 1, 0 );
234   plane_points->InsertNextPoint( 1, 1, 0 );
235   plane_points->InsertNextPoint( 1, 0, 0 );
236   plane_lines->InsertNextCell( 5 );
237   plane_lines->InsertCellPoint( 0 );
238   plane_lines->InsertCellPoint( 1 );
239   plane_lines->InsertCellPoint( 2 );
240   plane_lines->InsertCellPoint( 3 );
241   plane_lines->InsertCellPoint( 0 );
242   this->m_Plane->SetPoints( plane_points );
243   this->m_Plane->SetLines( plane_lines );
244
245   this->m_PlaneMapper->SetInputData( this->m_Plane );
246   this->m_PlaneActor->SetMapper( this->m_PlaneMapper );
247
248   this->m_TextActor->SetTextScaleModeToNone( );
249   vtkTextProperty* textprop = this->m_TextActor->GetTextProperty( );
250   textprop->SetColor( 1, 1, 1 );
251   textprop->SetFontFamilyToCourier( );
252   textprop->SetFontSize( 18 );
253   textprop->BoldOff( );
254   textprop->ItalicOff( );
255   textprop->ShadowOff( );
256   textprop->SetJustificationToLeft( );
257   textprop->SetVerticalJustificationToBottom( );
258   vtkCoordinate* coord = this->m_TextActor->GetPositionCoordinate( );
259   coord->SetCoordinateSystemToNormalizedViewport( );
260   coord->SetValue( 0.01, 0.01 );
261
262   // Update actor collection
263   this->AddItem( this->m_CursorActor );
264   this->AddItem( this->m_HorizontalLineActor );
265   this->AddItem( this->m_VerticalLineActor );
266   this->AddItem( this->m_TextActor );
267   this->AddItem( this->m_PlaneActor );
268 }
269
270 // -------------------------------------------------------------------------
271 void cpExtensions::Visualization::ImageSliceActors::
272 AssociateSlice( Self* slice )
273 {
274   this->m_AssociatedSlices.push_back( slice );
275   this->Modified( );
276 }
277
278 // -------------------------------------------------------------------------
279 vtkInteractorStyle* cpExtensions::Visualization::ImageSliceActors::
280 GetStyle( )
281 {
282   return( this->m_Style.GetPointer( ) );
283 }
284
285 // -------------------------------------------------------------------------
286 const vtkInteractorStyle* cpExtensions::Visualization::ImageSliceActors::
287 GetStyle( ) const
288 {
289   return( this->m_Style.GetPointer( ) );
290 }
291
292 // -------------------------------------------------------------------------
293 vtkImageData* cpExtensions::Visualization::ImageSliceActors::
294 GetInputImage( unsigned int id )
295 {
296   vtkAlgorithmOutput* aout = this->m_ImageMaps[ id ]->GetOutputPort( );
297   vtkImageData* image = dynamic_cast< vtkImageData* >(
298     aout->GetProducer( )->GetOutputDataObject( aout->GetIndex( ) )
299     );
300   return( image );
301 }
302
303 // -------------------------------------------------------------------------
304 const vtkImageData* cpExtensions::Visualization::ImageSliceActors::
305 GetInputImage( unsigned int id ) const
306 {
307   vtkAlgorithmOutput* aout = this->m_ImageMaps[ id ]->GetOutputPort( );
308   const vtkImageData* image = dynamic_cast< const vtkImageData* >(
309     aout->GetProducer( )->GetOutputDataObject( aout->GetIndex( ) )
310     );
311   return( image );
312 }
313
314 // -------------------------------------------------------------------------
315 void cpExtensions::Visualization::ImageSliceActors::
316 PushActorsInto( vtkRenderWindow* window, bool force_style )
317 {
318   this->m_Window = window;
319   if( window == NULL )
320     return;
321   vtkRenderWindowInteractor* rwi = window->GetInteractor( );
322   vtkRenderer* renderer = window->GetRenderers( )->GetFirstRenderer( );
323   if( rwi == NULL || renderer == NULL )
324     return;
325
326   // Update style
327   if( this->m_Style.GetPointer( ) != NULL && force_style )
328     rwi->SetInteractorStyle( this->m_Style );
329
330   // Update actors
331   vtkProp* prop;
332   this->InitTraversal( );
333   while( prop = this->GetNextProp( ) )
334     renderer->AddViewProp( prop );
335   renderer->Modified( );
336   if( !force_style )
337   {
338     renderer->RemoveViewProp( this->m_CursorActor );
339     renderer->RemoveViewProp( this->m_TextActor );
340
341   } // fi
342
343   // Configure camera
344   vtkCamera* camera = renderer->GetActiveCamera( );
345   if( camera != NULL && force_style )
346   {
347     // Parallel projections are better when displaying 2D images
348     int axis = this->GetAxis( );
349     camera->ParallelProjectionOn( );
350     camera->SetFocalPoint( double( 0 ), double( 0 ), double( 0 ) );
351     if( axis == 0 )
352     {
353       camera->SetPosition( double( 1 ), double( 0 ), double( 0 ) );
354       camera->SetViewUp  ( double( 0 ), double( 0 ), double( 1 ) );
355     }
356     else if( axis == 1 )
357     {
358       camera->SetPosition( double( 0 ), double( -1 ), double( 0 ) );
359       camera->SetViewUp  ( double( 0 ), double(  0 ), double( 1 ) );
360     }
361     else // if( axis == 2 )
362     {
363       camera->SetPosition( double( 0 ), double(  0 ), double( -1 ) );
364       camera->SetViewUp  ( double( 0 ), double( -1 ), double(  0 ) );
365
366     } // fi
367
368   } // fi
369   this->ResetCamera( );
370   rwi->Render( );
371 }
372
373 // -------------------------------------------------------------------------
374 void cpExtensions::Visualization::ImageSliceActors::
375 PopActorsFrom( vtkRenderWindow* window )
376 {
377   vtkRenderWindowInteractor* rwi = window->GetInteractor( );
378   vtkRenderer* renderer = window->GetRenderers( )->GetFirstRenderer( );
379
380   if( renderer != NULL )
381   {
382     // Update actors
383     vtkProp* prop;
384     this->InitTraversal( );
385     while( prop = this->GetNextProp( ) )
386       renderer->RemoveViewProp( prop );
387     renderer->Modified( );
388
389   } // fi
390   if( rwi != NULL )
391     rwi->Render( );
392 }
393
394 // -------------------------------------------------------------------------
395 unsigned int cpExtensions::Visualization::ImageSliceActors::
396 GetNumberOfImageActors( ) const
397 {
398   return( this->m_ImageActors.size( ) );
399 }
400
401 // -------------------------------------------------------------------------
402 vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
403 GetImageActor( unsigned int id )
404 {
405   if( id < this->m_ImageActors.size( ) )
406     return( this->m_ImageActors[ id ] );
407   else
408     return( NULL );
409 }
410
411 // -------------------------------------------------------------------------
412 const vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
413 GetImageActor( unsigned int id ) const
414 {
415   if( id < this->m_ImageActors.size( ) )
416     return( this->m_ImageActors[ id ] );
417   else
418     return( NULL );
419 }
420
421 // -------------------------------------------------------------------------
422 vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
423 GetTextActor( )
424 {
425   return( this->m_TextActor );
426 }
427
428 // -------------------------------------------------------------------------
429 const vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
430 GetTextActor( ) const
431 {
432   return( this->m_TextActor );
433 }
434
435 // -------------------------------------------------------------------------
436 vtkActor* cpExtensions::Visualization::ImageSliceActors::
437 GetPlaneActor( )
438 {
439   return( this->m_PlaneActor );
440 }
441
442 // -------------------------------------------------------------------------
443 const vtkActor* cpExtensions::Visualization::ImageSliceActors::
444 GetPlaneActor( ) const
445 {
446   return( this->m_PlaneActor );
447 }
448
449 // -------------------------------------------------------------------------
450 vtkPlane* cpExtensions::Visualization::ImageSliceActors::
451 GetPlaneFunction( )
452 {
453   return( this->m_SliceMappers[ 0 ]->GetSlicePlane( ) );
454 }
455
456 // -------------------------------------------------------------------------
457 const vtkPlane* cpExtensions::Visualization::ImageSliceActors::
458 GetPlaneFunction( ) const
459 {
460   return( this->m_SliceMappers[ 0 ]->GetSlicePlane( ) );
461 }
462
463 // -------------------------------------------------------------------------
464 void cpExtensions::Visualization::ImageSliceActors::
465 SetInterpolate( bool v )
466 {
467   if( this->m_Interpolate != v )
468   {
469     for( unsigned int i = 0; i < this->m_ImageActors.size( ); ++i )
470       this->m_ImageActors[ i ]->SetInterpolate( v );
471     this->m_Interpolate = v;
472     this->Modified( );
473
474   } // fi
475 }
476
477 // -------------------------------------------------------------------------
478 void cpExtensions::Visualization::ImageSliceActors::
479 InterpolateOn( )
480 {
481   this->SetInterpolate( true );
482 }
483
484 // -------------------------------------------------------------------------
485 void cpExtensions::Visualization::ImageSliceActors::
486 InterpolateOff( )
487 {
488   this->SetInterpolate( false );
489 }
490
491 // -------------------------------------------------------------------------
492 double* cpExtensions::Visualization::ImageSliceActors::
493 GetDisplayBounds( ) const
494 {
495   if( this->m_ImageActors.size( ) > 0 )
496     return( this->m_ImageActors[ 0 ]->GetDisplayBounds( ) );
497   else
498     return( NULL );
499 }
500
501 // -------------------------------------------------------------------------
502 void cpExtensions::Visualization::ImageSliceActors::
503 GetDisplayBounds( double bounds[ 6 ] ) const
504 {
505   if( this->m_ImageActors.size( ) == 0 )
506   {
507     bounds[ 0 ] = bounds[ 2 ] = bounds[ 4 ] = double( -1 );
508     bounds[ 1 ] = bounds[ 3 ] = bounds[ 5 ] = double( -1 );
509   }
510   else
511     this->m_ImageActors[ 0 ]->GetDisplayBounds( bounds );
512 }
513
514 // -------------------------------------------------------------------------
515 void cpExtensions::Visualization::ImageSliceActors::
516 ResetCursor( )
517 {
518   if( this->m_SliceMappers.size( ) > 0 )
519   {
520     double bounds[ 6 ];
521     this->m_SliceMappers[ 0 ]->GetInput( )->GetBounds( bounds );
522     double pos[] =
523       {
524         this->m_VisibleBounds[ 0 ],
525         this->m_VisibleBounds[ 2 ],
526         this->m_VisibleBounds[ 4 ]
527       };
528     this->SetCursor( pos );
529   }
530   else
531   {
532     vtkPoints* points = this->m_Cursor->GetPoints( );
533     points->SetPoint( 0, 0, 0, 0 );
534     points->SetPoint( 1, 0, 0, 0 );
535     points->SetPoint( 2, 0, 0, 0 );
536     points->SetPoint( 3, 0, 0, 0 );
537     points->SetPoint( 4, 0, 0, 0 );
538     points->SetPoint( 5, 0, 0, 0 );
539     points->SetPoint( 6, 0, 0, 0 );
540     points->SetPoint( 7, 0, 0, 0 );
541     this->m_Cursor->Modified( );
542     this->m_CursorMapper->Modified( );
543     this->m_CursorActor->Modified( );
544
545   } // fi
546 }
547
548 // -------------------------------------------------------------------------
549 void cpExtensions::Visualization::ImageSliceActors::
550 SetCursor( double pos[ 3 ] )
551 {
552   if( this->m_SliceMappers.size( ) == 0 )
553     return;
554
555   // Get ordered axes
556   int a0 = this->GetAxis( );
557   int a1 = ( a0 + 1 ) % 3;
558   int a2 = ( a0 + 2 ) % 3;
559   int ma0 = a0 << 1;
560   int ma1 = a1 << 1;
561   int ma2 = a2 << 1;
562
563   // Update cross
564   double* bounds = this->m_VisibleBounds;
565   double
566     p0[ 3 ], p1[ 3 ], p2[ 3 ], p3[ 3 ],
567     p4[ 3 ], p5[ 3 ], p6[ 3 ], p7[ 3 ];
568
569   p0[ a2 ] = p1[ a2 ] = p4[ a2 ] = p5[ a2 ] = pos[ a2 ];
570   p2[ a1 ] = p3[ a1 ] = p6[ a1 ] = p7[ a1 ] = pos[ a1 ];
571   p0[ a0 ] = p1[ a0 ] = p2[ a0 ] = p3[ a0 ] = bounds[ ma0 ];
572   p4[ a0 ] = p5[ a0 ] = p6[ a0 ] = p7[ a0 ] = bounds[ ma0 + 1 ];
573   p0[ a1 ] = p4[ a1 ] = bounds[ ma1 ];
574   p1[ a1 ] = p5[ a1 ] = bounds[ ma1 + 1 ];
575   p2[ a2 ] = p6[ a2 ] = bounds[ ma2 ];
576   p3[ a2 ] = p7[ a2 ] = bounds[ ma2 + 1 ];
577
578   vtkPoints* points = this->m_Cursor->GetPoints( );
579   points->SetPoint( 0, p0 );
580   points->SetPoint( 1, p1 );
581   points->SetPoint( 2, p2 );
582   points->SetPoint( 3, p3 );
583   points->SetPoint( 4, p4 );
584   points->SetPoint( 5, p5 );
585   points->SetPoint( 6, p6 );
586   points->SetPoint( 7, p7 );
587   this->m_Cursor->Modified( );
588   this->m_CursorMapper->Modified( );
589   this->m_CursorActor->Modified( );
590 }
591
592 // -------------------------------------------------------------------------
593 vtkImageMapToColors* cpExtensions::Visualization::ImageSliceActors::
594 GetImageMap( unsigned int id )
595 {
596   if( id < this->m_ImageMaps.size( ) )
597     return( this->m_ImageMaps[ id ].GetPointer( ) );
598   else
599     return( NULL );
600 }
601
602 // -------------------------------------------------------------------------
603 const vtkImageMapToColors* cpExtensions::Visualization::ImageSliceActors::
604 GetImageMap( unsigned int id ) const
605 {
606   if( id < this->m_ImageMaps.size( ) )
607     return( this->m_ImageMaps[ id ].GetPointer( ) );
608   else
609     return( NULL );
610 }
611
612 // -------------------------------------------------------------------------
613 double cpExtensions::Visualization::ImageSliceActors::
614 GetMinWindow( ) const
615 {
616   return( this->m_MinWindow );
617 }
618
619 // -------------------------------------------------------------------------
620 double cpExtensions::Visualization::ImageSliceActors::
621 GetMaxWindow( ) const
622 {
623   return( this->m_MaxWindow );
624 }
625
626 // -------------------------------------------------------------------------
627 double cpExtensions::Visualization::ImageSliceActors::
628 GetMinLevel( ) const
629 {
630   return( this->m_MinLevel );
631 }
632
633 // -------------------------------------------------------------------------
634 double cpExtensions::Visualization::ImageSliceActors::
635 GetMaxLevel( ) const
636 {
637   return( this->m_MaxLevel );
638 }
639
640 // -------------------------------------------------------------------------
641 double cpExtensions::Visualization::ImageSliceActors::
642 GetWindow( ) const
643 {
644   if( this->m_ImageMaps.size( ) == 0 )
645     return( double( 0 ) );
646   if( this->m_ImageMaps[ 0 ].GetPointer( ) == NULL )
647     return( double( 0 ) );
648
649   vtkWindowLevelLookupTable* lut =
650     dynamic_cast< vtkWindowLevelLookupTable* >(
651       this->m_ImageMaps[ 0 ]->GetLookupTable( )
652       );
653   if( lut != NULL )
654     return( lut->GetWindow( ) );
655   else
656     return( double( 0 ) );
657 }
658
659 // -------------------------------------------------------------------------
660 double cpExtensions::Visualization::ImageSliceActors::
661 GetLevel( ) const
662 {
663   if( this->m_ImageMaps.size( ) == 0 )
664     return( double( 0 ) );
665   if( this->m_ImageMaps[ 0 ].GetPointer( ) == NULL )
666     return( double( 0 ) );
667
668   vtkWindowLevelLookupTable* lut =
669     dynamic_cast< vtkWindowLevelLookupTable* >(
670       this->m_ImageMaps[ 0 ]->GetLookupTable( )
671       );
672   if( lut != NULL )
673     return( lut->GetLevel( ) );
674   else
675     return( double( 0 ) );
676 }
677
678 // -------------------------------------------------------------------------
679 void cpExtensions::Visualization::ImageSliceActors::
680 SetWindow( double w )
681 {
682   if( this->m_ImageMaps.size( ) == 0 )
683     return;
684   if( this->m_ImageMaps[ 0 ].GetPointer( ) == NULL )
685     return;
686   vtkWindowLevelLookupTable* lut =
687     dynamic_cast< vtkWindowLevelLookupTable* >(
688       this->m_ImageMaps[ 0 ]->GetLookupTable( )
689       );
690   if( lut == NULL )
691     return;
692
693   if( w < this->m_MinWindow )
694     w = this->m_MinWindow;
695   if( w > this->m_MaxWindow )
696     w = this->m_MaxWindow;
697
698   lut->SetWindow( w );
699   lut->Build( );
700   this->m_ImageMaps[ 0 ]->Modified( );
701   this->Modified( );
702 }
703
704 // -------------------------------------------------------------------------
705 void cpExtensions::Visualization::ImageSliceActors::
706 SetLevel( double l )
707 {
708   if( this->m_ImageMaps.size( ) == 0 )
709     return;
710   if( this->m_ImageMaps[ 0 ].GetPointer( ) == NULL )
711     return;
712   vtkWindowLevelLookupTable* lut =
713     dynamic_cast< vtkWindowLevelLookupTable* >(
714       this->m_ImageMaps[ 0 ]->GetLookupTable( )
715       );
716   if( lut == NULL )
717     return;
718
719   if( l < this->m_MinLevel )
720     l = this->m_MinLevel;
721   if( l > this->m_MaxLevel )
722     l = this->m_MaxLevel;
723
724   lut->SetLevel( l );
725   lut->Build( );
726   this->m_ImageMaps[ 0 ]->Modified( );
727   this->Modified( );
728 }
729
730 // -------------------------------------------------------------------------
731 void cpExtensions::Visualization::ImageSliceActors::
732 SetWindowLevel( double w, double l )
733 {
734   if( this->m_ImageMaps.size( ) == 0 )
735     return;
736   if( this->m_ImageMaps[ 0 ].GetPointer( ) == NULL )
737     return;
738   vtkWindowLevelLookupTable* lut =
739     dynamic_cast< vtkWindowLevelLookupTable* >(
740       this->m_ImageMaps[ 0 ]->GetLookupTable( )
741       );
742   if( lut == NULL )
743     return;
744
745   if( w < this->m_MinWindow )
746     w = this->m_MinWindow;
747   if( w > this->m_MaxWindow )
748     w = this->m_MaxWindow;
749   if( l < this->m_MinLevel )
750     l = this->m_MinLevel;
751   if( l > this->m_MaxLevel )
752     l = this->m_MaxLevel;
753
754   lut->SetWindow( w );
755   lut->SetLevel( l );
756   lut->Build( );
757   this->m_ImageMaps[ 0 ]->Modified( );
758   this->UpdateText( w, l );
759   this->Modified( );
760 }
761
762 // -------------------------------------------------------------------------
763 void cpExtensions::Visualization::ImageSliceActors::
764 ResetWindowLevel( )
765 {
766   static const double _2 = double( 2 );
767   this->SetWindowLevel(
768     this->m_MaxWindow, ( this->m_MaxLevel + this->m_MinLevel ) / _2
769     );
770 }
771
772 // -------------------------------------------------------------------------
773 void cpExtensions::Visualization::ImageSliceActors::
774 SetLookupTable( unsigned int id, vtkLookupTable* lut )
775 {
776   if( id < this->m_ImageMaps.size( ) && id > 0 )
777   {
778     if( this->m_ImageMaps[ id ].GetPointer( ) != NULL )
779     {
780       this->m_ImageMaps[ id ]->SetLookupTable( lut );
781       this->m_ImageMaps[ id ]->Modified( );
782       this->Modified( );
783
784     } // fi
785
786   } // fi
787 }
788
789 // -------------------------------------------------------------------------
790 void cpExtensions::Visualization::ImageSliceActors::
791 SetLookupTableAsColor( unsigned int id, double r, double g, double b )
792 {
793   static const double _0 = double( 0 );
794   static const double _2 = double( 2 );
795   static const double _4 = double( 4 );
796   static const double _6 = double( 6 );
797   static const double _OPACITY = double( 0.6 );
798
799   // Check ID consistency
800   if( id == 0 || id >= this->m_ImageMaps.size( ) )
801     return;
802
803   // Get image scalar range
804   vtkAlgorithmOutput* aout = this->m_ImageMaps[ id ]->GetOutputPort( );
805   vtkImageData* image = dynamic_cast< vtkImageData* >(
806     aout->GetProducer( )->GetOutputDataObject( aout->GetIndex( ) )
807     );
808   double range[ 2 ];
809   image->GetScalarRange( range );
810
811   // Get HSV from display color
812   double cmax = ( r > g )? r: g; cmax = ( b > cmax )? b: cmax;
813   double cmin = ( r < g )? r: g; cmin = ( b < cmin )? b: cmin;
814   double d = cmax - cmin;
815
816   double saturation = ( std::fabs( cmax ) > _0 )? d / cmax: _0;
817   double value = cmax;
818   double hue = _0;
819   if( d > _0 )
820   {
821     if( r == cmax )
822       hue = std::fmod( ( g - b ) / d, _6 );
823     else if( g == cmax )
824       hue = ( ( b - r ) / d ) + _2;
825     else if( b == cmax )
826       hue = ( ( r - g ) / d ) + _4;
827     hue /= _6;
828
829   } // fi
830
831   // Define new lookup table
832   vtkSmartPointer< vtkLookupTable > lut =
833     vtkSmartPointer< vtkLookupTable >::New( );
834   lut->SetScaleToLinear( );
835   lut->SetNanColor( _0, _0, _0, _0 );
836   lut->SetTableRange( range[ 0 ], range[ 1 ] );
837   lut->SetAlphaRange( _0, _OPACITY );
838   lut->SetHueRange( _0, hue );
839   lut->SetSaturationRange( _0, saturation );
840   lut->SetValueRange( _0, value );
841   lut->Build( );
842   this->SetLookupTable( id, lut );
843 }
844
845 // -------------------------------------------------------------------------
846 int cpExtensions::Visualization::ImageSliceActors::
847 GetAxis( ) const
848 {
849   if( this->m_SliceMappers.size( ) > 0 )
850     return( this->m_SliceMappers[ 0 ]->GetOrientation( ) );
851   else
852     return( -1 );
853 }
854
855 // -------------------------------------------------------------------------
856 int cpExtensions::Visualization::ImageSliceActors::
857 GetSliceNumber( ) const
858 {
859   if( this->m_SliceMappers.size( ) > 0 )
860     return( this->m_SliceMappers[ 0 ]->GetSliceNumber( ) );
861   else
862     return( -1 );
863 }
864
865 // -------------------------------------------------------------------------
866 int cpExtensions::Visualization::ImageSliceActors::
867 GetSliceNumberMinValue( ) const
868 {
869   if( this->m_SliceMappers.size( ) > 0 )
870     return( this->m_SliceMappers[ 0 ]->GetSliceNumberMinValue( ) );
871   else
872     return( -1 );
873 }
874
875 // -------------------------------------------------------------------------
876 int cpExtensions::Visualization::ImageSliceActors::
877 GetSliceNumberMaxValue( ) const
878 {
879   if( this->m_SliceMappers.size( ) > 0 )
880     return( this->m_SliceMappers[ 0 ]->GetSliceNumberMaxValue( ) );
881   else
882     return( -1 );
883 }
884
885 // -------------------------------------------------------------------------
886 void cpExtensions::Visualization::ImageSliceActors::
887 SetSliceNumber( const int& slice )
888 {
889   unsigned int nImages = this->m_SliceMappers.size( );
890   if( nImages == 0 )
891     return;
892
893   int axis = this->GetAxis( );
894   double prev_pos = this->m_VisibleBounds[ axis << 1 ];
895
896   // Change visualization extent
897   for( unsigned int i = 0; i < nImages; ++i )
898   {
899     // Update mappers and display bounds
900     this->m_SliceMappers[ i ]->SetSliceNumber( slice );
901     this->m_SliceMappers[ i ]->Modified( );
902     this->m_ImageActors[ i ]->Modified( );
903     this->m_SliceMappers[ i ]->Update( );
904
905     // Update display extent (this isn't done automatically)
906     if( i == 0 )
907     {
908       this->m_SliceMappers[ i ]->GetInput( )->
909         GetExtent( this->m_VisibleExtent );
910       this->m_VisibleExtent[ axis << 1 ] = slice;
911       this->m_VisibleExtent[ ( axis << 1 ) + 1 ] = slice;
912
913     } // fi
914     this->m_ImageActors[ i ]->SetDisplayExtent( this->m_VisibleExtent );
915
916   } // rof
917
918   this->m_SliceMappers[ 0 ]->GetBounds( this->m_VisibleBounds );
919   double x0[][ 3 ] =
920   {
921     {
922       this->m_VisibleBounds[ 0 ],
923       this->m_VisibleBounds[ 2 ],
924       this->m_VisibleBounds[ 4 ]
925     },
926     {
927       this->m_VisibleBounds[ 1 ],
928       this->m_VisibleBounds[ 3 ],
929       this->m_VisibleBounds[ 5 ]
930     }
931   };
932   double p0[ 2 ][ 3 ];
933
934   vtkPlane* plane = this->m_SliceMappers[ 0 ]->GetSlicePlane( );
935   plane->GeneralizedProjectPoint( x0[ 0 ], p0[ 0 ] );
936   plane->GeneralizedProjectPoint( x0[ 1 ], p0[ 1 ] );
937
938   this->m_VisibleBounds[ 0 ] = p0[ 0 ][ 0 ];
939   this->m_VisibleBounds[ 1 ] = p0[ 1 ][ 0 ];
940   this->m_VisibleBounds[ 2 ] = p0[ 0 ][ 1 ];
941   this->m_VisibleBounds[ 3 ] = p0[ 1 ][ 1 ];
942   this->m_VisibleBounds[ 4 ] = p0[ 0 ][ 2 ];
943   this->m_VisibleBounds[ 5 ] = p0[ 1 ][ 2 ];
944   double* bnds = this->m_VisibleBounds;
945
946   // Configure visualization and implicit plane orientation
947   this->m_PlaneActor->GetProperty( )->SetRepresentationToWireframe( );
948   this->m_PlaneActor->GetProperty( )->SetLineWidth( 3 );
949   vtkPoints* plane_points = this->m_Plane->GetPoints( );
950   plane_points->SetPoint( 0, bnds[ 0 ], bnds[ 2 ], bnds[ 4 ] );
951   plane_points->SetPoint( 2, bnds[ 1 ], bnds[ 3 ], bnds[ 5 ] );
952   if( axis == 0 || axis == 2 ) // YZ, x-normal
953   {
954     plane_points->SetPoint( 1, bnds[ 1 ], bnds[ 2 ], bnds[ 5 ] );
955     plane_points->SetPoint( 3, bnds[ 0 ], bnds[ 3 ], bnds[ 4 ] );
956     if( axis == 0 )
957       this->m_PlaneActor->GetProperty( )->SetColor( 1, 0, 0 );
958     else
959       this->m_PlaneActor->GetProperty( )->SetColor( 0, 0, 1 );
960   }
961   else if( axis == 1 ) // ZX, y-normal
962   {
963     plane_points->SetPoint( 1, bnds[ 0 ], bnds[ 2 ], bnds[ 5 ] );
964     plane_points->SetPoint( 3, bnds[ 1 ], bnds[ 3 ], bnds[ 4 ] );
965     this->m_PlaneActor->GetProperty( )->SetColor( 0, 1, 0 );
966
967   } // fi
968   this->m_Plane->Modified( );
969   this->m_PlaneMapper->Modified( );
970   this->m_PlaneActor->Modified( );
971
972   // Update text
973   this->UpdateText( );
974
975   // Update lines from associated slices
976   /* TODO
977      auto sIt = this->m_AssociatedSlices.begin( );
978      for( ; sIt != this->m_AssociatedSlices.end( ); ++sIt )
979      {
980      Self* slice = *sIt;
981      for( unsigned int id = 0; id < slice->m_AssociatedSlices.size( ); ++id )
982      {
983      std::cout << id << std::endl;
984      if( slice->m_AssociatedSlices[ id ] != this )
985      continue;
986
987      std::cout << "id : " << id << std::endl;
988
989      } // rof
990
991      } // rof
992   */
993
994   // Update camera position
995   if( this->m_Window == NULL )
996     return;
997   vtkRenderer* renderer =
998     this->m_Window->GetRenderers( )->GetFirstRenderer( );
999   if( renderer == NULL )
1000     return;
1001   vtkCamera* camera = renderer->GetActiveCamera( );
1002   if( camera == NULL )
1003     return;
1004   double cam_pos[ 3 ];
1005   camera->GetPosition( cam_pos );
1006   cam_pos[ axis ] += this->m_VisibleBounds[ axis << 1 ] - prev_pos;
1007   camera->SetPosition( cam_pos );
1008 }
1009
1010 // -------------------------------------------------------------------------
1011 void cpExtensions::Visualization::ImageSliceActors::
1012 SetSlice( double* pos )
1013 {
1014   vtkImageData* image;
1015   if( this->m_ImageMaps[ 0 ] != NULL )
1016     image =
1017       dynamic_cast< vtkImageData* >( this->m_ImageMaps[ 0 ]->GetInput( ) );
1018   else
1019     image = this->m_SliceMappers[ 0 ]->GetInput( );
1020
1021   int ijk[ 3 ];
1022   double pcoords[ 3 ];
1023   image->ComputeStructuredCoordinates( pos, ijk, pcoords );
1024   this->SetSliceNumber( ijk[ this->GetAxis( ) ] );
1025 }
1026
1027 // -------------------------------------------------------------------------
1028 void cpExtensions::Visualization::ImageSliceActors::
1029 UpdateText( )
1030 {
1031   if( this->m_SliceMappers.size( ) > 0 )
1032   {
1033     char axis;
1034     int axId = this->m_SliceMappers[ 0 ]->GetOrientation( );
1035     if     ( axId == 0 ) axis = 'X';
1036     else if( axId == 1 ) axis = 'Y';
1037     else if( axId == 2 ) axis = 'Z';
1038
1039     std::sprintf(
1040       this->m_TextBuffer, "Axis: %c (%d)",
1041       axis, this->m_SliceMappers[ 0 ]->GetSliceNumber( )
1042       );
1043   }
1044   else
1045     this->m_TextBuffer[ 0 ] = '\0';
1046   this->m_TextActor->SetInput( this->m_TextBuffer );
1047   this->m_TextActor->Modified( );
1048   this->Modified( );
1049 }
1050
1051 // -------------------------------------------------------------------------
1052 void cpExtensions::Visualization::ImageSliceActors::
1053 UpdateText( double pos[ 3 ] )
1054 {
1055   if( this->m_SliceMappers.size( ) > 0 )
1056   {
1057     char axis;
1058     int axId = this->m_SliceMappers[ 0 ]->GetOrientation( );
1059     if     ( axId == 0 ) axis = 'X';
1060     else if( axId == 1 ) axis = 'Y';
1061     else if( axId == 2 ) axis = 'Z';
1062     int slice = this->GetSliceNumber( );
1063
1064     vtkImageData* image;
1065     if( this->m_ImageMaps[ 0 ] != NULL )
1066       image =
1067         dynamic_cast< vtkImageData* >( this->m_ImageMaps[ 0 ]->GetInput( ) );
1068     else
1069       image = this->m_SliceMappers[ 0 ]->GetInput( );
1070
1071     int ijk[ 3 ];
1072     double pcoords[ 3 ];
1073     image->ComputeStructuredCoordinates( pos, ijk, pcoords );
1074     ijk[ axId ] = slice;
1075
1076     int ext[ 6 ];
1077     image->GetExtent( ext );
1078     if(
1079       ext[ 0 ] <= ijk[ 0 ] && ijk[ 0 ] <= ext[ 1 ] &&
1080       ext[ 2 ] <= ijk[ 1 ] && ijk[ 1 ] <= ext[ 3 ] &&
1081       ext[ 4 ] <= ijk[ 2 ] && ijk[ 2 ] <= ext[ 5 ]
1082       )
1083     {
1084       int nScl = image->GetNumberOfScalarComponents( );
1085       std::stringstream str;
1086       str
1087         << "[" << ijk[ 0 ]
1088         << "," << ijk[ 1 ]
1089         << "," << ijk[ 2 ] << "]=(";
1090       str <<
1091         image->GetScalarComponentAsFloat( ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], 0 );
1092       for( int n = 1; n < nScl; ++n )
1093         str
1094           << " "
1095           << image->GetScalarComponentAsFloat(
1096             ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], n
1097             );
1098       str << ")";
1099       std::sprintf(
1100         this->m_TextBuffer, "Axis: %c (%d)\nPixel %s",
1101         axis, slice, str.str( ).c_str( )
1102         );
1103
1104     } // fi
1105   }
1106   else
1107     this->m_TextBuffer[ 0 ] = '\0';
1108   this->m_TextActor->SetInput( this->m_TextBuffer );
1109   this->m_TextActor->Modified( );
1110   this->Modified( );
1111 }
1112
1113 // -------------------------------------------------------------------------
1114 void cpExtensions::Visualization::ImageSliceActors::
1115 UpdateText( const double& w, const double& l )
1116 {
1117   if( this->m_SliceMappers.size( ) > 0 )
1118   {
1119     char axis;
1120     int axId = this->m_SliceMappers[ 0 ]->GetOrientation( );
1121     if     ( axId == 0 ) axis = 'X';
1122     else if( axId == 1 ) axis = 'Y';
1123     else if( axId == 2 ) axis = 'Z';
1124
1125     std::sprintf(
1126       this->m_TextBuffer, "Axis: %c (%d)\nW/L (%.2f/%.2f)",
1127       axis, this->m_SliceMappers[ 0 ]->GetSliceNumber( ), w, l
1128       );
1129   }
1130   else
1131     this->m_TextBuffer[ 0 ] = '\0';
1132   this->m_TextActor->SetInput( this->m_TextBuffer );
1133   this->m_TextActor->Modified( );
1134   this->Modified( );
1135 }
1136
1137 // -------------------------------------------------------------------------
1138 void cpExtensions::Visualization::ImageSliceActors::
1139 Render( const double& t )
1140 {
1141   if( this->m_Window != NULL )
1142   {
1143     vtkRenderer* renderer =
1144       this->m_Window->GetRenderers( )->GetFirstRenderer( );
1145     if( renderer != NULL )
1146       renderer->SetAllocatedRenderTime( t );
1147     this->m_Window->Render( );
1148
1149   } // fi
1150 }
1151
1152 // -------------------------------------------------------------------------
1153 void cpExtensions::Visualization::ImageSliceActors::
1154 ResetCamera( )
1155 {
1156   if( this->m_Window == NULL )
1157     return;
1158   vtkRenderer* renderer =
1159     this->m_Window->GetRenderers( )->GetFirstRenderer( );
1160   if( renderer != NULL )
1161     renderer->ResetCamera( this->m_VisibleBounds );
1162 }
1163
1164 // -------------------------------------------------------------------------
1165 cpExtensions::Visualization::ImageSliceActors::
1166 ImageSliceActors( )
1167   : Superclass( ),
1168     m_Window( NULL ),
1169     m_Interpolate( false )
1170 {
1171   this->Clear( );
1172   this->_ConfigureStyle( );
1173 }
1174
1175 // -------------------------------------------------------------------------
1176 cpExtensions::Visualization::ImageSliceActors::
1177 ~ImageSliceActors( )
1178 {
1179 }
1180
1181 // -------------------------------------------------------------------------
1182 void cpExtensions::Visualization::ImageSliceActors::
1183 _ConfigureStyle( )
1184 {
1185   // Connect this view with a controller
1186   this->m_Style = vtkSmartPointer< TStyle >::New( );
1187   this->m_Style->AddMouseMoveCommand( Self::_MouseMoveCommand, this );
1188   this->m_Style->AddMouseClickCommand( Self::_MouseClickCommand, this );
1189   this->m_Style->AddMouseWheelCommand( Self::_MouseWheelCommand, this );
1190   this->m_Style->AddKeyCommand( Self::_KeyCommand, this );
1191   this->m_Style->AddEnterCommand( Self::_EnterCommand, this );
1192   this->m_Style->AddLeaveCommand( Self::_LeaveCommand, this );
1193 }
1194
1195 // -------------------------------------------------------------------------
1196 void cpExtensions::Visualization::ImageSliceActors::
1197 _ConfigureNewLUT( vtkImageData* data )
1198 {
1199   // Does the new LUT is a window-level one?
1200   unsigned int nImgs = this->m_ImageMaps.size( );
1201   unsigned int nCmps = data->GetNumberOfScalarComponents( );
1202
1203   if( nCmps > 1 )
1204   {
1205     this->m_ImageMaps.push_back( NULL );
1206     return;
1207
1208   } // fi
1209
1210   // Create LUT filter
1211   this->m_ImageMaps.push_back( vtkSmartPointer< vtkImageMapToColors >::New( ) );
1212   if( nImgs == 0 )
1213   {
1214     double range[ 2 ];
1215     data->GetScalarRange( range );
1216     vtkSmartPointer< vtkWindowLevelLookupTable > lut =
1217       vtkSmartPointer< vtkWindowLevelLookupTable >::New( );
1218     lut->SetScaleToLinear( );
1219     lut->SetTableRange( range );
1220     lut->SetWindow( range[ 1 ] - range[ 0 ] );
1221     lut->SetLevel( ( range[ 1 ] + range[ 0 ] ) / double( 2 ) );
1222     lut->Build( );
1223     this->m_ImageMaps[ 0 ]->SetLookupTable( lut );
1224   }
1225   else
1226     this->SetLookupTableAsColor( nImgs, 1, 0, 0 );
1227 }
1228
1229 // -------------------------------------------------------------------------
1230 void cpExtensions::Visualization::ImageSliceActors::
1231 _ConfigureNewInput( int axis )
1232 {
1233   unsigned int nImages = this->m_ImageActors.size( );
1234
1235   // Configure mapper
1236   vtkImageSliceMapper* mapper = this->m_SliceMappers[ nImages ];
1237   if( nImages == 0 )
1238     mapper->SetOrientation( axis );
1239   else
1240     mapper->SetOrientation( this->m_SliceMappers[ 0 ]->GetOrientation( ) );
1241   mapper->Update( );
1242
1243   // Create actor
1244   vtkSmartPointer< vtkImageActor > actor =
1245     vtkSmartPointer< vtkImageActor >::New( );
1246   this->m_ImageActors.push_back( actor );
1247   actor->SetMapper( mapper );
1248   actor->SetInterpolate( this->m_Interpolate );
1249   actor->Modified( );
1250
1251   if( nImages == 0 )
1252     this->m_Style->AssociateImageActor( actor );
1253   this->AddItem( actor );
1254
1255   if( nImages > 1 )
1256     this->SetSliceNumber( this->GetSliceNumber( ) );
1257   else
1258     this->SetSliceNumber( this->GetSliceNumberMaxValue( ) );
1259   this->ResetCursor( );
1260   this->Modified( );
1261 }
1262
1263 // -------------------------------------------------------------------------
1264 void cpExtensions::Visualization::ImageSliceActors::
1265 _MouseMoveCommand(
1266   void* data, const TStyle::ButtonID& btn, int* idx, double* pos,
1267   bool alt, bool ctr, bool sft
1268   )
1269 {
1270   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1271   if( actors == NULL )
1272     return;
1273
1274   if( btn == TStyle::ButtonID_None )
1275   {
1276     // Just show the pixel information
1277     actors->SetCursor( pos );
1278     actors->UpdateText( pos );
1279     actors->Render( 1e-3 );
1280   }
1281   else if( btn == TStyle::ButtonID_Left )
1282   {
1283     if( !alt && ctr && !sft )
1284     {
1285       // Interactively move slices
1286       auto i = actors->m_SlicesCommands.begin( );
1287       for( ; i != actors->m_SlicesCommands.end( ); ++i )
1288         i->first( pos, actors->GetAxis( ), i->second );
1289       actors->Render( 1e-3 );
1290
1291     } // fi
1292   }
1293   else if( btn == TStyle::ButtonID_Right )
1294   {
1295     if( !alt && !ctr && sft )
1296     {
1297       // Change image window level
1298       double bounds[ 6 ];
1299       actors->m_SliceMappers[ 0 ]->GetBounds( bounds );
1300
1301       int a0 = actors->GetAxis( );
1302       int a1 = ( a0 + 1 ) % 3;
1303       int a2 = ( a0 + 2 ) % 3;
1304       double dx = pos[ a1 ] - actors->m_StartWindowLevelPos[ a1 ];
1305       double dy = pos[ a2 ] - actors->m_StartWindowLevelPos[ a2 ];
1306       dx /= bounds[ ( a1 << 1 ) + 1 ] - bounds[ a1 << 1 ];
1307       dy /= bounds[ ( a2 << 1 ) + 1 ] - bounds[ a2 << 1 ];
1308
1309       dx *= actors->m_StartWindowLevel[ 0 ];
1310       dy *= actors->m_StartWindowLevel[ 1 ];
1311       dx += actors->m_StartWindowLevel[ 0 ];
1312       dy += actors->m_StartWindowLevel[ 1 ];
1313       actors->SetWindowLevel( dx, dy );
1314       actors->Render( 1e-3 );
1315
1316       // Associate objects
1317       auto i = actors->m_WindowLevelCommands.begin( );
1318       for( ; i != actors->m_WindowLevelCommands.end( ); ++i )
1319         i->first( dx, dy, i->second );
1320       
1321     } // fi
1322
1323   } // fi
1324 }
1325
1326 // -------------------------------------------------------------------------
1327 void cpExtensions::Visualization::ImageSliceActors::
1328 _MouseClickCommand(
1329   void* data, const TStyle::ButtonID& btn, int* idx, double* pos,
1330   bool alt, bool ctr, bool sft
1331   )
1332 {
1333   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1334   if( actors == NULL )
1335     return;
1336
1337   actors->m_StartWindowLevelPos[ 0 ] = pos[ 0 ];
1338   actors->m_StartWindowLevelPos[ 1 ] = pos[ 1 ];
1339   actors->m_StartWindowLevelPos[ 2 ] = pos[ 2 ];
1340   actors->m_StartWindowLevel[ 0 ] = actors->GetWindow( );
1341   actors->m_StartWindowLevel[ 1 ] = actors->GetLevel( );
1342 }
1343
1344 // -------------------------------------------------------------------------
1345 void cpExtensions::Visualization::ImageSliceActors::
1346 _MouseWheelCommand(
1347   void* data, const int& dir,
1348   bool alt, bool ctr, bool sft
1349   )
1350 {
1351   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1352   if( actors == NULL )
1353     return;
1354
1355   if( !alt && !ctr )
1356   {
1357     int slice = actors->GetSliceNumber( ) + ( dir * ( ( sft )? 10: 1 ) );
1358     if( slice < actors->GetSliceNumberMinValue( ) )
1359       slice = actors->GetSliceNumberMinValue( );
1360     if( slice > actors->GetSliceNumberMaxValue( ) )
1361       slice = actors->GetSliceNumberMaxValue( );
1362     actors->SetSliceNumber( slice );
1363
1364     auto a = actors->m_AssociatedSlices.begin( );
1365     for( ; a != actors->m_AssociatedSlices.end( ); ++a )
1366     {
1367       ( *a )->SetSliceNumber( slice );
1368       ( *a )->Render( 1e-3 );
1369
1370     } // rof
1371     actors->Render( 1e-3 );
1372     
1373     // Associate objects
1374     auto i = actors->m_RenderCommands.begin( );
1375     for( ; i != actors->m_RenderCommands.end( ); ++i )
1376       i->first( i->second );
1377
1378   } // fi
1379 }
1380
1381 // -------------------------------------------------------------------------
1382 void cpExtensions::Visualization::ImageSliceActors::
1383 _KeyCommand( void* data, const char& key )
1384 {
1385   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1386   if( actors == NULL )
1387     return;
1388
1389   switch( key )
1390   {
1391   case 'r': case 'R':
1392   {
1393     actors->ResetCamera( );
1394     actors->Render( 1e-3 );
1395
1396     // Associate objects
1397     auto i = actors->m_RenderCommands.begin( );
1398     for( ; i != actors->m_RenderCommands.end( ); ++i )
1399       i->first( i->second );
1400   }
1401   break;
1402   case 'w': case 'W':
1403   {
1404     actors->ResetWindowLevel( );
1405     actors->Render( 1e-3 );
1406
1407     // Associate objects
1408     auto i = actors->m_RenderCommands.begin( );
1409     for( ; i != actors->m_RenderCommands.end( ); ++i )
1410       i->first( i->second );
1411   }
1412   break;
1413   default:
1414     break;
1415   } // hctiws
1416 }
1417
1418 // -------------------------------------------------------------------------
1419 void cpExtensions::Visualization::ImageSliceActors::
1420 _EnterCommand( void* data )
1421 {
1422   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1423   if( actors == NULL )
1424     return;
1425
1426   actors->ResetCursor( );
1427   actors->m_CursorActor->VisibilityOn( );
1428   actors->Render( 1e-3 );
1429 }
1430
1431 // -------------------------------------------------------------------------
1432 void cpExtensions::Visualization::ImageSliceActors::
1433 _LeaveCommand( void* data )
1434 {
1435   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
1436   if( actors == NULL )
1437     return;
1438
1439   actors->ResetCursor( );
1440   actors->m_CursorActor->VisibilityOff( );
1441   actors->Render( 1e-3 );
1442 }
1443
1444 // eof - $RCSfile$