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