/*========================================================================= Program: Visualization Toolkit Module: vtkROIStencilSource.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 "vtkROIStencilSource.h" #include "vtkDataArray.h" #include "vtkImageData.h" #include "vtkImageStencilData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkStreamingDemandDrivenPipeline.h" #include vtkStandardNewMacro(vtkROIStencilSource); //------------------------------------------------------------------------------ vtkROIStencilSource::vtkROIStencilSource() { this->SetNumberOfInputPorts(0); this->Shape = vtkROIStencilSource::BOX; this->Bounds[0] = 0.0; this->Bounds[1] = 0.0; this->Bounds[2] = 0.0; this->Bounds[3] = 0.0; this->Bounds[4] = 0.0; this->Bounds[5] = 0.0; } //------------------------------------------------------------------------------ vtkROIStencilSource::~vtkROIStencilSource() = default; //------------------------------------------------------------------------------ void vtkROIStencilSource::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Shape: " << this->GetShapeAsString() << "\n"; os << indent << "Bounds: " << this->Bounds[0] << " " << this->Bounds[1] << " " << this->Bounds[2] << " " << this->Bounds[3] << " " << this->Bounds[4] << " " << this->Bounds[5] << "\n"; } //------------------------------------------------------------------------------ const char* vtkROIStencilSource::GetShapeAsString() { switch (this->Shape) { case vtkROIStencilSource::BOX: return "Box"; case vtkROIStencilSource::ELLIPSOID: return "Ellipsoid"; case vtkROIStencilSource::CYLINDERX: return "CylinderX"; case vtkROIStencilSource::CYLINDERY: return "CylinderY"; case vtkROIStencilSource::CYLINDERZ: return "CylinderZ"; } return ""; } //------------------------------------------------------------------------------ // tolerance for stencil operations #define VTK_STENCIL_TOL 7.62939453125e-06 //------------------------------------------------------------------------------ // Compute a reduced extent based on the Center and Size of the shape. // // Also returns the center and radius in voxel-index units. static void vtkROIStencilSourceSubExtent(vtkROIStencilSource* self, const double origin[3], const double spacing[3], const int extent[6], int subextent[6], double icenter[3], double iradius[3]) { double bounds[6]; self->GetBounds(bounds); for (int i = 0; i < 3; i++) { icenter[i] = (0.5 * (bounds[2 * i] + bounds[2 * i + 1]) - origin[i]) / spacing[i]; iradius[i] = 0.5 * (bounds[2 * i + 1] - bounds[2 * i]) / spacing[i]; if (iradius[i] < 0) { iradius[i] = -iradius[i]; } iradius[i] += VTK_STENCIL_TOL; double emin = icenter[i] - iradius[i]; double emax = icenter[i] + iradius[i]; subextent[2 * i] = extent[2 * i]; subextent[2 * i + 1] = extent[2 * i + 1]; if (extent[2 * i] < emin) { subextent[2 * i] = VTK_INT_MAX; if (extent[2 * i + 1] >= emin) { subextent[2 * i] = vtkMath::Floor(emin) + 1; } } if (extent[2 * i + 1] > emax) { subextent[2 * i + 1] = VTK_INT_MIN; if (extent[2 * i] <= emax) { subextent[2 * i + 1] = vtkMath::Floor(emax); } } } } //------------------------------------------------------------------------------ static int vtkROIStencilSourceBox(vtkROIStencilSource* self, vtkImageStencilData* data, const int extent[6], const double origin[3], const double spacing[3]) { int subextent[6]; double icenter[3]; double iradius[3]; vtkROIStencilSourceSubExtent(self, origin, spacing, extent, subextent, icenter, iradius); // for keeping track of progress unsigned long count = 0; unsigned long target = static_cast( (subextent[5] - subextent[4] + 1) * (subextent[3] - subextent[2] + 1) / 50.0); target++; for (int idZ = subextent[4]; idZ <= subextent[5]; idZ++) { for (int idY = subextent[2]; idY <= subextent[3]; idY++) { if (count % target == 0) { self->UpdateProgress(count / (50.0 * target)); } count++; int r1 = subextent[0]; int r2 = subextent[1]; if (r2 >= r1) { data->InsertNextExtent(r1, r2, idY, idZ); } } // for idY } // for idZ return 1; } //------------------------------------------------------------------------------ static int vtkROIStencilSourceEllipsoid(vtkROIStencilSource* self, vtkImageStencilData* data, const int extent[6], const double origin[3], const double spacing[3]) { int subextent[6]; double icenter[3]; double iradius[3]; vtkROIStencilSourceSubExtent(self, origin, spacing, extent, subextent, icenter, iradius); // for keeping track of progress unsigned long count = 0; unsigned long target = static_cast( (subextent[5] - subextent[4] + 1) * (subextent[3] - subextent[2] + 1) / 50.0); target++; for (int idZ = subextent[4]; idZ <= subextent[5]; idZ++) { double z = (idZ - icenter[2]) / iradius[2]; for (int idY = subextent[2]; idY <= subextent[3]; idY++) { if (count % target == 0) { self->UpdateProgress(count / (50.0 * target)); } count++; double y = (idY - icenter[1]) / iradius[1]; double x2 = 1.0 - y * y - z * z; if (x2 < 0) { continue; } double x = sqrt(x2); int r1 = subextent[0]; int r2 = subextent[1]; double xmin = icenter[0] - x * iradius[0]; double xmax = icenter[0] + x * iradius[0]; if (r1 < xmin) { r1 = vtkMath::Floor(xmin) + 1; } if (r2 > xmax) { r2 = vtkMath::Floor(xmax); } if (r2 >= r1) { data->InsertNextExtent(r1, r2, idY, idZ); } } // for idY } // for idZ return 1; } //------------------------------------------------------------------------------ static int vtkROIStencilSourceCylinderX(vtkROIStencilSource* self, vtkImageStencilData* data, const int extent[6], const double origin[3], const double spacing[3]) { int subextent[6]; double icenter[3]; double iradius[3]; vtkROIStencilSourceSubExtent(self, origin, spacing, extent, subextent, icenter, iradius); // for keeping track of progress unsigned long count = 0; unsigned long target = static_cast( (subextent[5] - subextent[4] + 1) * (subextent[3] - subextent[2] + 1) / 50.0); target++; for (int idZ = subextent[4]; idZ <= subextent[5]; idZ++) { double z = (idZ - icenter[2]) / iradius[2]; for (int idY = subextent[2]; idY <= subextent[3]; idY++) { if (count % target == 0) { self->UpdateProgress(count / (50.0 * target)); } count++; double y = (idY - icenter[1]) / iradius[1]; if (y * y + z * z > 1.0) { continue; } int r1 = subextent[0]; int r2 = subextent[1]; if (r2 >= r1) { data->InsertNextExtent(r1, r2, idY, idZ); } } // for idY } // for idZ return 1; } //------------------------------------------------------------------------------ static int vtkROIStencilSourceCylinderY(vtkROIStencilSource* self, vtkImageStencilData* data, int extent[6], double origin[3], double spacing[3]) { int subextent[6]; double icenter[3]; double iradius[3]; vtkROIStencilSourceSubExtent(self, origin, spacing, extent, subextent, icenter, iradius); // for keeping track of progress unsigned long count = 0; unsigned long target = static_cast( (subextent[5] - subextent[4] + 1) * (subextent[3] - subextent[2] + 1) / 50.0); target++; for (int idZ = subextent[4]; idZ <= subextent[5]; idZ++) { double z = (idZ - icenter[2]) / iradius[2]; for (int idY = subextent[2]; idY <= subextent[3]; idY++) { if (count % target == 0) { self->UpdateProgress(count / (50.0 * target)); } count++; double x2 = 1.0 - z * z; if (x2 < 0) { continue; } double x = sqrt(x2); int r1 = subextent[0]; int r2 = subextent[1]; double xmin = icenter[0] - x * iradius[0]; double xmax = icenter[0] + x * iradius[0]; if (r1 < xmin) { r1 = vtkMath::Floor(xmin) + 1; } if (r2 > xmax) { r2 = vtkMath::Floor(xmax); } if (r2 >= r1) { data->InsertNextExtent(r1, r2, idY, idZ); } } // for idY } // for idZ return 1; } //------------------------------------------------------------------------------ static int vtkROIStencilSourceCylinderZ(vtkROIStencilSource* self, vtkImageStencilData* data, int extent[6], double origin[3], double spacing[3]) { int subextent[6]; double icenter[3]; double iradius[3]; vtkROIStencilSourceSubExtent(self, origin, spacing, extent, subextent, icenter, iradius); // for keeping track of progress unsigned long count = 0; unsigned long target = static_cast( (subextent[5] - subextent[4] + 1) * (subextent[3] - subextent[2] + 1) / 50.0); target++; for (int idZ = subextent[4]; idZ <= subextent[5]; idZ++) { for (int idY = subextent[2]; idY <= subextent[3]; idY++) { if (count % target == 0) { self->UpdateProgress(count / (50.0 * target)); } count++; double y = (idY - icenter[1]) / iradius[1]; double x2 = 1.0 - y * y; if (x2 < 0) { continue; } double x = sqrt(x2); int r1 = subextent[0]; int r2 = subextent[1]; double xmin = icenter[0] - x * iradius[0]; double xmax = icenter[0] + x * iradius[0]; if (r1 < xmin) { r1 = vtkMath::Floor(xmin) + 1; } if (r2 > xmax) { r2 = vtkMath::Floor(xmax); } if (r2 >= r1) { data->InsertNextExtent(r1, r2, idY, idZ); } } // for idY } // for idZ return 1; } //------------------------------------------------------------------------------ int vtkROIStencilSource::RequestData( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { int extent[6]; double origin[3]; double spacing[3]; int result = 1; this->Superclass::RequestData(request, inputVector, outputVector); vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkImageStencilData* data = vtkImageStencilData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent); outInfo->Get(vtkDataObject::ORIGIN(), origin); outInfo->Get(vtkDataObject::SPACING(), spacing); switch (this->Shape) { case vtkROIStencilSource::BOX: result = vtkROIStencilSourceBox(this, data, extent, origin, spacing); break; case vtkROIStencilSource::ELLIPSOID: result = vtkROIStencilSourceEllipsoid(this, data, extent, origin, spacing); break; case vtkROIStencilSource::CYLINDERX: result = vtkROIStencilSourceCylinderX(this, data, extent, origin, spacing); break; case vtkROIStencilSource::CYLINDERY: result = vtkROIStencilSourceCylinderY(this, data, extent, origin, spacing); break; case vtkROIStencilSource::CYLINDERZ: result = vtkROIStencilSourceCylinderZ(this, data, extent, origin, spacing); break; } return result; }