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