/*========================================================================= Program: Visualization Toolkit Module: vtkAbstractImageInterpolator.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 "vtkAbstractImageInterpolator.h" #include "vtkDataArray.h" #include "vtkImageData.h" #include "vtkImageInterpolatorInternals.h" #include "vtkPointData.h" #include "vtkTypeTraits.h" #include "vtkTemplateAliasMacro.h" // turn off 64-bit ints when templating over all types, because // they cannot be faithfully represented by doubles #undef VTK_USE_INT64 #define VTK_USE_INT64 0 #undef VTK_USE_UINT64 #define VTK_USE_UINT64 0 //------------------------------------------------------------------------------ // default do-nothing interpolation functions namespace { template struct vtkInterpolateNOP { static void InterpolationFunc(vtkInterpolationInfo* info, const F point[3], F* outPtr); static void RowInterpolationFunc( vtkInterpolationWeights* weights, int idX, int idY, int idZ, F* outPtr, int n); }; template void vtkInterpolateNOP::InterpolationFunc(vtkInterpolationInfo*, const F[3], F*) { } template void vtkInterpolateNOP::RowInterpolationFunc(vtkInterpolationWeights*, int, int, int, F*, int) { } } // end anonymous namespace //------------------------------------------------------------------------------ vtkAbstractImageInterpolator::vtkAbstractImageInterpolator() { this->Scalars = nullptr; this->BorderMode = VTK_IMAGE_BORDER_CLAMP; this->SlidingWindow = false; for (int i = 0; i < 6; i++) { this->StructuredBoundsDouble[i] = 0.0; this->StructuredBoundsFloat[i] = 0.0f; } for (int j = 0; j < 3; j++) { this->Extent[2 * j] = 0; this->Extent[2 * j + 1] = -1; this->Spacing[j] = 1.0; this->Origin[j] = 0.0; } this->OutValue = 0.0; this->Tolerance = 7.62939453125e-06; this->ComponentOffset = 0; this->ComponentCount = -1; this->InterpolationInfo = new vtkInterpolationInfo(); this->InterpolationInfo->Array = nullptr; this->InterpolationInfo->NumberOfComponents = 1; this->InterpolationInfo->InterpolationMode = 0; this->InterpolationInfo->ExtraInfo = nullptr; this->InterpolationInfo->Pointer = nullptr; this->InterpolationInfo->Index = 0; this->InterpolationFuncDouble = &(vtkInterpolateNOP::InterpolationFunc); this->InterpolationFuncFloat = &(vtkInterpolateNOP::InterpolationFunc); this->RowInterpolationFuncDouble = &(vtkInterpolateNOP::RowInterpolationFunc); this->RowInterpolationFuncFloat = &(vtkInterpolateNOP::RowInterpolationFunc); } //------------------------------------------------------------------------------ vtkAbstractImageInterpolator::~vtkAbstractImageInterpolator() { if (this->Scalars) { this->Scalars->Delete(); } delete this->InterpolationInfo; } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::DeepCopy(vtkAbstractImageInterpolator* obj) { this->SetTolerance(obj->Tolerance); this->SetOutValue(obj->OutValue); this->SetComponentOffset(obj->ComponentOffset); this->SetComponentCount(obj->ComponentCount); this->SetBorderMode(obj->BorderMode); this->SetSlidingWindow(obj->SlidingWindow); obj->GetExtent(this->Extent); obj->GetOrigin(this->Origin); obj->GetSpacing(this->Spacing); if (this->Scalars) { this->Scalars->Delete(); this->Scalars = nullptr; } if (obj->Scalars) { this->Scalars = obj->Scalars; this->Scalars->Register(this); } *this->InterpolationInfo = *obj->InterpolationInfo; } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Tolerance: " << this->Tolerance << "\n"; os << indent << "OutValue: " << this->OutValue << "\n"; os << indent << "ComponentOffset: " << this->ComponentOffset << "\n"; os << indent << "ComponentCount: " << this->ComponentCount << "\n"; os << indent << "BorderMode: " << this->GetBorderModeAsString() << "\n"; os << indent << "SlidingWindow: " << (this->SlidingWindow ? "On\n" : "Off\n"); os << indent << "Extent: " << this->Extent[0] << " " << this->Extent[1] << " " << this->Extent[2] << " " << this->Extent[3] << " " << this->Extent[4] << " " << this->Extent[5] << "\n"; os << indent << "Origin: " << this->Origin[0] << " " << this->Origin[1] << " " << this->Origin[2] << "\n"; os << indent << "Spacing: " << this->Spacing[0] << " " << this->Spacing[1] << " " << this->Spacing[2] << "\n"; } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::SetBorderMode(vtkImageBorderMode mode) { mode = vtkMath::ClampValue(mode, VTK_IMAGE_BORDER_CLAMP, VTK_IMAGE_BORDER_MIRROR); if (this->BorderMode != mode) { this->BorderMode = mode; this->Modified(); } } //------------------------------------------------------------------------------ const char* vtkAbstractImageInterpolator::GetBorderModeAsString() { switch (this->BorderMode) { case VTK_IMAGE_BORDER_CLAMP: return "Clamp"; case VTK_IMAGE_BORDER_REPEAT: return "Repeat"; case VTK_IMAGE_BORDER_MIRROR: return "Mirror"; } return ""; } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::SetComponentOffset(int offset) { if (this->ComponentOffset != offset) { this->ComponentOffset = offset; this->Modified(); } } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::SetComponentCount(int count) { if (this->ComponentCount != count) { this->ComponentCount = count; this->Modified(); } } //------------------------------------------------------------------------------ int vtkAbstractImageInterpolator::ComputeNumberOfComponents(int inputCount) { // validate the component range to extract int component = this->ComponentOffset; int count = this->ComponentCount; component = ((component > 0) ? component : 0); component = ((component < inputCount) ? component : inputCount - 1); count = ((count < (inputCount - component)) ? count : (inputCount - component)); count = ((count > 0) ? count : (inputCount - component)); return count; } //------------------------------------------------------------------------------ int vtkAbstractImageInterpolator::GetNumberOfComponents() { return this->InterpolationInfo->NumberOfComponents; } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::SetOutValue(double value) { if (this->OutValue != value) { this->OutValue = value; this->Modified(); } } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::SetTolerance(double value) { if (this->Tolerance != value) { this->Tolerance = value; this->Modified(); } } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::SetSlidingWindow(bool x) { if (this->SlidingWindow != x) { this->SlidingWindow = x; this->Modified(); } } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::Initialize(vtkDataObject* o) { // free any previous scalars this->ReleaseData(); // check for valid data vtkImageData* data = vtkImageData::SafeDownCast(o); vtkDataArray* scalars = nullptr; if (data) { scalars = data->GetPointData()->GetScalars(); } if (data == nullptr || scalars == nullptr) { vtkErrorMacro("Initialize(): no image data to interpolate!"); return; } // claim the scalars scalars->Register(this); this->Scalars = scalars; // get the image information data->GetSpacing(this->Spacing); data->GetOrigin(this->Origin); data->GetExtent(this->Extent); // call update this->Update(); } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::ReleaseData() { if (this->Scalars) { this->Scalars->Delete(); this->Scalars = nullptr; } } namespace { //------------------------------------------------------------------------------ template void vtkSlidingWindowAllocateWorkspace(vtkInterpolationWeights* weights, F*) { int* extent = weights->WeightExtent; int kernelSizeX = weights->KernelSize[0]; int kernelSizeY = weights->KernelSize[1]; int kernelSizeZ = weights->KernelSize[2]; vtkIdType rowSize = (extent[1] - extent[0] + 1); rowSize *= weights->NumberOfComponents; // workPtr2 is a cache for partial sums F* workPtr2; // workPtr provides an index into the cache F** workPtr; if (kernelSizeX == 1 && kernelSizeY == 1 && kernelSizeZ == 1) { // no cache is needed for a 1x1x1 kernel workPtr2 = nullptr; workPtr = nullptr; } else if (kernelSizeZ == 1) { // allocate workspace for a 2D sliding window vtkIdType workSize = rowSize * kernelSizeY; workPtr2 = new F[workSize]; // allocate the sliding row pointers workPtr = new F*[kernelSizeY]; for (int i = 0; i < kernelSizeY; i++) { workPtr[i] = workPtr2 + i * rowSize; } } else { // allocate workspace for sliding window (slices and rows) vtkIdType sliceSize = rowSize * (extent[3] - extent[2] + 1); vtkIdType workSize = rowSize * kernelSizeY; workSize += sliceSize * kernelSizeZ; workPtr2 = new F[workSize]; // allocate the sliding row and slice pointers workPtr = new F*[kernelSizeZ + kernelSizeY]; // sliding rows for (int i = 0; i < kernelSizeY; i++) { workPtr[i] = workPtr2 + i * rowSize; } // sliding slices F** slicePtr = workPtr + kernelSizeY; F* workPtr3 = workPtr2 + kernelSizeY * rowSize; for (int i = 0; i < kernelSizeZ; i++) { slicePtr[i] = workPtr3 + i * sliceSize; } } // make the workspace available to the interpolator weights->Workspace = workPtr; // initialize the "last position" of the sliding window to invalid // values (i.e. to a position outside of the extent) weights->LastY = extent[2] - 1; weights->LastZ = extent[4] - 1; } //------------------------------------------------------------------------------ // Apply a 1D filter in the X direction. // The inPtr parameter must be positioned at the correct slice. template void vtkSlidingWindowX(const T* inPtr, F* outPtr, int pixelCount, int ncomp, const vtkIdType* a, const F* f, int kernelSize) { if (kernelSize == 1) { for (int i = 0; i < pixelCount; i++) { // 'a' maps output pixel to input pixel in the x direction const T* tmpPtr = inPtr + (*a++); for (int j = 0; j < ncomp; j++) { *outPtr++ = *tmpPtr++; } } } else { for (int i = 0; i < pixelCount; i++) { const T* tmpPtr = inPtr; for (int j = 0; j < ncomp; j++) { // do the convolution sum in the x direction, where // 'a' gives the input pixel positions and // 'g' gives the weights int k = kernelSize - 1; const vtkIdType* b = a; const F* g = f; F val = (*g++) * tmpPtr[*b++]; do { val += (*g++) * tmpPtr[*b++]; } while (--k); tmpPtr++; *outPtr++ = val; } a += kernelSize; f += kernelSize; } } } //------------------------------------------------------------------------------ // Apply a 1D filter along the Y or Z direction, given kernelSize rows // of data as input and producing one row of data as output. This function // must be called for each row of the output to filter a whole slice. template void vtkSlidingWindowYOrZ( F** rowPtr, F* outPtr, vtkIdType begin, vtkIdType end, const F* f, int kernelSize) { if (kernelSize == 1) { // don't apply the filter, just copy the data F* tmpPtr = *rowPtr + begin; for (vtkIdType i = begin; i < end; i++) { *outPtr++ = *tmpPtr++; } } else { // apply the filter to one row of the image for (vtkIdType i = begin; i < end; i++) { int k = kernelSize - 1; F** tmpPtr = rowPtr; // 'f' is an array of weights const F* g = f; F val = (*g++) * ((*tmpPtr++)[i]); do { val += (*g++) * ((*tmpPtr++)[i]); } while (--k); *outPtr++ = val; } } } //------------------------------------------------------------------------------ // Apply a 2D filter to image slices, // The inPtr parameter must be positioned at the correct slice. template void vtkSlidingWindow2D(const T* inPtr, F* outPtr, const int extent[6], int idX, int idY, int lastIdY, int pixelCount, int ncomp, const vtkIdType* aX, const F* fX, int kernelSizeX, const vtkIdType* aY, const F* fY, int kernelSizeY, F** workPtr) { int extentX = extent[1] - extent[0] + 1; vtkIdType outIncX = ncomp; vtkIdType begin = (idX - extent[0]) * outIncX; vtkIdType end = begin + pixelCount * outIncX; if (kernelSizeY == 1) { // filter only in the X direction vtkSlidingWindowX(&inPtr[*aY], *workPtr, extentX, ncomp, aX, fX, kernelSizeX); // this becomes a copy operation since kernelSizeY is 1 vtkSlidingWindowYOrZ(workPtr, outPtr, begin, end, fY, kernelSizeY); } else { // filter in both X and Y directions, // 'n' is the number of rows of partial sums that can be reused from // the previous y position int n = 0; // if lastIdY was outside of extent, then this is the first iteration if (lastIdY >= extent[2]) { const vtkIdType* lY = aY - (idY - lastIdY) * kernelSizeY; for (int j = 0; j < kernelSizeY; j++) { const vtkIdType* bY = lY + j; const vtkIdType* cY = aY; int i = kernelSizeY - j; do { if (*cY++ != *bY++) { break; } } while (--i); if (i == 0) { // if all indices after offset 'j' match, then 'j' rows worth of // partial sums have to be recomputed and 'n' rows are reusable n = kernelSizeY - j; break; } } } // rotate workspace rows to reuse the rows that can be reused if (n < kernelSizeY) { for (int k = 0; k < n; k++) { int j = kernelSizeY + k - n; F* tmpPtr = workPtr[k]; workPtr[k] = workPtr[j]; workPtr[j] = tmpPtr; } // compute the new rows that are needed for (int k = n; k < kernelSizeY; k++) { vtkSlidingWindowX(&inPtr[aY[k]], workPtr[k], extentX, ncomp, aX, fX, kernelSizeX); } } vtkSlidingWindowYOrZ(workPtr, outPtr, begin, end, fY, kernelSizeY); } } //------------------------------------------------------------------------------ template struct vtkSlidingWindow { static void InterpolateRow( vtkInterpolationWeights* weights, int idX, int idY, int idZ, F* outPtr, int pixelCount); }; //------------------------------------------------------------------------------ // Apply separable blur filter fX, fY, fZ to an image with minimum // memory overhead (3 rows of temp storage for 2D, 3 slices for 3D). // The aX, aY, and aZ contain increments for the X, Y, and Z // directions. template void vtkSlidingWindow::InterpolateRow( vtkInterpolationWeights* weights, int idX, int idY, int idZ, F* outPtr, int pixelCount) { if (!weights->Workspace) { vtkSlidingWindowAllocateWorkspace(weights, outPtr); } int lastIdY = weights->LastY; int lastIdZ = weights->LastZ; weights->LastY = idY; weights->LastZ = idZ; const T* inPtr = static_cast(weights->Pointer); F** workPtr = static_cast(weights->Workspace); const int* extent = weights->WeightExtent; int ncomp = weights->NumberOfComponents; int kernelSizeX = weights->KernelSize[0]; int kernelSizeY = weights->KernelSize[1]; int kernelSizeZ = weights->KernelSize[2]; const vtkIdType* aX = weights->Positions[0]; const vtkIdType* aY = weights->Positions[1]; const vtkIdType* aZ = weights->Positions[2]; const F* fX = static_cast(weights->Weights[0]); const F* fY = static_cast(weights->Weights[1]); const F* fZ = static_cast(weights->Weights[2]); if (kernelSizeX == 1 && kernelSizeY == 1 && kernelSizeZ == 1) { // no interpolation, direct input to output aX += idX * kernelSizeX; aY += idY * kernelSizeY; aZ += idZ * kernelSizeZ; inPtr += *aY + *aZ; for (int j = 0; j < pixelCount; j++) { const T* tmpPtr = inPtr + (*aX++); for (int i = 0; i < ncomp; i++) { *outPtr++ = *tmpPtr++; } } } else if (kernelSizeZ == 1) { // it is possible to just apply a 2D filter to each slice aX += extent[0] * kernelSizeX; aY += idY * kernelSizeY; aZ += idZ * kernelSizeZ; fX += extent[0] * kernelSizeX; fY += idY * kernelSizeY; vtkSlidingWindow2D(&inPtr[*aZ], outPtr, extent, idX, idY, lastIdY, pixelCount, ncomp, aX, fX, kernelSizeX, aY, fY, kernelSizeY, workPtr); } else { // apply filter in all three directions F** slicePtr = workPtr + kernelSizeY; int extentX = extent[1] - extent[0] + 1; vtkIdType outIncX = ncomp; vtkIdType rowSize = extentX * ncomp; aX += extent[0] * kernelSizeX; aY += extent[2] * kernelSizeY; aZ += idZ * kernelSizeZ; fX += extent[0] * kernelSizeX; fY += extent[2] * kernelSizeY; fZ += idZ * kernelSizeZ; // loop through the XY slices if (idZ != lastIdZ) { // look for overlap between the slices that are currently stored and // the slices that will be needed for this iteration int m = 0; if (lastIdZ >= extent[4]) { const vtkIdType* lZ = aZ - (idZ - lastIdZ) * kernelSizeZ; for (int j = 0; j < kernelSizeZ; j++) { const vtkIdType* bZ = lZ + j; const vtkIdType* cZ = aZ; int i = kernelSizeZ - j; do { if (*cZ++ != *bZ++) { break; } } while (--i); if (i == 0) { m = kernelSizeZ - j; break; } } } // reuse m of the temporary slices if (m < kernelSizeZ) { for (int i = 0; i < m; i++) { int j = kernelSizeZ + i - m; F* tmpPtr = slicePtr[i]; slicePtr[i] = slicePtr[j]; slicePtr[j] = tmpPtr; } // compute the new slices that are needed int extentY = extent[3] - extent[2] + 1; for (int i = m; i < kernelSizeZ; i++) { for (int dY = 0; dY < extentY; dY++) { vtkSlidingWindow2D(&inPtr[aZ[i]], slicePtr[i] + dY * rowSize, extent, extent[0], extent[2] + dY, extent[2] + dY - 1, extentX, ncomp, aX, fX, kernelSizeX, aY + dY * kernelSizeY, fY + dY * kernelSizeY, kernelSizeY, workPtr); } } } } // get one row of output data at the current Y,Z position vtkIdType begin = (idY - extent[2]) * rowSize + (idX - extent[0]) * outIncX; vtkIdType end = begin + pixelCount * outIncX; vtkSlidingWindowYOrZ(slicePtr, outPtr, begin, end, fZ, kernelSizeZ); } } //------------------------------------------------------------------------------ // get row interpolation function for different interpolation modes // and different scalar types template void vtkSlidingWindowGetRowInterpolationFunc( void (**summation)(vtkInterpolationWeights* weights, int idX, int idY, int idZ, F* outPtr, int n), int scalarType) { switch (scalarType) { vtkTemplateAliasMacro(*summation = &(vtkSlidingWindow::InterpolateRow)); default: *summation = nullptr; } } } // namespace //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::Update() { vtkDataArray* scalars = this->Scalars; // check for scalars if (!scalars) { this->InterpolationInfo->Pointer = nullptr; this->InterpolationInfo->NumberOfComponents = 1; this->InterpolationInfo->Array = nullptr; this->InterpolationInfo->Index = 0; this->InterpolationFuncDouble = &(vtkInterpolateNOP::InterpolationFunc); this->InterpolationFuncFloat = &(vtkInterpolateNOP::InterpolationFunc); this->RowInterpolationFuncDouble = &(vtkInterpolateNOP::RowInterpolationFunc); this->RowInterpolationFuncFloat = &(vtkInterpolateNOP::RowInterpolationFunc); return; } // set the InterpolationInfo object vtkInterpolationInfo* info = this->InterpolationInfo; vtkIdType* inc = info->Increments; int* extent = info->Extent; extent[0] = this->Extent[0]; extent[1] = this->Extent[1]; extent[2] = this->Extent[2]; extent[3] = this->Extent[3]; extent[4] = this->Extent[4]; extent[5] = this->Extent[5]; // use the Extent and Tolerance to set the bounds double* bounds = this->StructuredBoundsDouble; float* fbounds = this->StructuredBoundsFloat; double tol = this->Tolerance; // always restrict the bounds to the limits of int int supportSize[3]; this->ComputeSupportSize(nullptr, supportSize); // use the max of the three support size values int kernelSize = supportSize[0]; kernelSize = ((supportSize[1] < kernelSize) ? kernelSize : supportSize[1]); kernelSize = ((supportSize[2] < kernelSize) ? kernelSize : supportSize[2]); double minbound = VTK_INT_MIN + kernelSize / 2; double maxbound = VTK_INT_MAX - kernelSize / 2; for (int i = 0; i < 3; i++) { // use min tolerance of 0.5 if just one slice thick double newtol = 0.5 * (extent[2 * i] == extent[2 * i + 1]); newtol = ((newtol > tol) ? newtol : tol); double bound = extent[2 * i] - newtol; bound = ((bound > minbound) ? bound : minbound); fbounds[2 * i] = bounds[2 * i] = bound; bound = extent[2 * i + 1] + newtol; bound = ((bound < maxbound) ? bound : maxbound); fbounds[2 * i + 1] = bounds[2 * i + 1] = bound; } // generate the increments int xdim = extent[1] - extent[0] + 1; int ydim = extent[3] - extent[2] + 1; int ncomp = scalars->GetNumberOfComponents(); inc[0] = ncomp; inc[1] = inc[0] * xdim; inc[2] = inc[1] * ydim; // compute first component and adjust data pointer int component = this->ComponentOffset; component = ((component > 0) ? component : 0); component = ((component < ncomp) ? component : ncomp - 1); int dataSize = scalars->GetDataTypeSize(); void* inPtr = scalars->GetVoidPointer(0); info->Pointer = static_cast(inPtr) + component * dataSize; info->Array = scalars; info->Index = component * dataSize; // set all other elements of the InterpolationInfo info->ScalarType = scalars->GetDataType(); info->NumberOfComponents = this->ComputeNumberOfComponents(ncomp); info->BorderMode = this->BorderMode; // subclass-specific update this->InternalUpdate(); // get the functions that will perform the interpolation this->GetInterpolationFunc(&this->InterpolationFuncDouble); this->GetInterpolationFunc(&this->InterpolationFuncFloat); if (this->SlidingWindow) { this->GetSlidingWindowFunc(&this->RowInterpolationFuncDouble); this->GetSlidingWindowFunc(&this->RowInterpolationFuncFloat); } else { this->GetRowInterpolationFunc(&this->RowInterpolationFuncDouble); this->GetRowInterpolationFunc(&this->RowInterpolationFuncFloat); } } //------------------------------------------------------------------------------ bool vtkAbstractImageInterpolator::Interpolate(const double point[3], double* value) { double p[3]; p[0] = (point[0] - this->Origin[0]) / this->Spacing[0]; p[1] = (point[1] - this->Origin[1]) / this->Spacing[1]; p[2] = (point[2] - this->Origin[2]) / this->Spacing[2]; if (this->CheckBoundsIJK(p)) { this->InterpolationFuncDouble(this->InterpolationInfo, p, value); return true; } int n = this->InterpolationInfo->NumberOfComponents; for (int i = 0; i < n; i++) { value[i] = this->OutValue; } return false; } //------------------------------------------------------------------------------ double vtkAbstractImageInterpolator::Interpolate(double x, double y, double z, int component) { double value = this->OutValue; double point[3]; point[0] = x; point[1] = y; point[2] = z; double p[3]; p[0] = (point[0] - this->Origin[0]) / this->Spacing[0]; p[1] = (point[1] - this->Origin[1]) / this->Spacing[1]; p[2] = (point[2] - this->Origin[2]) / this->Spacing[2]; if (this->CheckBoundsIJK(p)) { vtkInterpolationInfo iinfo(*this->InterpolationInfo); int ncomp = static_cast(iinfo.Increments[0]); ncomp -= this->ComponentOffset; int size = vtkAbstractArray::GetDataTypeSize(iinfo.ScalarType); component = ((component > 0) ? component : 0); component = ((component < ncomp) ? component : ncomp - 1); iinfo.Pointer = (static_cast(iinfo.Pointer) + size * component); iinfo.NumberOfComponents = 1; this->InterpolationFuncDouble(&iinfo, p, &value); } return value; } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::GetInterpolationFunc( void (**)(vtkInterpolationInfo*, const double[3], double*)) { } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::GetInterpolationFunc( void (**)(vtkInterpolationInfo*, const float[3], float*)) { } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::GetRowInterpolationFunc( void (**)(vtkInterpolationWeights*, int, int, int, double*, int)) { } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::GetRowInterpolationFunc( void (**)(vtkInterpolationWeights*, int, int, int, float*, int)) { } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::GetSlidingWindowFunc( void (**)(vtkInterpolationWeights*, int, int, int, double*, int)) { vtkSlidingWindowGetRowInterpolationFunc( &this->RowInterpolationFuncDouble, this->InterpolationInfo->ScalarType); } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::GetSlidingWindowFunc( void (**)(vtkInterpolationWeights*, int, int, int, float*, int)) { vtkSlidingWindowGetRowInterpolationFunc( &this->RowInterpolationFuncFloat, this->InterpolationInfo->ScalarType); } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::PrecomputeWeightsForExtent( const double[16], const int[6], int[6], vtkInterpolationWeights*&) { vtkErrorMacro("PrecomputeWeights not supported for this interpolator"); } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::PrecomputeWeightsForExtent( const float[16], const int[6], int[6], vtkInterpolationWeights*&) { vtkErrorMacro("PrecomputeWeights not supported for this interpolator"); } //------------------------------------------------------------------------------ void vtkAbstractImageInterpolator::FreePrecomputedWeights(vtkInterpolationWeights*& weights) { int* extent = weights->WeightExtent; for (int k = 0; k < 3; k++) { int step = weights->KernelSize[k]; weights->Positions[k] += step * extent[2 * k]; delete[] weights->Positions[k]; if (weights->Weights[k]) { if (weights->WeightType == VTK_FLOAT) { float* constants = static_cast(weights->Weights[k]); constants += step * extent[2 * k]; delete[] constants; } else { double* constants = static_cast(weights->Weights[k]); constants += step * extent[2 * k]; delete[] constants; } } } if (weights->Workspace) { if (weights->WeightType == VTK_FLOAT) { float** workPtr = static_cast(weights->Workspace); float* firstPtr = workPtr[0]; for (int i = 1; i < weights->KernelSize[1]; i++) { firstPtr = (workPtr[i] < firstPtr ? workPtr[i] : firstPtr); } delete[] firstPtr; delete[] workPtr; } else { double** workPtr = static_cast(weights->Workspace); double* firstPtr = workPtr[0]; for (int i = 1; i < weights->KernelSize[1]; i++) { firstPtr = (workPtr[i] < firstPtr ? workPtr[i] : firstPtr); } delete[] firstPtr; delete[] workPtr; } } delete weights; weights = nullptr; }