]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageSliceActors.cxx
c9b8153e131c7480ac9f2144e90ce2447c070237
[cpPlugins.git] / lib / cpExtensions / Visualization / ImageSliceActors.cxx
1 #include <cpExtensions/Visualization/ImageSliceActors.h>
2
3 #include <sstream>
4
5 #include <vtkAlgorithmOutput.h>
6 #include <vtkCamera.h>
7 #include <vtkCellArray.h>
8 #include <vtkImageData.h>
9 #include <vtkInformation.h>
10 #include <vtkPlane.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 <vtkStreamingDemandDrivenPipeline.h>
18 #include <vtkTextProperty.h>
19
20 // -------------------------------------------------------------------------
21 cpExtensions::Visualization::ImageSliceActors*
22 cpExtensions::Visualization::ImageSliceActors::
23 New( )
24 {
25   return( new Self( ) );
26 }
27
28 // -------------------------------------------------------------------------
29 void cpExtensions::Visualization::ImageSliceActors::
30 AddInputConnection( vtkAlgorithmOutput* aout, int axis )
31 {
32   vtkSmartPointer< vtkImageSliceMapper > mapper =
33     vtkSmartPointer< vtkImageSliceMapper >::New( );
34   this->SliceMappers.push_back( mapper );
35   mapper->SetInputConnection( aout );
36   this->_ConfigureNewInput( axis );
37 }
38
39 // -------------------------------------------------------------------------
40 void cpExtensions::Visualization::ImageSliceActors::
41 AddInputData( vtkImageData* data, int axis )
42 {
43   vtkSmartPointer< vtkImageSliceMapper > mapper =
44     vtkSmartPointer< vtkImageSliceMapper >::New( );
45   this->SliceMappers.push_back( mapper );
46   mapper->SetInputData( data );
47   this->_ConfigureNewInput( axis );
48 }
49
50 // -------------------------------------------------------------------------
51 void cpExtensions::Visualization::ImageSliceActors::
52 Clear( )
53 {
54   // Unbind from container
55   this->RemoveAllItems( );
56
57   // Delete all images
58   this->SliceMappers.clear( );
59   this->ImageActors.clear( );
60   this->AssociatedActors.clear( );
61
62   // Reconfigure unique objects
63   this->Cursor = vtkSmartPointer< vtkPolyData >::New( );
64   this->CursorMapper = vtkSmartPointer< vtkPolyDataMapper >::New( );
65   this->CursorActor = vtkSmartPointer< vtkActor >::New( );
66   this->PlaneFunction = vtkSmartPointer< vtkPlane >::New( );
67   this->PlaneSource   = vtkSmartPointer< vtkPolyData >::New( );
68   this->PlaneMapper   = vtkSmartPointer< vtkPolyDataMapper >::New( );
69   this->TextActor     = vtkSmartPointer< vtkTextActor >::New( );
70   this->PlaneActor    = vtkSmartPointer< vtkActor >::New( );
71   this->TextBuffer[ 0 ] = '\0';
72
73   // Unique objects configuration
74   vtkSmartPointer< vtkPoints > cursor_points =
75     vtkSmartPointer< vtkPoints >::New( );
76   vtkSmartPointer< vtkCellArray > cursor_lines =
77     vtkSmartPointer< vtkCellArray >::New( );
78   cursor_points->InsertNextPoint( 0, 0, 0 );
79   cursor_points->InsertNextPoint( 0, 0, 0 );
80   cursor_points->InsertNextPoint( 0, 0, 0 );
81   cursor_points->InsertNextPoint( 0, 0, 0 );
82   cursor_lines->InsertNextCell( 2 );
83   cursor_lines->InsertCellPoint( 0 );
84   cursor_lines->InsertCellPoint( 1 );
85   cursor_lines->InsertNextCell( 2 );
86   cursor_lines->InsertCellPoint( 2 );
87   cursor_lines->InsertCellPoint( 3 );
88   this->Cursor->SetPoints( cursor_points );
89   this->Cursor->SetLines( cursor_lines );
90   this->CursorMapper->SetInputData( this->Cursor );
91   this->CursorActor->SetMapper( this->CursorMapper );
92
93   vtkSmartPointer< vtkPoints > plane_points =
94     vtkSmartPointer< vtkPoints >::New( );
95   vtkSmartPointer< vtkCellArray > plane_lines =
96     vtkSmartPointer< vtkCellArray >::New( );
97
98   plane_points->InsertNextPoint( 0, 0, 0 );
99   plane_points->InsertNextPoint( 0, 1, 0 );
100   plane_points->InsertNextPoint( 1, 1, 0 );
101   plane_points->InsertNextPoint( 1, 0, 0 );
102   plane_lines->InsertNextCell( 5 );
103   plane_lines->InsertCellPoint( 0 );
104   plane_lines->InsertCellPoint( 1 );
105   plane_lines->InsertCellPoint( 2 );
106   plane_lines->InsertCellPoint( 3 );
107   plane_lines->InsertCellPoint( 0 );
108   this->PlaneSource->SetPoints( plane_points );
109   this->PlaneSource->SetLines( plane_lines );
110
111   this->PlaneMapper->SetInputData( this->PlaneSource );
112   this->PlaneActor->SetMapper( this->PlaneMapper );
113
114   this->TextActor->SetTextScaleModeToNone( );
115   vtkTextProperty* textprop = this->TextActor->GetTextProperty( );
116   textprop->SetColor( 1, 1, 1 );
117   textprop->SetFontFamilyToCourier( );
118   textprop->SetFontSize( 18 );
119   textprop->BoldOff( );
120   textprop->ItalicOff( );
121   textprop->ShadowOff( );
122   textprop->SetJustificationToLeft( );
123   textprop->SetVerticalJustificationToBottom( );
124   vtkCoordinate* coord = this->TextActor->GetPositionCoordinate( );
125   coord->SetCoordinateSystemToNormalizedViewport( );
126   coord->SetValue( 0.01, 0.01 );
127 }
128
129 // -------------------------------------------------------------------------
130 vtkInteractorStyle* cpExtensions::Visualization::ImageSliceActors::
131 GetStyle( )
132 {
133   return( this->Style.GetPointer( ) );
134 }
135
136 // -------------------------------------------------------------------------
137 const vtkInteractorStyle* cpExtensions::Visualization::ImageSliceActors::
138 GetStyle( ) const
139 {
140   return( this->Style.GetPointer( ) );
141 }
142
143 // -------------------------------------------------------------------------
144 void cpExtensions::Visualization::ImageSliceActors::
145 PushActorsInto( vtkRenderWindow* window )
146 {
147   vtkRenderWindowInteractor* rwi = window->GetInteractor( );
148   vtkRenderer* renderer = window->GetRenderers( )->GetFirstRenderer( );
149
150   // Update style
151   if( rwi != NULL )
152   {
153     if( rwi->GetInteractorStyle( ) != this->Style.GetPointer( ) )
154       rwi->SetInteractorStyle( this->Style );
155
156   } // fi
157
158   if( renderer != NULL )
159   {
160     // Configure camera
161     vtkCamera* camera = renderer->GetActiveCamera( );
162     if( camera == NULL )
163       return;
164
165     // Parallel projections are better when displaying 2D images
166     int axis = this->GetAxis( );
167     camera->ParallelProjectionOn( );
168     camera->SetFocalPoint( double( 0 ), double( 0 ), double( 0 ) );
169     if( axis == 0 )
170     {
171       camera->SetPosition( double( 1 ), double( 0 ), double( 0 ) );
172       camera->SetViewUp  ( double( 0 ), double( 1 ), double( 0 ) );
173     }
174     else if( axis == 1 )
175     {
176       camera->SetPosition( double( 0 ), double( 1 ), double(  0 ) );
177       camera->SetViewUp  ( double( 0 ), double( 0 ), double( -1 ) );
178     }
179     else // if( axis == 2 )
180     {
181       camera->SetPosition( double( 0 ), double( 0 ), double( 1 ) );
182       camera->SetViewUp  ( double( 0 ), double( 1 ), double( 0 ) );
183
184     } // fi
185     renderer->ResetCamera( );
186
187     // Update actors
188     unsigned int N = this->GetNumberOfImageActors( );
189     for( unsigned int n = 0; n < N; ++n )
190       renderer->AddActor( this->GetImageActor( n ) );
191     renderer->AddActor( this->CursorActor );
192     renderer->AddActor( this->PlaneActor );
193     renderer->AddActor( this->TextActor );
194     renderer->Modified( );
195
196   } // fi
197 }
198
199 // -------------------------------------------------------------------------
200 void cpExtensions::Visualization::ImageSliceActors::
201 PopActorsFrom( vtkRenderWindow* window )
202 {
203   /*
204   unsigned int N = this->GetNumberOfImageActors( );
205   for( unsigned int n = 0; n < N; ++n )
206     renderer->RemoveActor( this->GetImageActor( n ) );
207   renderer->RemoveActor( this->GetTextActor( ) );
208   renderer->RemoveActor( this->GetPlaneActor( ) );
209   renderer->Modified( );
210   */
211 }
212
213 // -------------------------------------------------------------------------
214 unsigned int cpExtensions::Visualization::ImageSliceActors::
215 GetNumberOfImageActors( ) const
216 {
217   return( this->ImageActors.size( ) );
218 }
219
220 // -------------------------------------------------------------------------
221 vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
222 GetImageActor( unsigned int id )
223 {
224   if( id < this->ImageActors.size( ) )
225     return( this->ImageActors[ id ] );
226   else
227     return( NULL );
228 }
229
230 // -------------------------------------------------------------------------
231 const vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
232 GetImageActor( unsigned int id ) const
233 {
234   if( id < this->ImageActors.size( ) )
235     return( this->ImageActors[ id ] );
236   else
237     return( NULL );
238 }
239
240 // -------------------------------------------------------------------------
241 vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
242 GetTextActor( )
243 {
244   return( this->TextActor );
245 }
246
247 // -------------------------------------------------------------------------
248 const vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
249 GetTextActor( ) const
250 {
251   return( this->TextActor );
252 }
253
254 // -------------------------------------------------------------------------
255 vtkActor* cpExtensions::Visualization::ImageSliceActors::
256 GetPlaneActor( )
257 {
258   return( this->PlaneActor );
259 }
260
261 // -------------------------------------------------------------------------
262 const vtkActor* cpExtensions::Visualization::ImageSliceActors::
263 GetPlaneActor( ) const
264 {
265   return( this->PlaneActor );
266 }
267
268 // -------------------------------------------------------------------------
269 vtkPlane* cpExtensions::Visualization::ImageSliceActors::
270 GetPlaneFunction( )
271 {
272   return( this->PlaneFunction );
273 }
274
275 // -------------------------------------------------------------------------
276 const vtkPlane* cpExtensions::Visualization::ImageSliceActors::
277 GetPlaneFunction( ) const
278 {
279   return( this->PlaneFunction );
280 }
281
282 // -------------------------------------------------------------------------
283 void cpExtensions::Visualization::ImageSliceActors::
284 AddActor( vtkAlgorithm* algorithm, vtkActor* actor )
285 {
286   this->AssociatedActors.push_back( TAssociatedActor( algorithm, actor ) );
287   this->AddItem( actor );
288 }
289
290 // -------------------------------------------------------------------------
291 void cpExtensions::Visualization::ImageSliceActors::
292 AddActor( vtkActor* actor )
293 {
294   this->AddActor( NULL, actor );
295 }
296
297 // -------------------------------------------------------------------------
298 void cpExtensions::Visualization::ImageSliceActors::
299 SetInterpolate( bool v )
300 {
301   if( this->Interpolate != v )
302   {
303     for( unsigned int i = 0; i < this->ImageActors.size( ); ++i )
304       this->ImageActors[ i ]->SetInterpolate( v );
305     this->Interpolate = v;
306     this->Modified( );
307
308   } // fi
309 }
310
311 // -------------------------------------------------------------------------
312 void cpExtensions::Visualization::ImageSliceActors::
313 InterpolateOn( )
314 {
315   this->SetInterpolate( true );
316 }
317
318 // -------------------------------------------------------------------------
319 void cpExtensions::Visualization::ImageSliceActors::
320 InterpolateOff( )
321 {
322   this->SetInterpolate( false );
323 }
324
325 // -------------------------------------------------------------------------
326 double* cpExtensions::Visualization::ImageSliceActors::
327 GetDisplayBounds( ) const
328 {
329   if( this->ImageActors.size( ) > 0 )
330     return( this->ImageActors[ 0 ]->GetDisplayBounds( ) );
331   else
332     return( NULL );
333 }
334
335 // -------------------------------------------------------------------------
336 void cpExtensions::Visualization::ImageSliceActors::
337 GetDisplayBounds( double bounds[ 6 ] ) const
338 {
339   if( this->ImageActors.size( ) == 0 )
340   {
341     bounds[ 0 ] = bounds[ 2 ] = bounds[ 4 ] = double( -1 );
342     bounds[ 1 ] = bounds[ 3 ] = bounds[ 5 ] = double( -1 );
343   }
344   else
345     this->ImageActors[ 0 ]->GetDisplayBounds( bounds );
346 }
347
348 // -------------------------------------------------------------------------
349 void cpExtensions::Visualization::ImageSliceActors::
350 ResetCursor( )
351 {
352   vtkPoints* points = this->Cursor->GetPoints( );
353   points->SetPoint( 0, 0, 0, 0 );
354   points->SetPoint( 1, 0, 0, 0 );
355   points->SetPoint( 2, 0, 0, 0 );
356   points->SetPoint( 3, 0, 0, 0 );
357   this->Cursor->Modified( );
358   this->CursorMapper->Modified( );
359   this->CursorActor->Modified( );
360 }
361
362 // -------------------------------------------------------------------------
363 void cpExtensions::Visualization::ImageSliceActors::
364 SetCursor( double pos[ 3 ] )
365 {
366   if( this->SliceMappers.size( ) == 0 )
367     return;
368
369   int a0 = this->GetAxis( );
370   int a1 = ( a0 + 1 ) % 3;
371   int a2 = ( a0 + 2 ) % 3;
372
373   double bounds[ 6 ];
374   this->SliceMappers[ 0 ]->GetBounds( bounds );
375
376   double p0[ 3 ], p1[ 3 ], p2[ 3 ], p3[ 3 ];
377   p0[ a0 ] = p1[ a0 ] = p2[ a0 ] = p3[ a0 ] = pos[ a0 ];
378   p0[ a2 ] = p1[ a2 ] = pos[ a2 ];
379   p2[ a1 ] = p3[ a1 ] = pos[ a1 ];
380   p0[ a1 ] = bounds[ a1 << 1 ];
381   p1[ a1 ] = bounds[ ( a1 << 1 ) + 1 ];
382   p2[ a2 ] = bounds[ a2 << 1 ];
383   p3[ a2 ] = bounds[ ( a2 << 1 ) + 1 ];
384
385   vtkPoints* points = this->Cursor->GetPoints( );
386   points->SetPoint( 0, p0 );
387   points->SetPoint( 1, p1 );
388   points->SetPoint( 2, p2 );
389   points->SetPoint( 3, p3 );
390   this->Cursor->Modified( );
391   this->CursorMapper->Modified( );
392   this->CursorActor->Modified( );
393 }
394
395 // -------------------------------------------------------------------------
396 int cpExtensions::Visualization::ImageSliceActors::
397 GetAxis( ) const
398 {
399   if( this->SliceMappers.size( ) > 0 )
400     return( this->SliceMappers[ 0 ]->GetOrientation( ) );
401   else
402     return( -1 );
403 }
404
405 // -------------------------------------------------------------------------
406 int cpExtensions::Visualization::ImageSliceActors::
407 GetSliceNumber( ) const
408 {
409   if( this->SliceMappers.size( ) > 0 )
410     return( this->SliceMappers[ 0 ]->GetSliceNumber( ) );
411   else
412     return( -1 );
413 }
414
415 // -------------------------------------------------------------------------
416 int cpExtensions::Visualization::ImageSliceActors::
417 GetSliceNumberMinValue( ) const
418 {
419   if( this->SliceMappers.size( ) > 0 )
420     return( this->SliceMappers[ 0 ]->GetSliceNumberMinValue( ) );
421   else
422     return( -1 );
423 }
424
425 // -------------------------------------------------------------------------
426 int cpExtensions::Visualization::ImageSliceActors::
427 GetSliceNumberMaxValue( ) const
428 {
429   if( this->SliceMappers.size( ) > 0 )
430     return( this->SliceMappers[ 0 ]->GetSliceNumberMaxValue( ) );
431   else
432     return( -1 );
433 }
434
435 // -------------------------------------------------------------------------
436 void cpExtensions::Visualization::ImageSliceActors::
437 SetSliceNumber( const int& slice )
438 {
439   unsigned int nImages = this->SliceMappers.size( );
440   if( nImages == 0 )
441     return;
442
443   // Change visualization extent
444   for( unsigned int i = 0; i < nImages; ++i )
445   {
446     this->SliceMappers[ i ]->SetSliceNumber( slice );
447     this->SliceMappers[ i ]->Modified( );
448     this->ImageActors[ i ]->Modified( );
449     this->SliceMappers[ i ]->Update( );
450
451   } // rof
452
453   // Compute plane
454   vtkAlgorithm* algo = this->SliceMappers[ 0 ]->GetInputAlgorithm( );
455   vtkInformation* info = algo->GetOutputInformation( 0 );
456   int ext[ 6 ];
457   double ori[ 3 ], spac[ 3 ], pos[ 3 ];
458   info->Get( vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT( ), ext );
459   info->Get( vtkDataObject::ORIGIN( ), ori );
460   info->Get( vtkDataObject::SPACING( ), spac );
461   this->SliceMappers[ 0 ]->GetSlicePlane( )->GetOrigin( pos );
462
463   // Prevent obscuring voxels by offsetting the plane geometry
464   double xbnds[ ] =
465     {
466       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 0 ] ) ),
467       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 1 ] ) )
468     };
469   double ybnds[ ] =
470     {
471       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 2 ] ) ),
472       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 3 ] ) )
473     };
474   double zbnds[ ] =
475     {
476       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 4 ] ) ),
477       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 5 ] ) )
478     };
479
480   if( spac[ 0 ] < double( 0 ) )
481   {
482     double t = xbnds[ 0 ];
483     xbnds[ 0 ] = xbnds[ 1 ];
484     xbnds[ 1 ] = t;
485
486   } // fi
487   if( spac[ 1 ] < double( 0 ) )
488   {
489     double t = ybnds[ 0 ];
490     ybnds[ 0 ] = ybnds[ 1 ];
491     ybnds[ 1 ] = t;
492
493   } // fi
494   if( spac[ 2 ] < double( 0 ) )
495   {
496     double t = zbnds[ 0 ];
497     zbnds[ 0 ] = zbnds[ 1 ];
498     zbnds[ 1 ] = t;
499
500   } // fi
501
502   // Plane function origin
503   this->PlaneFunction->SetOrigin( pos );
504
505   // Configure visualization and implicit plane orientation
506   int axis = this->SliceMappers[ 0 ]->GetOrientation( );
507   this->PlaneActor->GetProperty( )->SetRepresentationToWireframe( );
508   this->PlaneActor->GetProperty( )->SetLineWidth( 2 );
509   vtkPoints* plane_points = this->PlaneSource->GetPoints( );
510   if( axis == 0 ) // YZ, x-normal
511   {
512     this->PlaneFunction->SetNormal( 1, 0, 0 );
513     plane_points->SetPoint( 0, pos[ 0 ], ybnds[ 0 ], zbnds[ 0 ] );
514     plane_points->SetPoint( 1, pos[ 0 ], ybnds[ 1 ], zbnds[ 0 ] );
515     plane_points->SetPoint( 2, pos[ 0 ], ybnds[ 1 ], zbnds[ 1 ] );
516     plane_points->SetPoint( 3, pos[ 0 ], ybnds[ 0 ], zbnds[ 1 ] );
517     this->PlaneActor->GetProperty( )->SetColor( 1, 0, 0 );
518   }
519   else if( axis == 1 ) // ZX, y-normal
520   {
521     this->PlaneFunction->SetNormal( 0, 1, 0 );
522     plane_points->SetPoint( 0, xbnds[ 0 ], pos[ 1 ], zbnds[ 0 ] );
523     plane_points->SetPoint( 1, xbnds[ 0 ], pos[ 1 ], zbnds[ 1 ] );
524     plane_points->SetPoint( 2, xbnds[ 1 ], pos[ 1 ], zbnds[ 1 ] );
525     plane_points->SetPoint( 3, xbnds[ 1 ], pos[ 1 ], zbnds[ 0 ] );
526     this->PlaneActor->GetProperty( )->SetColor( 0, 1, 0 );
527   }
528   else // XY, z-normal
529   {
530     this->PlaneFunction->SetNormal( 0, 0, 1 );
531     plane_points->SetPoint( 0, xbnds[ 0 ], ybnds[ 0 ], pos[ 2 ] );
532     plane_points->SetPoint( 1, xbnds[ 1 ], ybnds[ 0 ], pos[ 2 ] );
533     plane_points->SetPoint( 2, xbnds[ 1 ], ybnds[ 1 ], pos[ 2 ] );
534     plane_points->SetPoint( 3, xbnds[ 0 ], ybnds[ 1 ], pos[ 2 ] );
535     this->PlaneActor->GetProperty( )->SetColor( 0, 0, 1 );
536
537   } // fi
538   this->PlaneFunction->Modified( );
539   this->PlaneSource->Modified( );
540   this->PlaneMapper->Modified( );
541   this->PlaneActor->Modified( );
542
543   // Prepare other actors to update
544   /* TODO
545      for( unsigned int i = 0; i < this->OtherActors.size( ); ++i )
546      {
547      if( this->OtherActors[ i ].first.GetPointer( ) != NULL )
548      {
549      this->OtherActors[ i ].first->Modified( );
550      this->OtherActors[ i ].first->Update( );
551
552      } // fi
553
554      if( this->OtherActors[ i ].second.GetPointer( ) != NULL )
555      {
556      this->OtherActors[ i ].second->GetMapper( )->Modified( );
557      this->OtherActors[ i ].second->Modified( );
558
559      } // fi
560
561      } // rof
562
563      if( this->m_UpdateCommand != NULL )
564      this->m_UpdateCommand( this->m_UpdateData );
565   */
566
567   // Update text
568   this->UpdateText( );
569 }
570
571 // -------------------------------------------------------------------------
572 void cpExtensions::Visualization::ImageSliceActors::
573 UpdateText( )
574 {
575   if( this->SliceMappers.size( ) > 0 )
576   {
577     char axis;
578     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
579     if     ( axId == 0 ) axis = 'X';
580     else if( axId == 1 ) axis = 'Y';
581     else if( axId == 2 ) axis = 'Z';
582
583     std::sprintf(
584       this->TextBuffer, "Axis: %c (%d)",
585       axis, this->SliceMappers[ 0 ]->GetSliceNumber( )
586       );
587   }
588   else
589     this->TextBuffer[ 0 ] = '\0';
590   this->TextActor->SetInput( this->TextBuffer );
591   this->TextActor->Modified( );
592   this->Modified( );
593 }
594
595 // -------------------------------------------------------------------------
596 void cpExtensions::Visualization::ImageSliceActors::
597 UpdateText( double pos[ 3 ] )
598 {
599   if( this->SliceMappers.size( ) > 0 )
600   {
601     char axis;
602     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
603     if     ( axId == 0 ) axis = 'X';
604     else if( axId == 1 ) axis = 'Y';
605     else if( axId == 2 ) axis = 'Z';
606     int slice = this->GetSliceNumber( );
607
608     vtkImageData* image = this->SliceMappers[ 0 ]->GetInput( );
609
610     int ijk[ 3 ];
611     double pcoords[ 3 ];
612     image->ComputeStructuredCoordinates( pos, ijk, pcoords );
613     ijk[ axId ] = slice;
614
615     int ext[ 6 ];
616     image->GetExtent( ext );
617     if(
618       ext[ 0 ] <= ijk[ 0 ] && ijk[ 0 ] <= ext[ 1 ] &&
619       ext[ 2 ] <= ijk[ 1 ] && ijk[ 1 ] <= ext[ 3 ] &&
620       ext[ 4 ] <= ijk[ 2 ] && ijk[ 2 ] <= ext[ 5 ]
621       )
622     {
623       int nScl = image->GetNumberOfScalarComponents( );
624       std::stringstream str;
625       str
626         << "[" << ijk[ 0 ]
627         << "," << ijk[ 1 ]
628         << "," << ijk[ 2 ] << "]=(";
629       str <<
630         image->GetScalarComponentAsFloat( ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], 0 );
631       for( int n = 1; n < nScl; ++n )
632         str
633           << " "
634           << image->GetScalarComponentAsFloat(
635             ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], n
636             );
637       str << ")";
638       std::sprintf(
639         this->TextBuffer, "Axis: %c (%d) | Pixel %s",
640         axis, slice, str.str( ).c_str( )
641         );
642
643     } // fi
644   }
645   else
646     this->TextBuffer[ 0 ] = '\0';
647   this->TextActor->SetInput( this->TextBuffer );
648   this->TextActor->Modified( );
649   this->Modified( );
650 }
651
652 // -------------------------------------------------------------------------
653 void cpExtensions::Visualization::ImageSliceActors::
654 UpdateText( const double& w, const double& l )
655 {
656   if( this->SliceMappers.size( ) > 0 )
657   {
658     char axis;
659     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
660     if     ( axId == 0 ) axis = 'X';
661     else if( axId == 1 ) axis = 'Y';
662     else if( axId == 2 ) axis = 'Z';
663
664     std::sprintf(
665       this->TextBuffer, "Axis: %c (%d) | W/L (%.2f/%.2f)",
666       axis, this->SliceMappers[ 0 ]->GetSliceNumber( ), w, l
667       );
668   }
669   else
670     this->TextBuffer[ 0 ] = '\0';
671   this->TextActor->SetInput( this->TextBuffer );
672   this->TextActor->Modified( );
673   this->Modified( );
674 }
675
676 // -------------------------------------------------------------------------
677 cpExtensions::Visualization::ImageSliceActors::
678 ImageSliceActors( )
679   : Superclass( ),
680     Interpolate( false )
681 {
682   // Connect this view with a controller
683   this->Style = vtkSmartPointer< ImageInteractorStyle >::New( );
684   this->Style->AssociateView( this );
685   this->Style->SetMouseMoveCommand( Self::_MouseMoveCommand );
686   this->Style->SetMouseClickCommand( Self::_MouseClickCommand );
687   this->Style->SetMouseDoubleClickCommand( Self::_MouseDoubleClickCommand );
688   this->Style->SetMouseWheelCommand( Self::_MouseWheelCommand );
689   this->Style->SetKeyCommand( Self::_KeyCommand );
690
691   this->Clear( );
692 }
693
694 // -------------------------------------------------------------------------
695 cpExtensions::Visualization::ImageSliceActors::
696 ~ImageSliceActors( )
697 {
698 }
699
700 // -------------------------------------------------------------------------
701 void cpExtensions::Visualization::ImageSliceActors::
702 _ConfigureNewInput( int axis )
703 {
704   unsigned int nImages = this->ImageActors.size( );
705
706   // Configure mapper
707   vtkImageSliceMapper* mapper = this->SliceMappers[ nImages ];
708   if( nImages == 0 )
709     mapper->SetOrientation( axis );
710   else
711     mapper->SetOrientation( this->SliceMappers[ 0 ]->GetOrientation( ) );
712   mapper->Update( );
713
714   // Create actor
715   vtkSmartPointer< vtkImageActor > actor =
716     vtkSmartPointer< vtkImageActor >::New( );
717   this->ImageActors.push_back( actor );
718   actor->SetMapper( mapper );
719   actor->SetInterpolate( this->Interpolate );
720   actor->Modified( );
721
722   if( nImages == 0 )
723   {
724     this->AddItem( this->CursorActor );
725     this->AddItem( this->PlaneActor );
726     this->AddItem( this->TextActor );
727     this->Style->AssociateImageActor( actor );
728
729   } // fi
730   this->AddItem( actor );
731
732   if( nImages > 1 )
733     this->SetSliceNumber( this->GetSliceNumber( ) );
734   this->Modified( );
735 }
736
737 // -------------------------------------------------------------------------
738 void cpExtensions::Visualization::ImageSliceActors::
739 _MouseMoveCommand(
740   void* data,
741   const ImageInteractorStyle::ButtonID& btn, double* pos,
742   bool alt, bool ctr, bool sft
743   )
744 {
745   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
746   if( actors == NULL )
747     return;
748
749   if( btn == ImageInteractorStyle::ButtonID_None )
750   {
751     actors->UpdateText( pos );
752   }
753   else if( btn == ImageInteractorStyle::ButtonID_Left )
754   {
755   }
756   else if( btn == ImageInteractorStyle::ButtonID_Middle )
757   {
758   }
759   else if( btn == ImageInteractorStyle::ButtonID_Right )
760   {
761   } // fi
762 }
763
764 // -------------------------------------------------------------------------
765 void cpExtensions::Visualization::ImageSliceActors::
766 _MouseClickCommand(
767   void* data,
768   const ImageInteractorStyle::ButtonID& btn, double* pos,
769   bool alt, bool ctr, bool sft
770   )
771 {
772 }
773
774 // -------------------------------------------------------------------------
775 void cpExtensions::Visualization::ImageSliceActors::
776 _MouseDoubleClickCommand(
777   void* data,
778   const ImageInteractorStyle::ButtonID& btn, double* pos,
779   bool alt, bool ctr, bool sft
780   )
781 {
782   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
783   if( actors == NULL )
784     return;
785
786   if( btn == ImageInteractorStyle::ButtonID_Left )
787   {
788     if( !alt && !ctr && !sft )
789     {
790       actors->SetCursor( pos );
791
792     } // fi
793   }
794   else if( btn == ImageInteractorStyle::ButtonID_Middle )
795   {
796   }
797   else if( btn == ImageInteractorStyle::ButtonID_Right )
798   {
799   } // fi
800 }
801
802 // -------------------------------------------------------------------------
803 void cpExtensions::Visualization::ImageSliceActors::
804 _MouseWheelCommand(
805   void* data,
806   const int& dir, bool alt, bool ctr, bool sft
807   )
808 {
809   ImageSliceActors* actors = reinterpret_cast< ImageSliceActors* >( data );
810   if( actors == NULL )
811     return;
812
813   if( !alt && !ctr && !sft )
814   {
815     actors->SetSliceNumber( actors->GetSliceNumber( ) + dir );
816   }
817   else if( !alt && !ctr && sft )
818   {
819     actors->SetSliceNumber( actors->GetSliceNumber( ) + ( dir * 10 ) );
820
821   } // fi
822 }
823
824 // -------------------------------------------------------------------------
825 void cpExtensions::Visualization::ImageSliceActors::
826 _KeyCommand(
827   void* data,
828   const char& key
829   )
830 {
831 }
832
833 // eof - $RCSfile$