]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageSliceActors.cxx
469f270f6b7df5886232ed7601f339c857579110
[cpPlugins.git] / lib / cpExtensions / Visualization / ImageSliceActors.cxx
1 #include <cpExtensions/Visualization/ImageSliceActors.h>
2
3 #include <vtkAlgorithmOutput.h>
4 #include <vtkCellArray.h>
5 #include <vtkImageData.h>
6 #include <vtkInformation.h>
7 #include <vtkPlane.h>
8 #include <vtkPoints.h>
9 #include <vtkProperty.h>
10 #include <vtkStreamingDemandDrivenPipeline.h>
11 #include <vtkTextProperty.h>
12
13 // -------------------------------------------------------------------------
14 cpExtensions::Visualization::ImageSliceActors*
15 cpExtensions::Visualization::ImageSliceActors::
16 New( )
17 {
18   return( new Self( ) );
19 }
20
21 // -------------------------------------------------------------------------
22 void cpExtensions::Visualization::ImageSliceActors::
23 AddInputConnection( vtkAlgorithmOutput* aout, int axis )
24 {
25   vtkSmartPointer< vtkImageSliceMapper > mapper =
26     vtkSmartPointer< vtkImageSliceMapper >::New( );
27   this->SliceMappers.push_back( mapper );
28   mapper->SetInputConnection( aout );
29   this->_ConfigureNewInput( axis );
30 }
31
32 // -------------------------------------------------------------------------
33 void cpExtensions::Visualization::ImageSliceActors::
34 AddInputData( vtkImageData* data, int axis )
35 {
36   vtkSmartPointer< vtkImageSliceMapper > mapper =
37     vtkSmartPointer< vtkImageSliceMapper >::New( );
38   this->SliceMappers.push_back( mapper );
39   mapper->SetInputData( data );
40   this->_ConfigureNewInput( axis );
41 }
42
43 // -------------------------------------------------------------------------
44 void cpExtensions::Visualization::ImageSliceActors::
45 Clear( )
46 {
47   // Unbind from container
48   this->RemoveAllItems( );
49
50   // Delete all images
51   this->SliceMappers.clear( );
52   this->ImageActors.clear( );
53   this->OtherActors.clear( );
54
55   // Reconfigure unique objects
56   this->PlaneFunction = vtkSmartPointer< vtkPlane >::New( );
57   this->PlaneSource   = vtkSmartPointer< vtkPolyData >::New( );
58   this->PlaneMapper   = vtkSmartPointer< vtkPolyDataMapper >::New( );
59   this->TextActor     = vtkSmartPointer< vtkTextActor >::New( );
60   this->PlaneActor    = vtkSmartPointer< vtkActor >::New( );
61   this->TextBuffer[ 0 ] = '\0';
62
63   // Unique objects configuration
64   vtkSmartPointer< vtkPoints > plane_points =
65     vtkSmartPointer< vtkPoints >::New( );
66   vtkSmartPointer< vtkCellArray > plane_lines =
67     vtkSmartPointer< vtkCellArray >::New( );
68
69   plane_points->InsertNextPoint( 0, 0, 0 );
70   plane_points->InsertNextPoint( 0, 1, 0 );
71   plane_points->InsertNextPoint( 1, 1, 0 );
72   plane_points->InsertNextPoint( 1, 0, 0 );
73   plane_lines->InsertNextCell( 5 );
74   plane_lines->InsertCellPoint( 0 );
75   plane_lines->InsertCellPoint( 1 );
76   plane_lines->InsertCellPoint( 2 );
77   plane_lines->InsertCellPoint( 3 );
78   plane_lines->InsertCellPoint( 0 );
79   this->PlaneSource->SetPoints( plane_points );
80   this->PlaneSource->SetLines( plane_lines );
81
82   this->PlaneMapper->SetInputData( this->PlaneSource );
83   this->PlaneActor->SetMapper( this->PlaneMapper );
84
85   this->TextActor->SetTextScaleModeToNone( );
86   vtkTextProperty* textprop = this->TextActor->GetTextProperty( );
87   textprop->SetColor( 1, 1, 1 );
88   textprop->SetFontFamilyToCourier( );
89   textprop->SetFontSize( 18 );
90   textprop->BoldOff( );
91   textprop->ItalicOff( );
92   textprop->ShadowOff( );
93   textprop->SetJustificationToLeft( );
94   textprop->SetVerticalJustificationToBottom( );
95   vtkCoordinate* coord = this->TextActor->GetPositionCoordinate( );
96   coord->SetCoordinateSystemToNormalizedViewport( );
97   coord->SetValue( 0.01, 0.01 );
98 }
99
100 // -------------------------------------------------------------------------
101 unsigned int cpExtensions::Visualization::ImageSliceActors::
102 GetNumberOfImageActors( ) const
103 {
104   return( this->ImageActors.size( ) );
105 }
106
107 // -------------------------------------------------------------------------
108 vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
109 GetImageActor( unsigned int id )
110 {
111   if( id < this->ImageActors.size( ) )
112     return( this->ImageActors[ id ] );
113   else
114     return( NULL );
115 }
116
117 // -------------------------------------------------------------------------
118 const vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
119 GetImageActor( unsigned int id ) const
120 {
121   if( id < this->ImageActors.size( ) )
122     return( this->ImageActors[ id ] );
123   else
124     return( NULL );
125 }
126
127 // -------------------------------------------------------------------------
128 vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
129 GetTextActor( )
130 {
131   return( this->TextActor );
132 }
133
134 // -------------------------------------------------------------------------
135 const vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
136 GetTextActor( ) const
137 {
138   return( this->TextActor );
139 }
140
141 // -------------------------------------------------------------------------
142 vtkActor* cpExtensions::Visualization::ImageSliceActors::
143 GetPlaneActor( )
144 {
145   return( this->PlaneActor );
146 }
147
148 // -------------------------------------------------------------------------
149 const vtkActor* cpExtensions::Visualization::ImageSliceActors::
150 GetPlaneActor( ) const
151 {
152   return( this->PlaneActor );
153 }
154
155 // -------------------------------------------------------------------------
156 vtkPlane* cpExtensions::Visualization::ImageSliceActors::
157 GetPlaneFunction( )
158 {
159   return( this->PlaneFunction );
160 }
161
162 // -------------------------------------------------------------------------
163 const vtkPlane* cpExtensions::Visualization::ImageSliceActors::
164 GetPlaneFunction( ) const
165 {
166   return( this->PlaneFunction );
167 }
168
169 // -------------------------------------------------------------------------
170 void cpExtensions::Visualization::ImageSliceActors::
171 AddActor( vtkAlgorithm* algorithm, vtkActor* actor )
172 {
173   this->OtherActors.push_back( TActorPair( algorithm, actor ) );
174   this->AddItem( actor );
175 }
176
177 // -------------------------------------------------------------------------
178 void cpExtensions::Visualization::ImageSliceActors::
179 AddActor( vtkActor* actor )
180 {
181   this->AddActor( NULL, actor );
182 }
183
184 // -------------------------------------------------------------------------
185 void cpExtensions::Visualization::ImageSliceActors::
186 SetInterpolate( bool v )
187 {
188   if( this->Interpolate != v )
189   {
190     for( unsigned int i = 0; i < this->ImageActors.size( ); ++i )
191       this->ImageActors[ i ]->SetInterpolate( v );
192     this->Interpolate = v;
193     this->Modified( );
194
195   } // fi
196 }
197
198 // -------------------------------------------------------------------------
199 void cpExtensions::Visualization::ImageSliceActors::
200 InterpolateOn( )
201 {
202   this->SetInterpolate( true );
203 }
204
205 // -------------------------------------------------------------------------
206 void cpExtensions::Visualization::ImageSliceActors::
207 InterpolateOff( )
208 {
209   this->SetInterpolate( false );
210 }
211
212 // -------------------------------------------------------------------------
213 double* cpExtensions::Visualization::ImageSliceActors::
214 GetDisplayBounds( ) const
215 {
216   if( this->ImageActors.size( ) > 0 )
217     return( this->ImageActors[ 0 ]->GetDisplayBounds( ) );
218   else
219     return( NULL );
220 }
221
222 // -------------------------------------------------------------------------
223 void cpExtensions::Visualization::ImageSliceActors::
224 GetDisplayBounds( double bounds[ 6 ] ) const
225 {
226   if( this->ImageActors.size( ) == 0 )
227   {
228     bounds[ 0 ] = bounds[ 2 ] = bounds[ 4 ] = double( -1 );
229     bounds[ 1 ] = bounds[ 3 ] = bounds[ 5 ] = double( -1 );
230   }
231   else
232     this->ImageActors[ 0 ]->GetDisplayBounds( bounds );
233 }
234
235 // -------------------------------------------------------------------------
236 int cpExtensions::Visualization::ImageSliceActors::
237 GetAxis( ) const
238 {
239   if( this->SliceMappers.size( ) > 0 )
240     return( this->SliceMappers[ 0 ]->GetOrientation( ) );
241   else
242     return( -1 );
243 }
244
245 // -------------------------------------------------------------------------
246 int cpExtensions::Visualization::ImageSliceActors::
247 GetSliceNumber( ) const
248 {
249   if( this->SliceMappers.size( ) > 0 )
250     return( this->SliceMappers[ 0 ]->GetSliceNumber( ) );
251   else
252     return( -1 );
253 }
254
255 // -------------------------------------------------------------------------
256 int cpExtensions::Visualization::ImageSliceActors::
257 GetSliceNumberMinValue( ) const
258 {
259   if( this->SliceMappers.size( ) > 0 )
260     return( this->SliceMappers[ 0 ]->GetSliceNumberMinValue( ) );
261   else
262     return( -1 );
263 }
264
265 // -------------------------------------------------------------------------
266 int cpExtensions::Visualization::ImageSliceActors::
267 GetSliceNumberMaxValue( ) const
268 {
269   if( this->SliceMappers.size( ) > 0 )
270     return( this->SliceMappers[ 0 ]->GetSliceNumberMaxValue( ) );
271   else
272     return( -1 );
273 }
274
275 // -------------------------------------------------------------------------
276 void cpExtensions::Visualization::ImageSliceActors::
277 SetSliceNumber( const int& slice )
278 {
279   unsigned int nImages = this->SliceMappers.size( );
280   if( nImages == 0 )
281     return;
282
283   // Change visualization extent
284   for( unsigned int i = 0; i < nImages; ++i )
285   {
286     this->SliceMappers[ i ]->SetSliceNumber( slice );
287     this->SliceMappers[ i ]->Modified( );
288     this->ImageActors[ i ]->Modified( );
289     this->SliceMappers[ i ]->Update( );
290
291   } // rof
292
293   // Compute plane
294   vtkAlgorithm* algo = this->SliceMappers[ 0 ]->GetInputAlgorithm( );
295   vtkInformation* info = algo->GetOutputInformation( 0 );
296   int ext[ 6 ];
297   double ori[ 3 ], spac[ 3 ], pos[ 3 ];
298   info->Get( vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT( ), ext );
299   info->Get( vtkDataObject::ORIGIN( ), ori );
300   info->Get( vtkDataObject::SPACING( ), spac );
301   this->SliceMappers[ 0 ]->GetSlicePlane( )->GetOrigin( pos );
302
303   // Prevent obscuring voxels by offsetting the plane geometry
304   double xbnds[ ] =
305     {
306       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 0 ] ) ),
307       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 1 ] ) )
308     };
309   double ybnds[ ] =
310     {
311       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 2 ] ) ),
312       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 3 ] ) )
313     };
314   double zbnds[ ] =
315     {
316       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 4 ] ) ),
317       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 5 ] ) )
318     };
319
320   if( spac[ 0 ] < double( 0 ) )
321   {
322     double t = xbnds[ 0 ];
323     xbnds[ 0 ] = xbnds[ 1 ];
324     xbnds[ 1 ] = t;
325
326   } // fi
327   if( spac[ 1 ] < double( 0 ) )
328   {
329     double t = ybnds[ 0 ];
330     ybnds[ 0 ] = ybnds[ 1 ];
331     ybnds[ 1 ] = t;
332
333   } // fi
334   if( spac[ 2 ] < double( 0 ) )
335   {
336     double t = zbnds[ 0 ];
337     zbnds[ 0 ] = zbnds[ 1 ];
338     zbnds[ 1 ] = t;
339
340   } // fi
341
342   // Plane function origin
343   this->PlaneFunction->SetOrigin( pos );
344
345   // Configure visualization and implicit plane orientation
346   int axis = this->SliceMappers[ 0 ]->GetOrientation( );
347   this->PlaneActor->GetProperty( )->SetRepresentationToWireframe( );
348   this->PlaneActor->GetProperty( )->SetLineWidth( 2 );
349   vtkPoints* plane_points = this->PlaneSource->GetPoints( );
350   if( axis == 0 ) // YZ, x-normal
351   {
352     this->PlaneFunction->SetNormal( 1, 0, 0 );
353     plane_points->SetPoint( 0, pos[ 0 ], ybnds[ 0 ], zbnds[ 0 ] );
354     plane_points->SetPoint( 1, pos[ 0 ], ybnds[ 1 ], zbnds[ 0 ] );
355     plane_points->SetPoint( 2, pos[ 0 ], ybnds[ 1 ], zbnds[ 1 ] );
356     plane_points->SetPoint( 3, pos[ 0 ], ybnds[ 0 ], zbnds[ 1 ] );
357     this->PlaneActor->GetProperty( )->SetColor( 1, 0, 0 );
358   }
359   else if( axis == 1 ) // ZX, y-normal
360   {
361     this->PlaneFunction->SetNormal( 0, 1, 0 );
362     plane_points->SetPoint( 0, xbnds[ 0 ], pos[ 1 ], zbnds[ 0 ] );
363     plane_points->SetPoint( 1, xbnds[ 0 ], pos[ 1 ], zbnds[ 1 ] );
364     plane_points->SetPoint( 2, xbnds[ 1 ], pos[ 1 ], zbnds[ 1 ] );
365     plane_points->SetPoint( 3, xbnds[ 1 ], pos[ 1 ], zbnds[ 0 ] );
366     this->PlaneActor->GetProperty( )->SetColor( 0, 1, 0 );
367   }
368   else // XY, z-normal
369   {
370     this->PlaneFunction->SetNormal( 0, 0, 1 );
371     plane_points->SetPoint( 0, xbnds[ 0 ], ybnds[ 0 ], pos[ 2 ] );
372     plane_points->SetPoint( 1, xbnds[ 1 ], ybnds[ 0 ], pos[ 2 ] );
373     plane_points->SetPoint( 2, xbnds[ 1 ], ybnds[ 1 ], pos[ 2 ] );
374     plane_points->SetPoint( 3, xbnds[ 0 ], ybnds[ 1 ], pos[ 2 ] );
375     this->PlaneActor->GetProperty( )->SetColor( 0, 0, 1 );
376
377   } // fi
378   this->PlaneFunction->Modified( );
379   this->PlaneSource->Modified( );
380   this->PlaneMapper->Modified( );
381   this->PlaneActor->Modified( );
382
383   // Prepare other actors to update
384   for( unsigned int i = 0; i < this->OtherActors.size( ); ++i )
385   {
386     if( this->OtherActors[ i ].first.GetPointer( ) != NULL )
387     {
388       this->OtherActors[ i ].first->Modified( );
389       this->OtherActors[ i ].first->Update( );
390
391     } // fi
392
393     if( this->OtherActors[ i ].second.GetPointer( ) != NULL )
394     {
395       this->OtherActors[ i ].second->GetMapper( )->Modified( );
396       this->OtherActors[ i ].second->Modified( );
397
398     } // fi
399
400   } // rof
401
402   if( this->m_UpdateCommand != NULL )
403     this->m_UpdateCommand( this->m_UpdateData );
404
405   // Update text
406   this->UpdateText( );
407 }
408
409 // -------------------------------------------------------------------------
410 void cpExtensions::Visualization::ImageSliceActors::
411 UpdateText( )
412 {
413   if( this->SliceMappers.size( ) > 0 )
414   {
415     char axis;
416     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
417     if     ( axId == 0 ) axis = 'X';
418     else if( axId == 1 ) axis = 'Y';
419     else if( axId == 2 ) axis = 'Z';
420
421     std::sprintf(
422       this->TextBuffer, "Axis: %c (%d)",
423       axis, this->SliceMappers[ 0 ]->GetSliceNumber( )
424       );
425   }
426   else
427     this->TextBuffer[ 0 ] = '\0';
428   this->TextActor->SetInput( this->TextBuffer );
429   this->TextActor->Modified( );
430   this->Modified( );
431 }
432
433 // -------------------------------------------------------------------------
434 void cpExtensions::Visualization::ImageSliceActors::
435 UpdateText( const double& w, const double& l )
436 {
437   if( this->SliceMappers.size( ) > 0 )
438   {
439     char axis;
440     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
441     if     ( axId == 0 ) axis = 'X';
442     else if( axId == 1 ) axis = 'Y';
443     else if( axId == 2 ) axis = 'Z';
444
445     std::sprintf(
446       this->TextBuffer, "Axis: %c (%d) | W/L (%.2f/%.2f)",
447       axis, this->SliceMappers[ 0 ]->GetSliceNumber( ), w, l
448       );
449   }
450   else
451     this->TextBuffer[ 0 ] = '\0';
452   this->TextActor->SetInput( this->TextBuffer );
453   this->TextActor->Modified( );
454   this->Modified( );
455 }
456
457 // -------------------------------------------------------------------------
458 cpExtensions::Visualization::ImageSliceActors::
459 ImageSliceActors( )
460   : Superclass( ),
461     Interpolate( false ),
462     m_UpdateCommand( NULL ),
463     m_UpdateData( NULL )
464 {
465   this->Clear( );
466 }
467
468 // -------------------------------------------------------------------------
469 cpExtensions::Visualization::ImageSliceActors::
470 ~ImageSliceActors( )
471 {
472 }
473
474 // -------------------------------------------------------------------------
475 void cpExtensions::Visualization::ImageSliceActors::
476 _ConfigureNewInput( int axis )
477 {
478   unsigned int nImages = this->ImageActors.size( );
479
480   // Configure mapper
481   vtkImageSliceMapper* mapper = this->SliceMappers[ nImages ];
482   if( nImages == 0 )
483     mapper->SetOrientation( axis );
484   else
485     mapper->SetOrientation( this->SliceMappers[ 0 ]->GetOrientation( ) );
486   mapper->Update( );
487
488   // Create actor
489   vtkSmartPointer< vtkImageActor > actor =
490     vtkSmartPointer< vtkImageActor >::New( );
491   this->ImageActors.push_back( actor );
492   actor->SetMapper( mapper );
493   actor->SetInterpolate( this->Interpolate );
494   actor->Modified( );
495
496   if( nImages == 0 )
497   {
498     this->AddItem( this->TextActor );
499     this->AddItem( this->PlaneActor );
500
501   } // fi
502   this->AddItem( actor );
503
504   if( nImages > 1 )
505     this->SetSliceNumber( this->GetSliceNumber( ) );
506   this->Modified( );
507 }
508
509 // eof - $RCSfile$