]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageSliceActors.cxx
Merge ssh://git.creatis.insa-lyon.fr/cpPlugins
[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
54   // Reconfigure unique objects
55   this->PlaneSource = vtkSmartPointer< vtkPolyData >::New( );
56   this->PlaneMapper = vtkSmartPointer< vtkPolyDataMapper >::New( );
57   this->TextActor   = vtkSmartPointer< vtkTextActor >::New( );
58   this->PlaneActor  = vtkSmartPointer< vtkActor >::New( );
59   this->TextBuffer[ 0 ] = '\0';
60
61   // Unique objects configuration
62   vtkSmartPointer< vtkPoints > plane_points =
63     vtkSmartPointer< vtkPoints >::New( );
64   vtkSmartPointer< vtkCellArray > plane_lines =
65     vtkSmartPointer< vtkCellArray >::New( );
66
67   plane_points->InsertNextPoint( 0, 0, 0 );
68   plane_points->InsertNextPoint( 0, 1, 0 );
69   plane_points->InsertNextPoint( 1, 1, 0 );
70   plane_points->InsertNextPoint( 1, 0, 0 );
71   plane_lines->InsertNextCell( 5 );
72   plane_lines->InsertCellPoint( 0 );
73   plane_lines->InsertCellPoint( 1 );
74   plane_lines->InsertCellPoint( 2 );
75   plane_lines->InsertCellPoint( 3 );
76   plane_lines->InsertCellPoint( 0 );
77   this->PlaneSource->SetPoints( plane_points );
78   this->PlaneSource->SetLines( plane_lines );
79
80   this->PlaneMapper->SetInputData( this->PlaneSource );
81   this->PlaneActor->SetMapper( this->PlaneMapper );
82
83   this->TextActor->SetTextScaleModeToNone( );
84   vtkTextProperty* textprop = this->TextActor->GetTextProperty( );
85   textprop->SetColor( 1, 1, 1 );
86   textprop->SetFontFamilyToCourier( );
87   textprop->SetFontSize( 18 );
88   textprop->BoldOff( );
89   textprop->ItalicOff( );
90   textprop->ShadowOff( );
91   textprop->SetJustificationToLeft( );
92   textprop->SetVerticalJustificationToBottom( );
93   vtkCoordinate* coord = this->TextActor->GetPositionCoordinate( );
94   coord->SetCoordinateSystemToNormalizedViewport( );
95   coord->SetValue( 0.01, 0.01 );
96 }
97
98 // -------------------------------------------------------------------------
99 unsigned int cpExtensions::Visualization::ImageSliceActors::
100 GetNumberOfImageActors( ) const
101 {
102   return( this->ImageActors.size( ) );
103 }
104
105 // -------------------------------------------------------------------------
106 vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
107 GetImageActor( unsigned int id )
108 {
109   if( id < this->ImageActors.size( ) )
110     return( this->ImageActors[ id ] );
111   else
112     return( NULL );
113 }
114
115 // -------------------------------------------------------------------------
116 const vtkImageActor* cpExtensions::Visualization::ImageSliceActors::
117 GetImageActor( unsigned int id ) const
118 {
119   if( id < this->ImageActors.size( ) )
120     return( this->ImageActors[ id ] );
121   else
122     return( NULL );
123 }
124
125 // -------------------------------------------------------------------------
126 vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
127 GetTextActor( )
128 {
129   return( this->TextActor );
130 }
131
132 // -------------------------------------------------------------------------
133 const vtkTextActor* cpExtensions::Visualization::ImageSliceActors::
134 GetTextActor( ) const
135 {
136   return( this->TextActor );
137 }
138
139 // -------------------------------------------------------------------------
140 vtkActor* cpExtensions::Visualization::ImageSliceActors::
141 GetPlaneActor( )
142 {
143   return( this->PlaneActor );
144 }
145
146 // -------------------------------------------------------------------------
147 const vtkActor* cpExtensions::Visualization::ImageSliceActors::
148 GetPlaneActor( ) const
149 {
150   return( this->PlaneActor );
151 }
152
153 // -------------------------------------------------------------------------
154 void cpExtensions::Visualization::ImageSliceActors::
155 SetInterpolate( bool v )
156 {
157   if( this->Interpolate != v )
158   {
159     for( unsigned int i = 0; i < this->ImageActors.size( ); ++i )
160       this->ImageActors[ i ]->SetInterpolate( v );
161     this->Interpolate = v;
162     this->Modified( );
163
164   } // fi
165 }
166
167 // -------------------------------------------------------------------------
168 void cpExtensions::Visualization::ImageSliceActors::
169 InterpolateOn( )
170 {
171   this->SetInterpolate( true );
172 }
173
174 // -------------------------------------------------------------------------
175 void cpExtensions::Visualization::ImageSliceActors::
176 InterpolateOff( )
177 {
178   this->SetInterpolate( false );
179 }
180
181 // -------------------------------------------------------------------------
182 double* cpExtensions::Visualization::ImageSliceActors::
183 GetDisplayBounds( ) const
184 {
185   if( this->ImageActors.size( ) > 0 )
186     return( this->ImageActors[ 0 ]->GetDisplayBounds( ) );
187   else
188     return( NULL );
189 }
190
191 // -------------------------------------------------------------------------
192 void cpExtensions::Visualization::ImageSliceActors::
193 GetDisplayBounds( double bounds[ 6 ] ) const
194 {
195   if( this->ImageActors.size( ) == 0 )
196   {
197     bounds[ 0 ] = bounds[ 2 ] = bounds[ 4 ] = double( -1 );
198     bounds[ 1 ] = bounds[ 3 ] = bounds[ 5 ] = double( -1 );
199   }
200   else
201     this->ImageActors[ 0 ]->GetDisplayBounds( bounds );
202 }
203
204 // -------------------------------------------------------------------------
205 int cpExtensions::Visualization::ImageSliceActors::
206 GetAxis( ) const
207 {
208   if( this->SliceMappers.size( ) > 0 )
209     return( this->SliceMappers[ 0 ]->GetOrientation( ) );
210   else
211     return( -1 );
212 }
213
214 // -------------------------------------------------------------------------
215 int cpExtensions::Visualization::ImageSliceActors::
216 GetSliceNumber( ) const
217 {
218   if( this->SliceMappers.size( ) > 0 )
219     return( this->SliceMappers[ 0 ]->GetSliceNumber( ) );
220   else
221     return( -1 );
222 }
223
224 // -------------------------------------------------------------------------
225 int cpExtensions::Visualization::ImageSliceActors::
226 GetSliceNumberMinValue( ) const
227 {
228   if( this->SliceMappers.size( ) > 0 )
229     return( this->SliceMappers[ 0 ]->GetSliceNumberMinValue( ) );
230   else
231     return( -1 );
232 }
233
234 // -------------------------------------------------------------------------
235 int cpExtensions::Visualization::ImageSliceActors::
236 GetSliceNumberMaxValue( ) const
237 {
238   if( this->SliceMappers.size( ) > 0 )
239     return( this->SliceMappers[ 0 ]->GetSliceNumberMaxValue( ) );
240   else
241     return( -1 );
242 }
243
244 // -------------------------------------------------------------------------
245 void cpExtensions::Visualization::ImageSliceActors::
246 SetSliceNumber( const int& slice )
247 {
248   unsigned int nImages = this->SliceMappers.size( );
249   if( nImages == 0 )
250     return;
251
252   // Change visualization extent
253   for( unsigned int i = 0; i < nImages; ++i )
254   {
255     this->SliceMappers[ i ]->SetSliceNumber( slice );
256     this->SliceMappers[ i ]->Modified( );
257     this->ImageActors[ i ]->Modified( );
258     this->SliceMappers[ i ]->Update( );
259
260   } // rof
261
262   // Compute plane
263   vtkAlgorithm* algo = this->SliceMappers[ 0 ]->GetInputAlgorithm( );
264   vtkInformation* info = algo->GetOutputInformation( 0 );
265   int ext[ 6 ];
266   double ori[ 3 ], spac[ 3 ], pos[ 3 ];
267   info->Get( vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT( ), ext );
268   info->Get( vtkDataObject::ORIGIN( ), ori );
269   info->Get( vtkDataObject::SPACING( ), spac );
270   this->SliceMappers[ 0 ]->GetSlicePlane( )->GetOrigin( pos );
271
272   // Prevent obscuring voxels by offsetting the plane geometry
273   double xbnds[ ] =
274     {
275       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 0 ] ) ),
276       ori[ 0 ] + ( spac[ 0 ] * double( ext[ 1 ] ) )
277     };
278   double ybnds[ ] =
279     {
280       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 2 ] ) ),
281       ori[ 1 ] + ( spac[ 1 ] * double( ext[ 3 ] ) )
282     };
283   double zbnds[ ] =
284     {
285       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 4 ] ) ),
286       ori[ 2 ] + ( spac[ 2 ] * double( ext[ 5 ] ) )
287     };
288
289   if( spac[ 0 ] < double( 0 ) )
290   {
291     double t = xbnds[ 0 ];
292     xbnds[ 0 ] = xbnds[ 1 ];
293     xbnds[ 1 ] = t;
294
295   } // fi
296   if( spac[ 1 ] < double( 0 ) )
297   {
298     double t = ybnds[ 0 ];
299     ybnds[ 0 ] = ybnds[ 1 ];
300     ybnds[ 1 ] = t;
301
302   } // fi
303   if( spac[ 2 ] < double( 0 ) )
304   {
305     double t = zbnds[ 0 ];
306     zbnds[ 0 ] = zbnds[ 1 ];
307     zbnds[ 1 ] = t;
308
309   } // fi
310
311   int axis = this->SliceMappers[ 0 ]->GetOrientation( );
312   this->PlaneActor->GetProperty( )->SetRepresentationToWireframe( );
313   this->PlaneActor->GetProperty( )->SetLineWidth( 2 );
314   vtkPoints* plane_points = this->PlaneSource->GetPoints( );
315   if( axis == 0 ) // YZ, x-normal
316   {
317     plane_points->SetPoint( 0, pos[ 0 ], ybnds[ 0 ], zbnds[ 0 ] );
318     plane_points->SetPoint( 1, pos[ 0 ], ybnds[ 1 ], zbnds[ 0 ] );
319     plane_points->SetPoint( 2, pos[ 0 ], ybnds[ 1 ], zbnds[ 1 ] );
320     plane_points->SetPoint( 3, pos[ 0 ], ybnds[ 0 ], zbnds[ 1 ] );
321     this->PlaneActor->GetProperty( )->SetColor( 1, 0, 0 );
322   }
323   else if( axis == 1 ) // ZX, y-normal
324   {
325     plane_points->SetPoint( 0, xbnds[ 0 ], pos[ 1 ], zbnds[ 0 ] );
326     plane_points->SetPoint( 1, xbnds[ 0 ], pos[ 1 ], zbnds[ 1 ] );
327     plane_points->SetPoint( 2, xbnds[ 1 ], pos[ 1 ], zbnds[ 1 ] );
328     plane_points->SetPoint( 3, xbnds[ 1 ], pos[ 1 ], zbnds[ 0 ] );
329     this->PlaneActor->GetProperty( )->SetColor( 0, 1, 0 );
330   }
331   else // XY, z-normal
332   {
333     plane_points->SetPoint( 0, xbnds[ 0 ], ybnds[ 0 ], pos[ 2 ] );
334     plane_points->SetPoint( 1, xbnds[ 1 ], ybnds[ 0 ], pos[ 2 ] );
335     plane_points->SetPoint( 2, xbnds[ 1 ], ybnds[ 1 ], pos[ 2 ] );
336     plane_points->SetPoint( 3, xbnds[ 0 ], ybnds[ 1 ], pos[ 2 ] );
337     this->PlaneActor->GetProperty( )->SetColor( 0, 0, 1 );
338
339   } // fi
340   this->PlaneSource->Modified( );
341   this->PlaneMapper->Modified( );
342   this->PlaneActor->Modified( );
343   this->UpdateText( );
344 }
345
346 // -------------------------------------------------------------------------
347 void cpExtensions::Visualization::ImageSliceActors::
348 UpdateText( )
349 {
350   if( this->SliceMappers.size( ) > 0 )
351   {
352     char axis;
353     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
354     if     ( axId == 0 ) axis = 'X';
355     else if( axId == 1 ) axis = 'Y';
356     else if( axId == 2 ) axis = 'Z';
357
358     std::sprintf(
359       this->TextBuffer, "Axis: %c (%d)",
360       axis, this->SliceMappers[ 0 ]->GetSliceNumber( )
361       );
362   }
363   else
364     this->TextBuffer[ 0 ] = '\0';
365   this->TextActor->SetInput( this->TextBuffer );
366   this->TextActor->Modified( );
367   this->Modified( );
368 }
369
370 // -------------------------------------------------------------------------
371 void cpExtensions::Visualization::ImageSliceActors::
372 UpdateText( const double& w, const double& l )
373 {
374   if( this->SliceMappers.size( ) > 0 )
375   {
376     char axis;
377     int axId = this->SliceMappers[ 0 ]->GetOrientation( );
378     if     ( axId == 0 ) axis = 'X';
379     else if( axId == 1 ) axis = 'Y';
380     else if( axId == 2 ) axis = 'Z';
381
382     std::sprintf(
383       this->TextBuffer, "Axis: %c (%d) | W/L (%.2f/%.2f)",
384       axis, this->SliceMappers[ 0 ]->GetSliceNumber( ), w, l
385       );
386   }
387   else
388     this->TextBuffer[ 0 ] = '\0';
389   this->TextActor->SetInput( this->TextBuffer );
390   this->TextActor->Modified( );
391   this->Modified( );
392 }
393
394 // -------------------------------------------------------------------------
395 cpExtensions::Visualization::ImageSliceActors::
396 ImageSliceActors( )
397   : Superclass( ),
398     Interpolate( false )
399 {
400   this->Clear( );
401 }
402
403 // -------------------------------------------------------------------------
404 cpExtensions::Visualization::ImageSliceActors::
405 ~ImageSliceActors( )
406 {
407 }
408
409 // -------------------------------------------------------------------------
410 void cpExtensions::Visualization::ImageSliceActors::
411 _ConfigureNewInput( int axis )
412 {
413   unsigned int nImages = this->ImageActors.size( );
414
415   // Configure mapper
416   vtkImageSliceMapper* mapper = this->SliceMappers[ nImages ];
417   if( nImages == 0 )
418     mapper->SetOrientation( axis );
419   else
420     mapper->SetOrientation( this->SliceMappers[ 0 ]->GetOrientation( ) );
421   mapper->Update( );
422
423   // Create actor
424   vtkSmartPointer< vtkImageActor > actor =
425     vtkSmartPointer< vtkImageActor >::New( );
426   this->ImageActors.push_back( actor );
427   actor->SetMapper( mapper );
428   actor->SetInterpolate( this->Interpolate );
429   actor->Modified( );
430
431   if( nImages == 0 )
432   {
433     this->AddItem( this->TextActor );
434     this->AddItem( this->PlaneActor );
435
436   } // fi
437   this->AddItem( actor );
438
439   if( nImages > 1 )
440     this->SetSliceNumber( this->GetSliceNumber( ) );
441   this->Modified( );
442 }
443
444 // eof - $RCSfile$