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