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