/*========================================================================= Program: Visualization Toolkit Module: vtkImageSlice.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkImageSlice.h" #include "vtkCamera.h" #include "vtkDataArray.h" #include "vtkImageData.h" #include "vtkImageMapper3D.h" #include "vtkImageProperty.h" #include "vtkLinearTransform.h" #include "vtkLookupTable.h" #include "vtkMatrix4x4.h" #include "vtkObjectFactory.h" #include "vtkRenderer.h" #include "vtkTransform.h" #include vtkStandardNewMacro(vtkImageSlice); //------------------------------------------------------------------------------ class vtkImageToImageMapper3DFriendship { public: static void SetCurrentProp(vtkImageMapper3D* mapper, vtkImageSlice* prop) { mapper->CurrentProp = prop; } static void SetCurrentRenderer(vtkImageMapper3D* mapper, vtkRenderer* ren) { mapper->CurrentRenderer = ren; } static void SetStackedImagePass(vtkImageMapper3D* mapper, int pass) { switch (pass) { case 0: mapper->MatteEnable = true; mapper->ColorEnable = false; mapper->DepthEnable = false; break; case 1: mapper->MatteEnable = false; mapper->ColorEnable = true; mapper->DepthEnable = false; break; case 2: mapper->MatteEnable = false; mapper->ColorEnable = false; mapper->DepthEnable = true; break; default: mapper->MatteEnable = true; mapper->ColorEnable = true; mapper->DepthEnable = true; break; } } }; //------------------------------------------------------------------------------ vtkImageSlice::vtkImageSlice() { this->Mapper = nullptr; this->Property = nullptr; this->ForceTranslucent = false; } //------------------------------------------------------------------------------ vtkImageSlice::~vtkImageSlice() { if (this->Property) { this->Property->UnRegister(this); } this->SetMapper(nullptr); } //------------------------------------------------------------------------------ void vtkImageSlice::GetImages(vtkPropCollection* vc) { vc->AddItem(this); } //------------------------------------------------------------------------------ void vtkImageSlice::ShallowCopy(vtkProp* prop) { vtkImageSlice* v = vtkImageSlice::SafeDownCast(prop); if (v != nullptr) { this->SetMapper(v->GetMapper()); this->SetProperty(v->GetProperty()); } // Now do superclass this->vtkProp3D::ShallowCopy(prop); } //------------------------------------------------------------------------------ void vtkImageSlice::SetMapper(vtkImageMapper3D* mapper) { if (this->Mapper != mapper) { if (this->Mapper != nullptr) { vtkImageToImageMapper3DFriendship::SetCurrentProp(this->Mapper, nullptr); this->Mapper->UnRegister(this); } this->Mapper = mapper; if (this->Mapper != nullptr) { this->Mapper->Register(this); vtkImageToImageMapper3DFriendship::SetCurrentProp(this->Mapper, this); } this->Modified(); } } //------------------------------------------------------------------------------ // Get the bounds for this Volume as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax). double* vtkImageSlice::GetBounds() { int i, n; double bbox[24], *fptr; // get the bounds of the Mapper if we have one if (!this->Mapper) { return this->Bounds; } const double* bounds = this->Mapper->GetBounds(); // Check for the special case when the mapper's bounds are unknown if (!bounds) { return nullptr; } // fill out vertices of a bounding box bbox[0] = bounds[1]; bbox[1] = bounds[3]; bbox[2] = bounds[5]; bbox[3] = bounds[1]; bbox[4] = bounds[2]; bbox[5] = bounds[5]; bbox[6] = bounds[0]; bbox[7] = bounds[2]; bbox[8] = bounds[5]; bbox[9] = bounds[0]; bbox[10] = bounds[3]; bbox[11] = bounds[5]; bbox[12] = bounds[1]; bbox[13] = bounds[3]; bbox[14] = bounds[4]; bbox[15] = bounds[1]; bbox[16] = bounds[2]; bbox[17] = bounds[4]; bbox[18] = bounds[0]; bbox[19] = bounds[2]; bbox[20] = bounds[4]; bbox[21] = bounds[0]; bbox[22] = bounds[3]; bbox[23] = bounds[4]; // make sure matrix (transform) is up-to-date this->ComputeMatrix(); // and transform into actors coordinates fptr = bbox; for (n = 0; n < 8; n++) { double homogeneousPt[4] = { fptr[0], fptr[1], fptr[2], 1.0 }; this->Matrix->MultiplyPoint(homogeneousPt, homogeneousPt); fptr[0] = homogeneousPt[0] / homogeneousPt[3]; fptr[1] = homogeneousPt[1] / homogeneousPt[3]; fptr[2] = homogeneousPt[2] / homogeneousPt[3]; fptr += 3; } // now calc the new bounds this->Bounds[0] = this->Bounds[2] = this->Bounds[4] = VTK_DOUBLE_MAX; this->Bounds[1] = this->Bounds[3] = this->Bounds[5] = -VTK_DOUBLE_MAX; for (i = 0; i < 8; i++) { for (n = 0; n < 3; n++) { if (bbox[i * 3 + n] < this->Bounds[n * 2]) { this->Bounds[n * 2] = bbox[i * 3 + n]; } if (bbox[i * 3 + n] > this->Bounds[n * 2 + 1]) { this->Bounds[n * 2 + 1] = bbox[i * 3 + n]; } } } return this->Bounds; } //------------------------------------------------------------------------------ // Get the minimum X bound double vtkImageSlice::GetMinXBound() { this->GetBounds(); return this->Bounds[0]; } // Get the maximum X bound double vtkImageSlice::GetMaxXBound() { this->GetBounds(); return this->Bounds[1]; } // Get the minimum Y bound double vtkImageSlice::GetMinYBound() { this->GetBounds(); return this->Bounds[2]; } // Get the maximum Y bound double vtkImageSlice::GetMaxYBound() { this->GetBounds(); return this->Bounds[3]; } // Get the minimum Z bound double vtkImageSlice::GetMinZBound() { this->GetBounds(); return this->Bounds[4]; } // Get the maximum Z bound double vtkImageSlice::GetMaxZBound() { this->GetBounds(); return this->Bounds[5]; } //------------------------------------------------------------------------------ // Does this prop have some translucent polygonal geometry? vtkTypeBool vtkImageSlice::HasTranslucentPolygonalGeometry() { if (this->ForceTranslucent) { return 1; } // Unless forced to translucent, always render during opaque pass, // to keep the behavior predictable and because depth-peeling kills // alpha-blending. return 0; } //------------------------------------------------------------------------------ int vtkImageSlice::RenderTranslucentPolygonalGeometry(vtkViewport* viewport) { vtkDebugMacro(<< "vtkImageSlice::RenderTranslucentPolygonalGeometry"); if (this->HasTranslucentPolygonalGeometry()) { this->Render(vtkRenderer::SafeDownCast(viewport)); return 1; } return 0; } //------------------------------------------------------------------------------ int vtkImageSlice::RenderOpaqueGeometry(vtkViewport* viewport) { vtkDebugMacro(<< "vtkImageSlice::RenderOpaqueGeometry"); if (!this->HasTranslucentPolygonalGeometry()) { this->Render(vtkRenderer::SafeDownCast(viewport)); return 1; } return 0; } //------------------------------------------------------------------------------ int vtkImageSlice::RenderOverlay(vtkViewport* vtkNotUsed(viewport)) { vtkDebugMacro(<< "vtkImageSlice::RenderOverlay"); // Render the image as an underlay return 0; } //------------------------------------------------------------------------------ void vtkImageSlice::Render(vtkRenderer* ren) { // Force the creation of a property if (!this->Property) { this->GetProperty(); } if (!this->Property) { vtkErrorMacro(<< "Error generating a property!\n"); return; } if (!this->Mapper) { vtkErrorMacro(<< "You must specify a mapper!\n"); return; } vtkImageToImageMapper3DFriendship::SetCurrentRenderer(this->Mapper, ren); this->Update(); // only call the mapper if it has an input vtkImageData* input = this->Mapper->GetInput(); if (input) { int* extent = input->GetExtent(); if (extent[0] <= extent[1] && extent[2] <= extent[3] && extent[4] <= extent[5]) { this->Mapper->Render(ren, this); this->EstimatedRenderTime += this->Mapper->GetTimeToDraw(); } } vtkImageToImageMapper3DFriendship::SetCurrentRenderer(this->Mapper, nullptr); } //------------------------------------------------------------------------------ void vtkImageSlice::ReleaseGraphicsResources(vtkWindow* win) { // pass this information onto the mapper if (this->Mapper) { this->Mapper->ReleaseGraphicsResources(win); } } //------------------------------------------------------------------------------ void vtkImageSlice::Update() { if (this->Mapper) { vtkImageToImageMapper3DFriendship::SetCurrentProp(this->Mapper, this); this->Mapper->Update(); } } //------------------------------------------------------------------------------ void vtkImageSlice::SetProperty(vtkImageProperty* property) { if (this->Property != property) { if (this->Property != nullptr) { this->Property->UnRegister(this); } this->Property = property; if (this->Property != nullptr) { this->Property->Register(this); } this->Modified(); } } //------------------------------------------------------------------------------ vtkImageProperty* vtkImageSlice::GetProperty() { if (this->Property == nullptr) { this->Property = vtkImageProperty::New(); this->Property->Register(this); this->Property->Delete(); } return this->Property; } //------------------------------------------------------------------------------ vtkMTimeType vtkImageSlice::GetMTime() { vtkMTimeType mTime = this->Superclass::GetMTime(); vtkMTimeType time; if (this->Property != nullptr) { time = this->Property->GetMTime(); mTime = (time > mTime ? time : mTime); } if (this->UserMatrix != nullptr) { time = this->UserMatrix->GetMTime(); mTime = (time > mTime ? time : mTime); } if (this->UserTransform != nullptr) { time = this->UserTransform->GetMTime(); mTime = (time > mTime ? time : mTime); } return mTime; } //------------------------------------------------------------------------------ vtkMTimeType vtkImageSlice::GetRedrawMTime() { vtkMTimeType mTime = this->GetMTime(); vtkMTimeType time; if (this->Mapper != nullptr) { time = this->Mapper->GetMTime(); mTime = (time > mTime ? time : mTime); if (this->GetMapper()->GetInputAlgorithm() != nullptr) { this->GetMapper()->GetInputAlgorithm()->Update(); time = this->Mapper->GetInput()->GetMTime(); mTime = (time > mTime ? time : mTime); } } if (this->Property != nullptr) { time = this->Property->GetMTime(); mTime = (time > mTime ? time : mTime); if (this->Property->GetLookupTable() != nullptr) { // check the lookup table mtime time = this->Property->GetLookupTable()->GetMTime(); mTime = (time > mTime ? time : mTime); } } return mTime; } //------------------------------------------------------------------------------ void vtkImageSlice::SetStackedImagePass(int pass) { if (this->Mapper) { vtkImageToImageMapper3DFriendship::SetStackedImagePass(this->Mapper, pass); } } //------------------------------------------------------------------------------ void vtkImageSlice::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); if (this->Property) { os << indent << "Property:\n"; this->Property->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "Property: (not defined)\n"; } if (this->Mapper) { os << indent << "Mapper:\n"; this->Mapper->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "Mapper: (not defined)\n"; } // make sure our bounds are up to date if (this->Mapper) { this->GetBounds(); os << indent << "Bounds: (" << this->Bounds[0] << ", " << this->Bounds[1] << ") (" << this->Bounds[2] << ") (" << this->Bounds[3] << ") (" << this->Bounds[4] << ") (" << this->Bounds[5] << ")\n"; } else { os << indent << "Bounds: (not defined)\n"; } os << indent << "ForceTranslucent: " << (this->ForceTranslucent ? "On\n" : "Off\n"); }