1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
21 #include "vvSlicerManagerCommand.h"
22 #include "vvGlyphSource.h"
23 #include "vvGlyph2D.h"
24 #include "vvImageMapToWLColors.h"
26 #include <vtkTextProperty.h>
27 #include <vtkTextActor.h>
28 #include <vtkTextSource.h>
29 #include <vtkActor2D.h>
30 #include <vtkCursor2D.h>
31 #include <vtkPolyDataMapper2D.h>
32 #include <vtkProperty2D.h>
33 #include <vtkCornerAnnotation.h>
34 #include <vtkImageMapToWindowLevelColors.h>
35 #include <vtkImageData.h>
36 #include <vtkImageActor.h>
37 #include <vvBlendImageActor.h>
38 #include <vtkToolkits.h>
39 #include <vtkObjectFactory.h>
40 #include <vtkPointData.h>
41 #include <vtkDataArray.h>
42 #include <vtkFloatArray.h>
43 #include <vtkClipPolyData.h>
44 #include <vtkGlyph3D.h>
46 #include <vtkCursor3D.h>
47 #include <vtkProperty.h>
49 #include <vtkLightCollection.h>
50 #include <vtkScalarBarActor.h>
51 #include <vtkLookupTable.h>
53 #include <vtkRenderer.h>
54 #include <vtkRendererCollection.h>
55 #include <vtkRenderWindow.h>
56 #include <vtkRenderWindowInteractor.h>
57 #include <vtkCamera.h>
58 #include <vtkCallbackCommand.h>
59 #include <vtkCommand.h>
60 #include <vtkPolyDataMapper.h>
63 #include <vtkExtractVOI.h>
64 #include <vtkSphereSource.h>
65 #include <vtkCutter.h>
66 #include <vtkAssignAttribute.h>
67 #include <vtkImageAccumulate.h>
68 #include <vtkImageReslice.h>
70 vtkCxxRevisionMacro(vvSlicer, "DummyRevision");
71 vtkStandardNewMacro(vvSlicer);
73 //------------------------------------------------------------------------------
76 this->UnInstallPipeline();
79 mUseReducedExtent = false;
81 mCurrent[0] = -VTK_DOUBLE_MAX;
82 mCurrent[1] = -VTK_DOUBLE_MAX;
83 mCurrent[2] = -VTK_DOUBLE_MAX;
85 mCursor[0] = -VTK_DOUBLE_MAX;
86 mCursor[1] = -VTK_DOUBLE_MAX;
87 mCursor[2] = -VTK_DOUBLE_MAX;
88 mCursor[3] = -VTK_DOUBLE_MAX;
98 std::string text = "F1 = sagital; F2 = coronal; F3 = axial\n";
99 text += "F5 = horizontal flip; F6 = vertical flip\n\n";
100 text += "0,1,2,3,4,5 : preset windowing\n";
101 text += "6,7,8,9 : preset colormap\n";
102 text += "z : local windowing\n";
103 text += "r : reset view\n";
104 text += "l : reload image\n";
105 text += "f : fly to mouse position\n";
106 text += "g : go to cross hair position\n\n";
107 text += "Up,down : change slice\n";
108 text += "Left,right : change tenporal slice\n\n";
109 text += "Scrollbar (or w/x) : zoom in/out\n";
110 text += "left button : synchronize all views\n";
111 text += "middle button : grab image\n";
112 text += "right button : change windowing\n";
114 crossCursor = vtkSmartPointer<vtkCursor2D>::New();
115 crossCursor->AllOff();
116 crossCursor->AxesOn();
117 crossCursor->SetTranslationMode(1);
118 crossCursor->SetRadius(2);
120 pdm = vtkSmartPointer<vtkPolyDataMapper2D>::New();
121 pdm->SetInput(crossCursor->GetOutput());
123 pdmA = vtkSmartPointer<vtkActor2D>::New();
124 pdmA->SetMapper(pdm);
125 pdmA->GetProperty()->SetColor(255,10,212);
126 pdmA->SetVisibility(0);
127 pdmA->SetPickable(0);
129 ca = vtkSmartPointer<vtkCornerAnnotation>::New();
130 ca->GetTextProperty()->SetColor(255,10,212);
131 ca->SetVisibility(1);
139 legend = vtkSmartPointer<vtkScalarBarActor>::New();
140 //legend->SetTitle("test!");
141 legend->SetPosition(0.82,0.18);
142 legend->SetWidth(0.1);
143 legend->SetVisibility(0);
144 legend->SetLabelFormat("%.1f");
145 this->GetRenderer()->AddActor(legend);
147 this->WindowLevel->Delete();
148 this->WindowLevel = vvImageMapToWLColors::New();
150 this->InstallPipeline();
152 //------------------------------------------------------------------------------
155 //------------------------------------------------------------------------------
156 vtkImageMapToWindowLevelColors* vvSlicer::GetOverlayMapper()
158 return mOverlayMapper.GetPointer();
160 //------------------------------------------------------------------------------
163 //------------------------------------------------------------------------------
164 vvBlendImageActor* vvSlicer::GetOverlayActor()
166 return mOverlayActor.GetPointer();
168 //------------------------------------------------------------------------------
171 //------------------------------------------------------------------------------
172 vtkImageMapToWindowLevelColors* vvSlicer::GetFusionMapper()
174 return mFusionMapper.GetPointer();
176 //------------------------------------------------------------------------------
179 //------------------------------------------------------------------------------
180 vtkImageActor* vvSlicer::GetFusionActor()
182 return mFusionActor.GetPointer();
184 //------------------------------------------------------------------------------
187 //------------------------------------------------------------------------------
188 vtkActor* vvSlicer::GetVFActor()
190 return mVFActor.GetPointer();
192 //------------------------------------------------------------------------------
195 //------------------------------------------------------------------------------
196 vtkCornerAnnotation* vvSlicer::GetAnnotation()
198 return ca.GetPointer();
200 //------------------------------------------------------------------------------
203 //------------------------------------------------------------------------------
204 void vvSlicer::EnableReducedExtent(bool b)
206 mUseReducedExtent = b;
208 //------------------------------------------------------------------------------
211 //------------------------------------------------------------------------------
212 void vvSlicer::SetReducedExtent(int * ext)
214 mReducedExtent = ext;
216 //------------------------------------------------------------------------------
219 //------------------------------------------------------------------------------
220 void vvSlicer::AddContour(vvMesh::Pointer contour,bool propagate)
223 mSurfaceCutActors.push_back(new vvMeshActor());
225 mSurfaceCutActors.back()->Init(contour,mCurrentTSlice,mVF);
227 mSurfaceCutActors.back()->Init(contour,mCurrentTSlice);
228 mSurfaceCutActors.back()->SetSlicingOrientation(SliceOrientation);
229 this->GetRenderer()->AddActor(mSurfaceCutActors.back()->GetActor());
233 //------------------------------------------------------------------------------
236 //------------------------------------------------------------------------------
237 void vvSlicer::ToggleContourSuperposition()
239 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
240 i!=mSurfaceCutActors.end(); i++)
241 (*i)->ToggleSuperposition();
243 //------------------------------------------------------------------------------
246 //------------------------------------------------------------------------------
247 void vvSlicer::SetCursorColor(int r,int g, int b)
249 pdmA->GetProperty()->SetColor(r,g,b);
251 //------------------------------------------------------------------------------
254 //------------------------------------------------------------------------------
255 void vvSlicer::SetCursorVisibility(bool s)
257 pdmA->SetVisibility(s);
259 //------------------------------------------------------------------------------
262 //------------------------------------------------------------------------------
263 bool vvSlicer::GetCursorVisibility()
265 return pdmA->GetVisibility();
267 //------------------------------------------------------------------------------
270 //------------------------------------------------------------------------------
271 void vvSlicer::SetCornerAnnotationVisibility(bool s)
273 ca->SetVisibility(s);
275 //------------------------------------------------------------------------------
278 //------------------------------------------------------------------------------
279 bool vvSlicer::GetCornerAnnotationVisibility()
281 return ca->GetVisibility();
283 //------------------------------------------------------------------------------
286 //------------------------------------------------------------------------------
287 vvSlicer::~vvSlicer()
289 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
290 i!=mSurfaceCutActors.end(); i++)
293 //------------------------------------------------------------------------------
296 //------------------------------------------------------------------------------
297 void vvSlicer::SetCurrentPosition(double x, double y, double z, int t)
304 //------------------------------------------------------------------------------
307 //------------------------------------------------------------------------------
308 void vvSlicer::SetImage(vvImage::Pointer image)
310 if (image->GetVTKImages().size()) {
313 if (!mImageReslice) {
314 mImageReslice = vtkSmartPointer<vtkImageReslice>::New();
315 mImageReslice->SetInterpolationModeToLinear();
316 mImageReslice->AutoCropOutputOn();
317 mImageReslice->SetBackgroundColor(-1000,-1000,-1000,1);
319 mImageReslice->SetResliceTransform(mImage->GetTransform());
320 mImageReslice->SetInput(0, mImage->GetFirstVTKImageData());
321 mImageReslice->UpdateInformation();
323 this->Superclass::SetInput(mImageReslice->GetOutput());
326 this->GetInput()->GetWholeExtent(extent);
328 // Prevent crash when reload -> change slice if outside extent
329 if (Slice < extent[SliceOrientation*2] || Slice>=extent[SliceOrientation*2+1]) {
330 Slice = (extent[SliceOrientation*2+1]-extent[SliceOrientation*2])/2.0;
333 // Make sure that the required part image has been computed
334 extent[SliceOrientation*2] = Slice;
335 extent[SliceOrientation*2+1] = Slice;
336 mImageReslice->GetOutput()->SetUpdateExtent(extent);
337 mImageReslice->GetOutput()->Update();
339 this->UpdateDisplayExtent();
342 ca->SetText(0,mFileName.c_str());
345 //------------------------------------------------------------------------------
348 //------------------------------------------------------------------------------
349 void vvSlicer::SetOverlay(vvImage::Pointer overlay)
351 if (overlay->GetVTKImages().size()) {
354 if (!mOverlayReslice) {
355 mOverlayReslice = vtkSmartPointer<vtkImageReslice>::New();
356 mOverlayReslice->SetInterpolationModeToLinear();
357 mOverlayReslice->AutoCropOutputOn();
358 mOverlayReslice->SetBackgroundColor(-1000,-1000,-1000,1);
360 mOverlayReslice->SetResliceTransform(mOverlay->GetTransform());
361 mOverlayReslice->SetInput(0, mOverlay->GetFirstVTKImageData());
364 mOverlayMapper = vtkSmartPointer<vtkImageMapToWindowLevelColors>::New();
365 mOverlayMapper->SetInput(mOverlayReslice->GetOutput());
367 if (!mOverlayActor) {
368 mOverlayActor = vtkSmartPointer<vvBlendImageActor>::New();
369 mOverlayActor->SetInput(mOverlayMapper->GetOutput());
370 mOverlayActor->SetPickable(0);
371 mOverlayActor->SetVisibility(false);
372 mOverlayActor->SetOpacity(0.5);
375 //stupid but necessary : the Overlay need to be rendered before fusion
377 this->GetRenderer()->RemoveActor(mFusionActor);
378 this->GetRenderer()->AddActor(mOverlayActor);
379 this->GetRenderer()->AddActor(mFusionActor);
381 this->GetRenderer()->AddActor(mOverlayActor);
383 //Synchronize orientation and slice
384 this->SetSliceOrientation(this->SliceOrientation);
385 this->SetTSlice(mCurrentTSlice);
388 //------------------------------------------------------------------------------
391 //------------------------------------------------------------------------------
392 void vvSlicer::SetFusion(vvImage::Pointer fusion)
394 if (fusion->GetVTKImages().size()) {
397 if (!mFusionReslice) {
398 mFusionReslice = vtkSmartPointer<vtkImageReslice>::New();
399 mFusionReslice->SetInterpolationModeToLinear();
400 mFusionReslice->AutoCropOutputOn();
401 mFusionReslice->SetBackgroundColor(-1000,-1000,-1000,1);
403 mFusionReslice->SetResliceTransform(mFusion->GetTransform());
404 mFusionReslice->SetInput(0, mFusion->GetFirstVTKImageData());
407 mFusionMapper = vtkSmartPointer<vtkImageMapToWindowLevelColors>::New();
408 mFusionMapper->SetInput(mFusionReslice->GetOutput());
411 mFusionActor = vtkSmartPointer<vtkImageActor>::New();
412 mFusionActor->SetInput(mFusionMapper->GetOutput());
413 mFusionActor->SetPickable(0);
414 mFusionActor->SetVisibility(false);
415 mFusionActor->SetOpacity(0.7);
416 this->GetRenderer()->AddActor(mFusionActor);
419 //Synchronize orientation and slice
420 this->SetSliceOrientation(this->SliceOrientation);
421 this->SetTSlice(mCurrentTSlice);
424 //------------------------------------------------------------------------------
427 //------------------------------------------------------------------------------
428 void vvSlicer::SetActorVisibility(const std::string& actor_type, int overlay_index ,bool vis)
430 if (actor_type == "vector") {
431 this->mVFActor->SetVisibility(vis);
433 if (actor_type == "overlay") {
434 this->mOverlayActor->SetVisibility(vis);
436 if (actor_type == "fusion") {
437 this->mFusionActor->SetVisibility(vis);
439 if (actor_type == "contour")
440 this->mSurfaceCutActors[overlay_index]->GetActor()->SetVisibility(vis);
441 UpdateDisplayExtent();
443 //------------------------------------------------------------------------------
446 //------------------------------------------------------------------------------
447 void vvSlicer::SetVF(vvImage::Pointer vf)
449 if (vf->GetVTKImages().size()) {
453 mAAFilter= vtkSmartPointer<vtkAssignAttribute>::New();
454 mVOIFilter = vtkSmartPointer<vtkExtractVOI>::New();
455 mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling);
457 mVOIFilter->SetInput(vf->GetFirstVTKImageData());
458 mAAFilter->SetInput(mVOIFilter->GetOutput());
459 ///This tells VTK to use the scalar (pixel) data of the image to draw the little arrows
460 mAAFilter->Assign(vtkDataSetAttributes::SCALARS, vtkDataSetAttributes::VECTORS, vtkAssignAttribute::POINT_DATA);
463 mArrow = vtkSmartPointer<vvGlyphSource>::New();
464 mArrow->SetGlyphTypeToSpecificArrow();
465 mArrow->SetScale(mScale);
468 // Glyph the gradient vector (with arrows)
470 mGlyphFilter = vtkSmartPointer<vvGlyph2D>::New();
471 mGlyphFilter->SetInput(mAAFilter->GetOutput());
472 mGlyphFilter->SetSource(mArrow->GetOutput());
473 mGlyphFilter->ScalingOn();
474 mGlyphFilter->SetScaleModeToScaleByVector();
475 mGlyphFilter->OrientOn();
476 mGlyphFilter->SetVectorModeToUseVector();
477 mGlyphFilter->SetColorModeToColorByVector();
480 mVFColorLUT = vtkSmartPointer<vtkLookupTable>::New();
482 double mVFColorHSV[3];
483 vtkMath::RGBToHSV(mVFColor, mVFColorHSV);
484 mVFColorLUT->SetHueRange(mVFColorHSV[0], mVFColorHSV[0]);
485 mVFColorLUT->SetSaturationRange(mVFColorHSV[1],mVFColorHSV[1]);
486 mVFColorLUT->SetValueRange(mVFColorHSV[2], mVFColorHSV[2]);
489 mVFMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
490 mVFMapper->SetInput(mGlyphFilter->GetOutput());
491 mVFMapper->ImmediateModeRenderingOn();
492 mVFMapper->SetLookupTable(mVFColorLUT);
495 mVFActor = vtkSmartPointer<vtkActor>::New();
496 mVFActor->SetMapper(mVFMapper);
497 mVFActor->SetPickable(0);
498 mVFActor->GetProperty()->SetLineWidth(mVFWidth);
499 this->UpdateDisplayExtent();
500 this->GetRenderer()->AddActor(mVFActor);
503 SetTSlice(mCurrentTSlice);
506 //------------------------------------------------------------------------------
509 //------------------------------------------------------------------------------
510 void vvSlicer::SetLandmarks(vvLandmarks* landmarks)
512 mLandmarks = landmarks;
516 mCross = vtkSmartPointer<vtkCursor3D>::New();
517 mCross->SetFocalPoint(0.0,0.0,0.0);
518 mCross->SetModelBounds(-10,10,-10,10,-10,10);
523 mLandGlyph = vtkSmartPointer<vtkGlyph3D>::New();
524 mLandGlyph->SetSource(mCross->GetOutput());
525 mLandGlyph->SetInput(landmarks->GetOutput());
526 //mLandGlyph->SetIndexModeToScalar();
527 mLandGlyph->SetRange(0,1);
528 mLandGlyph->ScalingOff();
530 mLandGlyph->SetColorModeToColorByScalar();
533 mClipBox = vtkSmartPointer<vtkBox>::New();
535 mLandClipper = vtkSmartPointer<vtkClipPolyData>::New();
536 mLandClipper->InsideOutOn();
537 mLandClipper->SetInput(mLandGlyph->GetOutput());
538 mLandClipper->SetClipFunction(mClipBox);
541 mLandMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
542 mLandMapper->SetInputConnection(mLandClipper->GetOutputPort());
543 //mLandMapper->ScalarVisibilityOff();
546 mLandActor = vtkSmartPointer<vtkActor>::New();
547 mLandActor->SetMapper(mLandMapper);
548 mLandActor->GetProperty()->SetColor(255,10,212);
549 mLandActor->SetPickable(0);
550 mLandActor->SetVisibility(true);
551 this->UpdateDisplayExtent();
552 this->GetRenderer()->AddActor(mLandActor);
555 //------------------------------------------------------------------------------
557 //------------------------------------------------------------------------------
558 //FIXME: this function leaks memory, we should fix it someday :)
559 void vvSlicer::RemoveActor(const std::string& actor_type, int overlay_index)
561 if (actor_type == "vector") {
562 Renderer->RemoveActor(mVFActor);
571 if (actor_type == "overlay") {
572 Renderer->RemoveActor(mOverlayActor);
574 mOverlayActor = NULL;
575 mOverlayMapper = NULL;
577 if (actor_type == "fusion") {
578 Renderer->RemoveActor(mFusionActor);
581 mFusionMapper = NULL;
583 if (actor_type == "contour") {
584 Renderer->RemoveActor(this->mSurfaceCutActors[overlay_index]->GetActor());
585 mSurfaceCutActors.erase(mSurfaceCutActors.begin()+overlay_index);
588 //------------------------------------------------------------------------------
591 //------------------------------------------------------------------------------
592 void vvSlicer::SetVFSubSampling(int sub)
595 mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling);
598 UpdateDisplayExtent();
601 //------------------------------------------------------------------------------
604 //------------------------------------------------------------------------------
605 void vvSlicer::SetVFScale(int scale)
609 mArrow->SetScale(mScale);
610 UpdateDisplayExtent();
613 //------------------------------------------------------------------------------
615 //------------------------------------------------------------------------------
616 void vvSlicer::SetVFWidth(int width)
620 mVFActor->GetProperty()->SetLineWidth(mVFWidth);
621 UpdateDisplayExtent();
624 //------------------------------------------------------------------------------
627 //------------------------------------------------------------------------------
628 void vvSlicer::SetVFLog(int log)
632 mGlyphFilter->SetUseLog(mVFLog);
633 mGlyphFilter->Modified();
635 UpdateDisplayExtent();
638 //------------------------------------------------------------------------------
641 //------------------------------------------------------------------------------
642 void vvSlicer::SetTSlice(int t)
646 else if ((unsigned int)t >= mImage->GetVTKImages().size())
647 t = mImage->GetVTKImages().size() -1;
649 if (mCurrentTSlice == t) return;
652 mImageReslice->SetInput( mImage->GetVTKImages()[mCurrentTSlice] );
653 if (mVF && mVFActor->GetVisibility()) {
654 if (mVF->GetVTKImages().size() > (unsigned int)mCurrentTSlice)
655 mVOIFilter->SetInput(mVF->GetVTKImages()[mCurrentTSlice]);
657 if (mOverlay && mOverlayActor->GetVisibility()) {
658 if (mOverlay->GetVTKImages().size() > (unsigned int)mCurrentTSlice)
659 mOverlayReslice->SetInput( mOverlay->GetVTKImages()[mCurrentTSlice] );
661 if (mFusion && mFusionActor->GetVisibility()) {
662 if (mFusion->GetVTKImages().size() > (unsigned int)mCurrentTSlice)
663 mFusionReslice->SetInput( mFusion->GetVTKImages()[mCurrentTSlice]);
665 if (mSurfaceCutActors.size() > 0)
666 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
667 i!=mSurfaceCutActors.end(); i++)
668 (*i)->SetTimeSlice(mCurrentTSlice);
669 UpdateDisplayExtent();
671 //------------------------------------------------------------------------------
674 //------------------------------------------------------------------------------
675 int vvSlicer::GetTSlice()
677 return mCurrentTSlice;
679 //------------------------------------------------------------------------------
681 //------------------------------------------------------------------------------
682 void vvSlicer::SetSliceOrientation(int orientation)
684 //if 2D image, force to watch in Axial View
686 this->GetInput()->GetWholeExtent(extent);
687 if (extent[5]-extent[4] <= 2)
688 orientation = vtkImageViewer2::SLICE_ORIENTATION_XY;
690 if (orientation < vtkImageViewer2::SLICE_ORIENTATION_YZ ||
691 orientation > vtkImageViewer2::SLICE_ORIENTATION_XY) {
692 vtkErrorMacro("Error - invalid slice orientation " << orientation);
696 this->SliceOrientation = orientation;
699 AdjustResliceToSliceOrientation(mFusionReslice);
702 AdjustResliceToSliceOrientation(mOverlayReslice);
705 int *range = this->GetSliceRange();
707 this->Slice = static_cast<int>((range[0] + range[1]) * 0.5);
709 // Go to current cursor position
710 // double* cursorPos = GetCursorPosition();
711 // DDV(cursorPos, 3);
712 // SetCurrentPosition(cursorPos[0],cursorPos[1],cursorPos[2],cursorPos[3]);
714 this->UpdateOrientation();
715 this->UpdateDisplayExtent();
717 if (this->Renderer && this->GetInput()) {
718 double scale = this->Renderer->GetActiveCamera()->GetParallelScale();
719 this->Renderer->ResetCamera();
720 this->Renderer->GetActiveCamera()->SetParallelScale(scale);
725 //----------------------------------------------------------------------------
727 //------------------------------------------------------------------------------
728 // This function ensures that we sample the slices of a vtkImageReslice filter
729 // in the direction of the slicer (SliceOrientation) similarly as mImageReslice.
730 // In other words, we change the grid of the reslice in the same way as the grid
731 // of the displayed image in the slicing direction.
732 void vvSlicer::AdjustResliceToSliceOrientation(vtkImageReslice *reslice)
735 double origin[3] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MAX, VTK_DOUBLE_MAX};
736 double spacing[3] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MAX, VTK_DOUBLE_MAX};
737 reslice->SetOutputOrigin(origin);
738 reslice->SetOutputSpacing(spacing);
739 reslice->GetOutput()->UpdateInformation();
740 reslice->GetOutput()->GetOrigin(origin);
741 reslice->GetOutput()->GetSpacing(spacing);
743 // Use similar spacing as the image in the direction SliceOrientation
744 spacing[this->SliceOrientation] = mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation];
746 // Modify origin to be on the image grid in the direction SliceOrientation in 3 steps
747 // Step 1: from world coordinates to image coordinates
748 origin[this->SliceOrientation] -= mImageReslice->GetOutput()->GetOrigin()[this->SliceOrientation];
749 origin[this->SliceOrientation] /= mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation];
750 // Step 2: round to superior grid positionInc
751 origin[this->SliceOrientation] = itk::Math::Ceil<double>(origin[this->SliceOrientation]);
752 // Step 3: back to world coordinates
753 origin[this->SliceOrientation] *= mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation];
754 origin[this->SliceOrientation] += mImageReslice->GetOutput()->GetOrigin()[this->SliceOrientation];
756 // Set new spacing and origin
757 reslice->SetOutputOrigin(origin);
758 reslice->SetOutputSpacing(spacing);
759 reslice->UpdateInformation();
761 //------------------------------------------------------------------------------
763 //----------------------------------------------------------------------------
764 int * vvSlicer::GetExtent()
767 if (mUseReducedExtent) {
768 w_ext = mReducedExtent;
769 } else w_ext = GetInput()->GetWholeExtent();
772 //----------------------------------------------------------------------------
775 //----------------------------------------------------------------------------
776 int vvSlicer::GetOrientation()
778 return this->SliceOrientation;
780 //----------------------------------------------------------------------------
782 //----------------------------------------------------------------------------
783 void vvSlicer::UpdateDisplayExtent()
785 vtkImageData *input = this->GetInput();
786 if (!input || !this->ImageActor) {
789 input->UpdateInformation();
791 // Local copy of extent
793 for(unsigned int i=0; i<6; i++){
794 if (mUseReducedExtent)
795 w_ext[i] = mReducedExtent[i];
797 w_ext[i] = input->GetWholeExtent()[i];
801 w_ext[ this->SliceOrientation*2 ] = this->Slice;
802 w_ext[ this->SliceOrientation*2+1 ] = this->Slice;
805 this->ImageActor->SetDisplayExtent(w_ext);
808 double position[3] = {0.,0.,0.};
809 double positionInc = (Renderer->GetActiveCamera()->GetPosition()[this->SliceOrientation] > this->Slice)?10:-10;
810 position[this->SliceOrientation] += positionInc;
812 // Overlay image actor
813 if (mOverlay && mOverlayActor->GetVisibility()) {
815 mOverlayReslice->GetOutput()->UpdateInformation();
816 this->ConvertImageToImageDisplayExtent(input, w_ext, mOverlayReslice->GetOutput(), overExtent);
817 ClipDisplayedExtent(overExtent, mOverlayMapper->GetInput()->GetWholeExtent());
818 mOverlayActor->SetDisplayExtent( overExtent );
819 mOverlayActor->SetPosition(position);
821 position[this->SliceOrientation] += positionInc;
823 // Fusion image actor
824 if (mFusion && mFusionActor->GetVisibility()) {
826 mFusionReslice->GetOutput()->UpdateInformation();
827 this->ConvertImageToImageDisplayExtent(input, w_ext, mFusionReslice->GetOutput(), fusExtent);
828 ClipDisplayedExtent(fusExtent, mFusionMapper->GetInput()->GetWholeExtent());
829 mFusionActor->SetDisplayExtent(fusExtent);
830 mFusionActor->SetPosition(position);
832 position[this->SliceOrientation] += positionInc;
834 // Vector field actor
835 if (mVF && mVFActor->GetVisibility()) {
837 mVF->GetVTKImages()[0]->UpdateInformation();
838 this->ConvertImageToImageDisplayExtent(input, w_ext, mVF->GetVTKImages()[0], vfExtent);
839 ClipDisplayedExtent(vfExtent, mVOIFilter->GetInput()->GetWholeExtent());
840 mVOIFilter->SetVOI(vfExtent);
841 int orientation[3] = {1,1,1};
842 orientation[this->SliceOrientation] = 0;
843 mGlyphFilter->SetOrientation(orientation[0], orientation[1], orientation[2]);
845 mVFActor->SetPosition(position);
847 position[this->SliceOrientation] += positionInc;
853 for(unsigned int i=0; i<6; i++)
854 bounds[i] = ImageActor->GetBounds()[i];
855 bounds[ this->SliceOrientation*2 ] = ImageActor->GetBounds()[ this->SliceOrientation*2 ]-fabs(0.5/this->GetInput()->GetSpacing()[this->SliceOrientation]);
856 bounds[ this->SliceOrientation*2+1 ] = ImageActor->GetBounds()[ this->SliceOrientation*2+1 ]+fabs(0.5/this->GetInput()->GetSpacing()[this->SliceOrientation]);
857 mClipBox->SetBounds(bounds);
860 mLandActor->SetPosition(position);
863 // Figure out the correct clipping range
864 if (this->Renderer) {
865 if (this->InteractorStyle &&
866 this->InteractorStyle->GetAutoAdjustCameraClippingRange()) {
867 this->Renderer->ResetCameraClippingRange();
869 vtkCamera *cam = this->Renderer->GetActiveCamera();
872 this->ImageActor->GetBounds(bounds);
873 double spos = (double)bounds[this->SliceOrientation * 2];
874 double cpos = (double)cam->GetPosition()[this->SliceOrientation];
875 double range = fabs(spos - cpos);
876 double *spacing = input->GetSpacing();
878 ((double)spacing[0] + (double)spacing[1] + (double)spacing[2]) / 3.0;
879 cam->SetClippingRange(range - avg_spacing * 3.0, range + avg_spacing * 3.0);
884 //----------------------------------------------------------------------------
886 //----------------------------------------------------------------------------
887 void vvSlicer::ConvertImageToImageDisplayExtent(vtkImageData *sourceImage, const int sourceExtent[6],
888 vtkImageData *targetImage, int targetExtent[6])
891 for(unsigned int i=0; i<6; i++) {
892 // From source voxel coordinates to world coordinates
893 dExtents[i] = sourceImage->GetOrigin()[i/2] + sourceImage->GetSpacing()[i/2] * sourceExtent[i];
895 // From world coordinates to floating point target voxel coordinates
896 dExtents[i] = (dExtents[i]- targetImage->GetOrigin()[i/2]) / targetImage->GetSpacing()[i/2];
899 targetExtent[i] = itk::Math::Round<double>(dExtents[i]);
902 //----------------------------------------------------------------------------
904 //----------------------------------------------------------------------------
905 void vvSlicer::ClipDisplayedExtent(int extent[6], int refExtent[6])
910 //2D overlay on 3D image specific case
911 if (refExtent[4] == refExtent[5]) {
913 extent[4] = refExtent[4];
914 extent[5] = refExtent[5];
917 for (int i = 0; i < maxBound; i = i+2) {
918 //if we are totally outside the image
919 if ( extent[i] > refExtent[i+1] || extent[i+1] < refExtent[i] ) {
923 //crop to the limit of the image
924 extent[i] = (extent[i] > refExtent[i]) ? extent[i] : refExtent[i];
925 extent[i] = (extent[i] < refExtent[i+1]) ? extent[i] : refExtent[i+1];
926 extent[i+1] = (extent[i+1] > refExtent[i]) ? extent[i+1] : refExtent[i];
927 extent[i+1] = (extent[i+1] < refExtent[i+1]) ? extent[i+1] : refExtent[i+1];
930 for (int i = 0; i < maxBound; i = i+2) {
931 extent[i] = refExtent[i];
932 extent[i+1] = refExtent[i];
935 //----------------------------------------------------------------------------
938 //----------------------------------------------------------------------------
939 void vvSlicer::UpdateOrientation()
941 // Set the camera position
942 vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL;
944 switch (this->SliceOrientation) {
945 case vtkImageViewer2::SLICE_ORIENTATION_XY:
946 cam->SetFocalPoint(0,0,0);
947 cam->SetPosition(0,0,-1); // -1 if medical ?
948 cam->SetViewUp(0,-1,0);
951 case vtkImageViewer2::SLICE_ORIENTATION_XZ:
952 cam->SetFocalPoint(0,0,0);
953 cam->SetPosition(0,-1,0); // 1 if medical ?
954 cam->SetViewUp(0,0,1);
957 case vtkImageViewer2::SLICE_ORIENTATION_YZ:
958 cam->SetFocalPoint(0,0,0);
959 cam->SetPosition(-1,0,0); // -1 if medical ?
960 cam->SetViewUp(0,0,1);
965 //----------------------------------------------------------------------------
968 //----------------------------------------------------------------------------
969 void vvSlicer::SetOpacity(double s)
971 this->GetImageActor()->SetOpacity(s);
973 //----------------------------------------------------------------------------
976 //----------------------------------------------------------------------------
977 void vvSlicer::SetRenderWindow(int orientation, vtkRenderWindow * rw)
979 this->Superclass::SetRenderWindow(rw);
980 this->SetupInteractor(rw->GetInteractor());
981 ca->SetImageActor(this->GetImageActor());
982 ca->SetWindowLevel(this->GetWindowLevel());
983 ca->SetText(2, "<slice>");
984 ca->SetText(3, "<window>\n<level>");
996 crossCursor->SetModelBounds(bounds);
997 this->GetRenderer()->AddActor(pdmA);
998 this->GetRenderer()->AddActor(ca);
999 this->GetRenderer()->ResetCamera();
1001 //this is just a mapping between the labeling of the orientations presented to the user and
1002 //the one used by vtk
1003 SetSliceOrientation(2-(orientation%3));
1006 //----------------------------------------------------------------------------
1009 //----------------------------------------------------------------------------
1010 void vvSlicer::ResetCamera()
1012 this->GetRenderer()->ResetCamera();
1014 //----------------------------------------------------------------------------
1017 //----------------------------------------------------------------------------
1018 void vvSlicer::SetDisplayMode(bool i)
1020 this->GetImageActor()->SetVisibility(i);
1021 this->GetAnnotation()->SetVisibility(i);
1022 this->GetRenderer()->SetDraw(i);
1024 mLandActor->SetVisibility(i);
1025 pdmA->SetVisibility(i);
1027 UpdateDisplayExtent();
1029 //----------------------------------------------------------------------------
1032 //----------------------------------------------------------------------------
1033 void vvSlicer::FlipHorizontalView()
1035 vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL;
1037 double *position = cam->GetPosition();
1038 switch (this->SliceOrientation) {
1039 case vtkImageViewer2::SLICE_ORIENTATION_XY:
1040 cam->SetPosition(position[0],position[1],-position[2]);
1043 case vtkImageViewer2::SLICE_ORIENTATION_XZ:
1044 cam->SetPosition(position[0],-position[1],position[2]);
1047 case vtkImageViewer2::SLICE_ORIENTATION_YZ:
1048 cam->SetPosition(-position[0],position[1],position[2]);
1051 this->Renderer->ResetCameraClippingRange();
1052 this->UpdateDisplayExtent();
1055 //----------------------------------------------------------------------------
1058 //----------------------------------------------------------------------------
1059 void vvSlicer::FlipVerticalView()
1061 vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL;
1063 FlipHorizontalView();
1064 double *viewup = cam->GetViewUp();
1065 cam->SetViewUp(-viewup[0],-viewup[1],-viewup[2]);
1066 this->UpdateDisplayExtent();
1069 //----------------------------------------------------------------------------
1072 //----------------------------------------------------------------------------
1073 void vvSlicer::SetColorWindow(double window)
1075 vtkLookupTable* LUT = static_cast<vtkLookupTable*>(this->GetWindowLevel()->GetLookupTable());
1077 double level = this->GetWindowLevel()->GetLevel();
1078 LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4);
1081 this->vtkImageViewer2::SetColorWindow(window);
1083 //----------------------------------------------------------------------------
1086 //----------------------------------------------------------------------------
1087 void vvSlicer::SetColorLevel(double level)
1089 vtkLookupTable* LUT = static_cast<vtkLookupTable*>(this->GetWindowLevel()->GetLookupTable());
1091 double window = this->GetWindowLevel()->GetWindow();
1092 LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4);
1095 this->vtkImageViewer2::SetColorLevel(level);
1097 //----------------------------------------------------------------------------
1099 //----------------------------------------------------------------------------
1100 // Returns the min an the max value in a 41x41 region around the mouse pointer
1101 void vvSlicer::GetExtremasAroundMousePointer(double & min, double & max)
1103 //Get mouse pointer position in view coordinates
1104 double fLocalExtents[6];
1105 for(int i=0; i<3; i++) {
1106 fLocalExtents[i*2 ] = mCurrent[i];
1107 fLocalExtents[i*2+1] = mCurrent[i];
1109 this->Renderer->WorldToView(fLocalExtents[0], fLocalExtents[2], fLocalExtents[4]);
1110 this->Renderer->WorldToView(fLocalExtents[1], fLocalExtents[3], fLocalExtents[5]);
1111 for(int i=0; i<3; i++) {
1112 if (i!=SliceOrientation) { //SR: assumes that SliceOrientation is valid in ViewCoordinates (???)
1113 fLocalExtents[i*2 ] -= 0.2;
1114 fLocalExtents[i*2+1] += 0.2;
1117 this->Renderer->ViewToWorld(fLocalExtents[0], fLocalExtents[2], fLocalExtents[4]);
1118 this->Renderer->ViewToWorld(fLocalExtents[1], fLocalExtents[3], fLocalExtents[5]);
1120 //Convert to image pixel coordinates (rounded)
1121 int iLocalExtents[6];
1122 for(int i=0; i<3; i++) {
1123 fLocalExtents[i*2 ] = (fLocalExtents[i*2 ] - this->GetInput()->GetOrigin()[i])/this->GetInput()->GetSpacing()[i];
1124 fLocalExtents[i*2+1] = (fLocalExtents[i*2+1] - this->GetInput()->GetOrigin()[i])/this->GetInput()->GetSpacing()[i];
1126 iLocalExtents[i*2 ] = lrint(fLocalExtents[i*2 ]);
1127 iLocalExtents[i*2+1] = lrint(fLocalExtents[i*2+1]);
1129 if(iLocalExtents[i*2 ]>iLocalExtents[i*2+1])
1130 std::swap(iLocalExtents[i*2], iLocalExtents[i*2+1]);
1133 vtkSmartPointer<vtkExtractVOI> voiFilter = vtkSmartPointer<vtkExtractVOI>::New();
1134 voiFilter->SetInput(this->GetInput());
1135 voiFilter->SetVOI(iLocalExtents);
1136 voiFilter->Update();
1137 if (!voiFilter->GetOutput()->GetNumberOfPoints()) {
1143 vtkSmartPointer<vtkImageAccumulate> accFilter = vtkSmartPointer<vtkImageAccumulate>::New();
1144 accFilter->SetInput(voiFilter->GetOutput());
1145 accFilter->Update();
1147 min = *(accFilter->GetMin());
1148 max = *(accFilter->GetMax());
1150 //----------------------------------------------------------------------------
1152 //----------------------------------------------------------------------------
1153 double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, int X, double Y, double Z, int &ix, int &iy, int &iz, int component)
1158 if (ix < image->GetWholeExtent()[0] ||
1159 ix > image->GetWholeExtent()[1] ||
1160 iy < image->GetWholeExtent()[2] ||
1161 iy > image->GetWholeExtent()[3] ||
1162 iz < image->GetWholeExtent()[4] ||
1163 iz > image->GetWholeExtent()[5] )
1164 return std::numeric_limits<double>::quiet_NaN();
1166 image->SetUpdateExtent(ix, ix, iy, iy, iz, iz);
1168 return image->GetScalarComponentAsDouble(ix, iy, iz, component);
1170 //----------------------------------------------------------------------------
1172 //----------------------------------------------------------------------------
1173 void vvSlicer::Render()
1175 if (this->GetWindowLevel()->GetLookupTable() && !this->mOverlay && !this->mFusion) {
1176 legend->SetLookupTable(this->GetWindowLevel()->GetLookupTable());
1177 legend->SetVisibility(1);
1178 } else legend->SetVisibility(0);
1180 if (ca->GetVisibility()) {
1181 std::string worldPos = "";
1182 std::stringstream world1;
1183 std::stringstream world2;
1184 std::stringstream world3;
1185 world1 << (int)mCurrent[0];
1186 world2 << (int)mCurrent[1];
1187 world3 << (int)mCurrent[2];
1188 double X = (mCurrent[0] - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0];
1189 double Y = (mCurrent[1] - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1];
1190 double Z = (mCurrent[2] - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2];
1192 // if (X < this->GetInput()->GetWholeExtent()[0]) X = this->GetInput()->GetWholeExtent()[0];
1193 // else if (X > this->GetInput()->GetWholeExtent()[1]) X = this->GetInput()->GetWholeExtent()[1];
1194 // if (Y < this->GetInput()->GetWholeExtent()[2]) Y = this->GetInput()->GetWholeExtent()[2];
1195 // else if (Y > this->GetInput()->GetWholeExtent()[3]) Y = this->GetInput()->GetWholeExtent()[3];
1196 // if (Z < this->GetInput()->GetWholeExtent()[4]) Z = this->GetInput()->GetWholeExtent()[4];
1197 // else if (Z > this->GetInput()->GetWholeExtent()[5]) Z = this->GetInput()->GetWholeExtent()[5];
1199 if (X >= this->GetInput()->GetWholeExtent()[0] &&
1200 X <= this->GetInput()->GetWholeExtent()[1] &&
1201 Y >= this->GetInput()->GetWholeExtent()[2] &&
1202 Y <= this->GetInput()->GetWholeExtent()[3] &&
1203 Z >= this->GetInput()->GetWholeExtent()[4] &&
1204 Z <= this->GetInput()->GetWholeExtent()[5]) {
1208 double value = this->GetScalarComponentAsDouble(this->GetInput(), X, Y, Z, ix, iy, iz);
1210 std::stringstream pixel1;
1211 std::stringstream pixel2;
1212 std::stringstream pixel3;
1213 std::stringstream temps;
1217 temps << mCurrentTSlice;
1219 std::stringstream val;
1221 worldPos += "data value : " + val.str();
1222 worldPos += "\n mm : " + world1.str() + " " + world2.str() + " " +
1223 world3.str() + " " + temps.str();
1224 worldPos += "\n pixel : " + pixel1.str() + " " + pixel2.str() + " " +
1225 pixel3.str() + " " + temps.str();
1227 ca->SetText(1,worldPos.c_str());
1230 if (pdmA->GetVisibility()) {
1231 double x = mCursor[0];
1232 double y = mCursor[1];
1233 double z = mCursor[2];
1234 double xCursor = (x - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0];
1235 double yCursor = (y - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1];
1236 double zCursor = (z - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2];
1238 if (xCursor >= this->GetImageActor()->GetDisplayExtent()[0] &&
1239 xCursor < this->GetImageActor()->GetDisplayExtent()[1]+1 &&
1240 yCursor >= this->GetImageActor()->GetDisplayExtent()[2] &&
1241 yCursor < this->GetImageActor()->GetDisplayExtent()[3]+1 &&
1242 zCursor >= this->GetImageActor()->GetDisplayExtent()[4] &&
1243 zCursor < this->GetImageActor()->GetDisplayExtent()[5]+1 ) {
1244 vtkRenderer * renderer = this->Renderer;
1246 renderer->WorldToView(x,y,z);
1247 renderer->ViewToNormalizedViewport(x,y,z);
1248 renderer->NormalizedViewportToViewport(x,y);
1249 renderer->ViewportToNormalizedDisplay(x,y);
1250 renderer->NormalizedDisplayToDisplay(x,y);
1251 crossCursor->SetFocalPoint(x,y,z);
1253 crossCursor->SetFocalPoint(-1,-1,z);
1257 if (mOverlay && mOverlayActor->GetVisibility()) {
1258 mOverlayMapper->SetWindow(this->GetColorWindow());
1259 mOverlayMapper->SetLevel(this->GetColorLevel());
1260 mOverlayMapper->GetOutput()->SetUpdateExtent(mOverlayActor->GetDisplayExtent());
1261 mOverlayMapper->GetOutput()->Update();
1262 mOverlayMapper->Update();
1267 this->GetRenderWindow()->Render();
1269 //----------------------------------------------------------------------------
1272 //----------------------------------------------------------------------------
1273 void vvSlicer::UpdateCursorPosition()
1275 if (this->GetImageActor()->GetVisibility()) {
1276 pdmA->SetVisibility(true);
1277 mCursor[0] = mCurrent[0];
1278 mCursor[1] = mCurrent[1];
1279 mCursor[2] = mCurrent[2];
1280 mCursor[3] = mCurrentTSlice;
1283 //----------------------------------------------------------------------------
1286 //----------------------------------------------------------------------------
1287 void vvSlicer::UpdateLandmarks()
1289 vtkPolyData *pd = static_cast<vtkPolyData*>(mLandClipper->GetInput());
1290 if (pd->GetPoints()) {
1291 mLandGlyph->SetRange(0,1);
1292 mLandGlyph->Modified();
1293 mLandGlyph->Update();
1295 mClipBox->Modified();
1296 mLandClipper->Update();
1297 mLandMapper->Update();
1301 //----------------------------------------------------------------------------
1304 //----------------------------------------------------------------------------
1305 void vvSlicer::SetSlice(int slice)
1307 int *range = this->GetSliceRange();
1309 if (slice < range[0]) {
1311 } else if (slice > range[1]) {
1316 if (this->Slice == slice) {
1320 this->Slice = slice;
1323 this->UpdateDisplayExtent();
1325 // Seems to work without this line
1328 //----------------------------------------------------------------------------
1331 //----------------------------------------------------------------------------
1332 void vvSlicer::SetContourSlice()
1334 if (mSurfaceCutActors.size() > 0)
1335 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
1336 i!=mSurfaceCutActors.end(); i++)
1337 (*i)->SetCutSlice((this->Slice)*this->GetImage()->GetSpacing()[this->SliceOrientation]+
1338 this->GetImage()->GetOrigin()[this->SliceOrientation]);
1340 //----------------------------------------------------------------------------
1343 //----------------------------------------------------------------------------
1344 void vvSlicer::ForceUpdateDisplayExtent()
1346 this->UpdateDisplayExtent();
1348 //----------------------------------------------------------------------------
1351 //----------------------------------------------------------------------------
1352 int* vvSlicer::GetDisplayExtent()
1354 return this->GetImageActor()->GetDisplayExtent();
1356 //----------------------------------------------------------------------------
1359 //----------------------------------------------------------------------------
1360 void vvSlicer::PrintSelf(ostream& os, vtkIndent indent)
1362 this->Superclass::PrintSelf(os, indent);
1364 //----------------------------------------------------------------------------
1366 //----------------------------------------------------------------------------
1367 void vvSlicer::SetVFColor(double r, double g, double b)
1369 double mVFColorHSV[3];
1374 vtkMath::RGBToHSV(mVFColor, mVFColorHSV);
1375 mVFColorLUT->SetHueRange(mVFColorHSV[0], mVFColorHSV[0]);
1376 mVFColorLUT->SetSaturationRange(mVFColorHSV[1],mVFColorHSV[1]);
1377 mVFColorLUT->SetValueRange(mVFColorHSV[2], mVFColorHSV[2]);