2 # ---------------------------------------------------------------------
4 # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
6 # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
7 # Previous Authors : Laurent Guigues, Jean-Pierre Roux
8 # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
10 # This software is governed by the CeCILL-B license under French law and
11 # abiding by the rules of distribution of free software. You can use,
12 # modify and/ or redistribute the software under the terms of the CeCILL-B
13 # license as circulated by CEA, CNRS and INRIA at the following URL
14 # http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
15 # or in the file LICENSE.txt.
17 # As a counterpart to the access to the source code and rights to copy,
18 # modify and redistribute granted by the license, users are provided only
19 # with a limited warranty and the software's author, the holder of the
20 # economic rights, and the successive licensors have only limited
23 # The fact that you are presently reading this means that you have had
24 # knowledge of the CeCILL-B license and that you accept its terms.
25 # ------------------------------------------------------------------------ */
28 /*=========================================================================
30 Program: Visualization Toolkit
31 Module: $RCSfile: wxvtkImageViewer2.cxx,v $
33 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
35 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
37 This software is distributed WITHOUT ANY WARRANTY; without even
38 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
39 PURPOSE. See the above copyright notice for more information.
41 =========================================================================*/
42 #include "wxvtkImageViewer2.h"
44 #include "vtkCamera.h"
45 #include "vtkCommand.h"
46 #include "vtkImageActor.h"
47 #include "vtkImageData.h"
48 #include "vtkImageData.h"
49 #include "vtkImageMapToWindowLevelColors.h"
50 #include "vtkInteractorStyleImage.h"
51 #include "vtkObjectFactory.h"
52 #include "vtkRenderWindow.h"
53 #include "vtkRenderWindowInteractor.h"
54 #include "vtkRenderer.h"
56 vtkCxxRevisionMacro(wxvtkImageViewer2, "$Revision: 1.8 $");
57 vtkStandardNewMacro(wxvtkImageViewer2);
59 //----------------------------------------------------------------------------
60 wxvtkImageViewer2::wxvtkImageViewer2()
62 this->RenderWindow = NULL;
63 this->Renderer = NULL;
64 this->ImageActor = vtkImageActor::New();
65 this->WindowLevel = vtkImageMapToWindowLevelColors::New();
66 this->Interactor = NULL;
67 this->InteractorStyle = NULL;
70 this->FirstRender = 1;
71 this->SliceOrientation = wxvtkImageViewer2::SLICE_ORIENTATION_XY;
75 vtkRenderWindow *renwin = vtkRenderWindow::New();
76 this->SetRenderWindow(renwin);
79 vtkRenderer *ren = vtkRenderer::New();
80 this->SetRenderer(ren);
83 this->InstallPipeline();
86 //----------------------------------------------------------------------------
87 wxvtkImageViewer2::~wxvtkImageViewer2()
89 if (this->WindowLevel)
91 this->WindowLevel->Delete();
92 this->WindowLevel = NULL;
97 this->ImageActor->Delete();
98 this->ImageActor = NULL;
103 this->Renderer->Delete();
104 this->Renderer = NULL;
107 if (this->RenderWindow)
109 this->RenderWindow->Delete();
110 this->RenderWindow = NULL;
113 if (this->Interactor)
115 this->Interactor->Delete();
116 this->Interactor = NULL;
119 if (this->InteractorStyle)
121 this->InteractorStyle->Delete();
122 this->InteractorStyle = NULL;
126 //----------------------------------------------------------------------------
127 void wxvtkImageViewer2::SetupInteractor(vtkRenderWindowInteractor *arg)
129 if (this->Interactor == arg)
134 this->UnInstallPipeline();
136 if (this->Interactor)
138 this->Interactor->UnRegister(this);
141 this->Interactor = arg;
143 if (this->Interactor)
145 this->Interactor->Register(this);
148 this->InstallPipeline();
152 this->Renderer->GetActiveCamera()->ParallelProjectionOn();
156 //----------------------------------------------------------------------------
157 void wxvtkImageViewer2::SetRenderWindow(vtkRenderWindow *arg)
159 if (this->RenderWindow == arg)
164 this->UnInstallPipeline();
166 if (this->RenderWindow)
168 this->RenderWindow->UnRegister(this);
171 this->RenderWindow = arg;
173 if (this->RenderWindow)
175 this->RenderWindow->Register(this);
178 this->InstallPipeline();
181 //----------------------------------------------------------------------------
182 void wxvtkImageViewer2::SetRenderer(vtkRenderer *arg)
184 if (this->Renderer == arg)
189 this->UnInstallPipeline();
193 this->Renderer->UnRegister(this);
196 this->Renderer = arg;
200 this->Renderer->Register(this);
203 this->InstallPipeline();
204 this->UpdateOrientation();
207 //----------------------------------------------------------------------------
208 void wxvtkImageViewer2::SetSize(int a,int b)
210 this->RenderWindow->SetSize(a, b);
213 //----------------------------------------------------------------------------
214 int* wxvtkImageViewer2::GetSize()
216 return this->RenderWindow->GetSize();
219 //----------------------------------------------------------------------------
220 void wxvtkImageViewer2::GetSliceRange(int &min, int &max)
222 vtkImageData *input = this->GetInput();
225 input->UpdateInformation();
226 int *w_ext = input->GetWholeExtent();
227 min = w_ext[this->SliceOrientation * 2];
228 max = w_ext[this->SliceOrientation * 2 + 1];
232 //----------------------------------------------------------------------------
233 int* wxvtkImageViewer2::GetSliceRange()
235 vtkImageData *input = this->GetInput();
238 input->UpdateInformation();
239 return input->GetWholeExtent() + this->SliceOrientation * 2;
244 //----------------------------------------------------------------------------
245 int wxvtkImageViewer2::GetSliceMin()
247 int *range = this->GetSliceRange();
255 //----------------------------------------------------------------------------
256 int wxvtkImageViewer2::GetSliceMax()
258 int *range = this->GetSliceRange();
266 //----------------------------------------------------------------------------
267 void wxvtkImageViewer2::SetSlice(int slice)
269 int *range = this->GetSliceRange();
272 if (slice < range[0])
276 else if (slice > range[1])
282 if (this->Slice == slice)
290 this->UpdateDisplayExtent();
294 //----------------------------------------------------------------------------
295 void wxvtkImageViewer2::SetSliceOrientation(int orientation)
297 if (orientation < wxvtkImageViewer2::SLICE_ORIENTATION_YZ ||
298 orientation > wxvtkImageViewer2::SLICE_ORIENTATION_XY)
300 vtkErrorMacro("Error - invalid slice orientation " << orientation);
304 if (this->SliceOrientation == orientation)
309 this->SliceOrientation = orientation;
313 int *range = this->GetSliceRange();
316 this->Slice = static_cast<int>((range[0] + range[1]) * 0.5);
319 this->UpdateOrientation();
320 this->UpdateDisplayExtent();
322 if (this->Renderer && this->GetInput())
324 double scale = this->Renderer->GetActiveCamera()->GetParallelScale();
325 this->Renderer->ResetCamera();
326 this->Renderer->GetActiveCamera()->SetParallelScale(scale);
332 //----------------------------------------------------------------------------
333 void wxvtkImageViewer2::UpdateOrientation()
335 // Set the camera position
337 vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL;
341 // EED 21 mars FLIP problem ..PLOP..
342 switch (this->SliceOrientation)
344 case wxvtkImageViewer2::SLICE_ORIENTATION_YZ:
345 cam->SetViewUp(0,0,1);
346 cam->SetPosition(1,0,0); // -1 if medical ?
347 cam->SetFocalPoint(0,0,0);
350 case wxvtkImageViewer2::SLICE_ORIENTATION_XZ:
351 cam->SetViewUp(0,0,1);
352 cam->SetPosition(0,-1,0); // 1 if medical ?
353 cam->SetFocalPoint(0,0,0);
356 case wxvtkImageViewer2::SLICE_ORIENTATION_XY:
357 cam->SetViewUp(0,-1,0);
358 cam->SetPosition(0,0,-1);
359 cam->SetFocalPoint(0,0,0);
364 switch (this->SliceOrientation)
366 case wxvtkImageViewer2::SLICE_ORIENTATION_YZ:
367 cam->SetViewUp(0,0,1);
368 cam->SetPosition(1,0,0); // -1 if medical ?
369 cam->SetFocalPoint(0,0,0);
372 case wxvtkImageViewer2::SLICE_ORIENTATION_XZ:
373 cam->SetViewUp(0,0,1);
374 cam->SetPosition(0,-1,0); // 1 if medical ?
375 cam->SetFocalPoint(0,0,0);
378 case wxvtkImageViewer2::SLICE_ORIENTATION_XY:
379 cam->SetViewUp(0,1,0);
380 cam->SetPosition(0,0,1); // -1 if medical ?
381 cam->SetFocalPoint(0,0,0);
391 //----------------------------------------------------------------------------
392 void wxvtkImageViewer2::UpdateDisplayExtent()
394 vtkImageData *input = this->GetInput();
395 if (!input || !this->ImageActor)
400 // std::cout << "--- wxvtkImageViewer2::UpdateDisplayExtent()"<<std::endl;
401 input->UpdateInformation();
402 int *w_ext = input->GetWholeExtent();
404 // std::cout << "ext = "
405 // <<w_ext[0]<<" - "<<w_ext[1]<<" ; "
406 // <<w_ext[2]<<" - "<<w_ext[3]<<" ; "
407 // <<w_ext[4]<<" - "<<w_ext[5]
409 // Is the slice in range ? If not, fix it
411 int slice_min = w_ext[this->SliceOrientation * 2];
412 int slice_max = w_ext[this->SliceOrientation * 2 + 1];
413 if (this->Slice < slice_min || this->Slice > slice_max)
415 this->Slice = static_cast<int>((slice_min + slice_max) * 0.5);
418 // Set the image actor
420 switch (this->SliceOrientation)
422 case wxvtkImageViewer2::SLICE_ORIENTATION_XY:
423 this->ImageActor->SetDisplayExtent(
424 w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice);
427 case wxvtkImageViewer2::SLICE_ORIENTATION_XZ:
428 this->ImageActor->SetDisplayExtent(
429 w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5]);
432 case wxvtkImageViewer2::SLICE_ORIENTATION_YZ:
433 this->ImageActor->SetDisplayExtent(
434 this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5]);
438 // Figure out the correct clipping range
442 if (this->InteractorStyle &&
443 this->InteractorStyle->GetAutoAdjustCameraClippingRange())
445 this->Renderer->ResetCameraClippingRange();
449 vtkCamera *cam = this->Renderer->GetActiveCamera();
453 this->ImageActor->GetBounds(bounds);
454 double spos = bounds[this->SliceOrientation * 2];
455 double cpos = cam->GetPosition()[this->SliceOrientation];
456 double range = fabs(spos - cpos);
457 double *spacing = input->GetSpacing();
459 //(spacing[0] + spacing[1] + spacing[2]) / 3.0;
461 cam->SetClippingRange(
462 range - avg_spacing * 3.0, range + avg_spacing * 3.0);
468 //----------------------------------------------------------------------------
469 void wxvtkImageViewer2::SetPosition(int a,int b)
471 this->RenderWindow->SetPosition(a, b);
474 //----------------------------------------------------------------------------
475 int* wxvtkImageViewer2::GetPosition()
477 return this->RenderWindow->GetPosition();
480 //----------------------------------------------------------------------------
481 void wxvtkImageViewer2::SetDisplayId(void *a)
483 this->RenderWindow->SetDisplayId(a);
486 //----------------------------------------------------------------------------
487 void wxvtkImageViewer2::SetWindowId(void *a)
489 this->RenderWindow->SetWindowId(a);
492 //----------------------------------------------------------------------------
493 void wxvtkImageViewer2::SetParentId(void *a)
495 this->RenderWindow->SetParentId(a);
498 //----------------------------------------------------------------------------
499 double wxvtkImageViewer2::GetColorWindow()
501 return this->WindowLevel->GetWindow();
504 //----------------------------------------------------------------------------
505 double wxvtkImageViewer2::GetColorLevel()
507 return this->WindowLevel->GetLevel();
510 //----------------------------------------------------------------------------
511 void wxvtkImageViewer2::SetColorWindow(double s)
513 this->WindowLevel->SetWindow(s);
516 //----------------------------------------------------------------------------
517 void wxvtkImageViewer2::SetColorLevel(double s)
519 this->WindowLevel->SetLevel(s);
522 //----------------------------------------------------------------------------
523 class wxvtkImageViewer2Callback : public vtkCommand
526 static wxvtkImageViewer2Callback *New() { return new wxvtkImageViewer2Callback; }
528 void Execute(vtkObject *caller,
530 void *vtkNotUsed(callData))
532 if (this->IV->GetInput() == NULL)
539 if (event == vtkCommand::ResetWindowLevelEvent)
541 this->IV->GetInput()->UpdateInformation();
542 this->IV->GetInput()->SetUpdateExtent
543 (this->IV->GetInput()->GetWholeExtent());
544 this->IV->GetInput()->Update();
545 double *range = this->IV->GetInput()->GetScalarRange();
546 this->IV->SetColorWindow(range[1] - range[0]);
547 this->IV->SetColorLevel(0.5 * (range[1] + range[0]));
554 if (event == vtkCommand::StartWindowLevelEvent)
556 this->InitialWindow = this->IV->GetColorWindow();
557 this->InitialLevel = this->IV->GetColorLevel();
561 // Adjust the window level here
563 vtkInteractorStyleImage *isi =
564 static_cast<vtkInteractorStyleImage *>(caller);
566 int *size = this->IV->GetRenderWindow()->GetSize();
567 double window = this->InitialWindow;
568 double level = this->InitialLevel;
570 // Compute normalized delta
573 (isi->GetWindowLevelCurrentPosition()[0] -
574 isi->GetWindowLevelStartPosition()[0]) / size[0];
576 (isi->GetWindowLevelStartPosition()[1] -
577 isi->GetWindowLevelCurrentPosition()[1]) / size[1];
579 // Scale by current values
581 if (fabs(window) > 0.01)
587 dx = dx * (window < 0 ? -0.01 : 0.01);
589 if (fabs(level) > 0.01)
595 dy = dy * (level < 0 ? -0.01 : 0.01);
598 // Abs so that direction does not flip
609 // Compute new window level
611 double newWindow = dx + window;
613 newLevel = level - dy;
615 // Stay away from zero and really
617 if (fabs(newWindow) < 0.01)
619 newWindow = 0.01*(newWindow < 0 ? -1 : 1);
621 if (fabs(newLevel) < 0.01)
623 newLevel = 0.01*(newLevel < 0 ? -1 : 1);
626 this->IV->SetColorWindow(newWindow);
627 this->IV->SetColorLevel(newLevel);
631 wxvtkImageViewer2 *IV;
632 double InitialWindow;
636 //----------------------------------------------------------------------------
637 void wxvtkImageViewer2::InstallPipeline()
639 if (this->RenderWindow && this->Renderer)
641 this->RenderWindow->AddRenderer(this->Renderer);
644 if (this->Interactor)
646 if (!this->InteractorStyle)
648 this->InteractorStyle = vtkInteractorStyleImage::New();
649 wxvtkImageViewer2Callback *cbk = wxvtkImageViewer2Callback::New();
651 this->InteractorStyle->AddObserver(
652 vtkCommand::WindowLevelEvent, cbk);
653 this->InteractorStyle->AddObserver(
654 vtkCommand::StartWindowLevelEvent, cbk);
655 this->InteractorStyle->AddObserver(
656 vtkCommand::ResetWindowLevelEvent, cbk);
660 this->Interactor->SetInteractorStyle(this->InteractorStyle);
661 this->Interactor->SetRenderWindow(this->RenderWindow);
664 if (this->Renderer && this->ImageActor)
666 this->Renderer->AddViewProp(this->ImageActor);
669 if (this->ImageActor && this->WindowLevel)
671 this->ImageActor->SetInput(this->WindowLevel->GetOutput());
675 //----------------------------------------------------------------------------
676 void wxvtkImageViewer2::UnInstallPipeline()
678 if (this->ImageActor)
680 this->ImageActor->SetInput(NULL);
683 if (this->Renderer && this->ImageActor)
685 this->Renderer->RemoveViewProp(this->ImageActor);
688 if (this->RenderWindow && this->Renderer)
690 this->RenderWindow->RemoveRenderer(this->Renderer);
693 if (this->Interactor)
695 this->Interactor->SetInteractorStyle(NULL);
696 this->Interactor->SetRenderWindow(NULL);
700 //----------------------------------------------------------------------------
701 void wxvtkImageViewer2::Render()
703 if (this->FirstRender)
705 // Initialize the size if not set yet
707 vtkImageData *input = this->GetInput();
708 if (this->RenderWindow->GetSize()[0] == 0 &&
712 input->UpdateInformation();
713 int *w_ext = input->GetWholeExtent();
716 // std::cout << "wxvtkImageViewer2::Render ext = "
717 // <<w_ext[0]<<" - "<<w_ext[1]<<" ; "
718 // <<w_ext[2]<<" - "<<w_ext[3]<<" ; "
719 // <<w_ext[4]<<" - "<<w_ext[5]
722 switch (this->SliceOrientation)
724 case wxvtkImageViewer2::SLICE_ORIENTATION_XY:
726 xs = w_ext[1] - w_ext[0] + 1;
727 ys = w_ext[3] - w_ext[2] + 1;
728 // std::cout << "SLICE_ORIENTATION_XY" << std::endl;
731 case wxvtkImageViewer2::SLICE_ORIENTATION_XZ:
732 xs = w_ext[1] - w_ext[0] + 1;
733 ys = w_ext[5] - w_ext[4] + 1;
734 // std::cout << "SLICE_ORIENTATION_XZ" << std::endl;
737 case wxvtkImageViewer2::SLICE_ORIENTATION_YZ:
738 xs = w_ext[3] - w_ext[2] + 1;
739 ys = w_ext[5] - w_ext[4] + 1;
740 // std::cout << "SLICE_ORIENTATION_YZ" << std::endl;
744 // if it would be smaller than 150 by 100 then limit to 150 by 100
745 this->RenderWindow->SetSize(
746 xs < 150 ? 150 : xs, ys < 100 ? 100 : ys);
748 // std::cout << "wxvtkImageViewer2::Render() : "<<xs<<"-"<<ys<<std::endl;
751 this->Renderer->ResetCamera();
752 this->Renderer->GetActiveCamera()->SetParallelScale(
753 xs < 150 ? 75 : (xs - 1 ) / 2.0);
755 this->FirstRender = 0;
759 if (this->GetInput())
761 this->RenderWindow->Render();
765 //----------------------------------------------------------------------------
766 const char* wxvtkImageViewer2::GetWindowName()
768 return this->RenderWindow->GetWindowName();
771 //----------------------------------------------------------------------------
772 void wxvtkImageViewer2::SetOffScreenRendering(int i)
774 this->RenderWindow->SetOffScreenRendering(i);
777 //----------------------------------------------------------------------------
778 int wxvtkImageViewer2::GetOffScreenRendering()
780 return this->RenderWindow->GetOffScreenRendering();
783 //----------------------------------------------------------------------------
784 void wxvtkImageViewer2::SetInput(vtkImageData *in)
786 // std::cout << "### wxvtkImageViewer2::SetInput"<<std::endl;
787 this->WindowLevel->SetInput(in);
788 this->UpdateDisplayExtent();
792 //----------------------------------------------------------------------------
793 vtkImageData* wxvtkImageViewer2::GetInput()
795 return vtkImageData::SafeDownCast(this->WindowLevel->GetInput());
798 //----------------------------------------------------------------------------
799 void wxvtkImageViewer2::SetInputConnection(vtkAlgorithmOutput* input)
801 this->WindowLevel->SetInputConnection(input);
802 this->UpdateDisplayExtent();
805 //----------------------------------------------------------------------------
806 #ifndef VTK_LEGACY_REMOVE
807 int wxvtkImageViewer2::GetWholeZMin()
809 VTK_LEGACY_REPLACED_BODY(wxvtkImageViewer2::GetWholeZMin, "VTK 5.0",
810 wxvtkImageViewer2::GetSliceMin);
811 return this->GetSliceMin();
813 int wxvtkImageViewer2::GetWholeZMax()
815 VTK_LEGACY_REPLACED_BODY(wxvtkImageViewer2::GetWholeZMax, "VTK 5.0",
816 wxvtkImageViewer2::GetSliceMax);
817 return this->GetSliceMax();
819 int wxvtkImageViewer2::GetZSlice()
821 VTK_LEGACY_REPLACED_BODY(wxvtkImageViewer2::GetZSlice, "VTK 5.0",
822 wxvtkImageViewer2::GetSlice);
823 return this->GetSlice();
825 void wxvtkImageViewer2::SetZSlice(int s)
827 VTK_LEGACY_REPLACED_BODY(wxvtkImageViewer2::SetZSlice, "VTK 5.0",
828 wxvtkImageViewer2::SetSlice);
833 //----------------------------------------------------------------------------
834 void wxvtkImageViewer2::PrintSelf(ostream& os, vtkIndent indent)
836 this->Superclass::PrintSelf(os, indent);
838 os << indent << "RenderWindow:\n";
839 this->RenderWindow->PrintSelf(os,indent.GetNextIndent());
840 os << indent << "Renderer:\n";
841 this->Renderer->PrintSelf(os,indent.GetNextIndent());
842 os << indent << "ImageActor:\n";
843 this->ImageActor->PrintSelf(os,indent.GetNextIndent());
844 os << indent << "WindowLevel:\n" << endl;
845 this->WindowLevel->PrintSelf(os,indent.GetNextIndent());
846 os << indent << "Slice: " << this->Slice << endl;
847 os << indent << "SliceOrientation: " << this->SliceOrientation << endl;
848 os << indent << "InteractorStyle: " << endl;
849 if (this->InteractorStyle)
852 this->InteractorStyle->PrintSelf(os,indent.GetNextIndent());