/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkZeroFluxNeumannBoundaryCondition_hxx #define itkZeroFluxNeumannBoundaryCondition_hxx namespace itk { template auto ZeroFluxNeumannBoundaryCondition::operator()(const OffsetType & point_index, const OffsetType & boundary_offset, const NeighborhoodType * data) const -> OutputPixelType { int linear_index = 0; // Return the value of the pixel at the closest boundary point. for (unsigned int i = 0; i < ImageDimension; ++i) { linear_index += (point_index[i] + boundary_offset[i]) * data->GetStride(i); } // The reinterpret_cast is necessary, cause we will have a warning if we // do not do this. (In fact this function exists for legacy // reasons. The overloaded function below should be (and is) used instead). // See any of the neighborhood iterators. // // (data->operator[](linear_index)) is guaranteed to be a pointer to // TImage::PixelType except for VectorImage, in which case, it will be a // pointer to TImage::InternalPixelType. // // A typical neighborhood iterator working on an image will use the boundary // condition in the following manner: // // \code // // Initialize the functor typically in the constructor. // m_NeighborhoodAccessorFunctor = image->GetNeighborhoodAccessor(); // m_NeighborhoodAccessorFunctor->SetBegin( image->GetBufferPointer() ); // // m_NeighborhoodAccessorFunctor.BoundaryCondition( // point_index, boundary_offset, data, m_ChosenBoundaryCondition ); // \endcode // return static_cast(*(reinterpret_cast((data->operator[](linear_index))))); } template auto ZeroFluxNeumannBoundaryCondition::operator()( const OffsetType & point_index, const OffsetType & boundary_offset, const NeighborhoodType * data, const NeighborhoodAccessorFunctorType & neighborhoodAccessorFunctor) const -> OutputPixelType { int linear_index = 0; // Return the value of the pixel at the closest boundary point. for (unsigned int i = 0; i < ImageDimension; ++i) { linear_index += (point_index[i] + boundary_offset[i]) * data->GetStride(i); } return static_cast(neighborhoodAccessorFunctor.Get(data->operator[](linear_index))); } template auto ZeroFluxNeumannBoundaryCondition::GetInputRequestedRegion( const RegionType & inputLargestPossibleRegion, const RegionType & outputRequestedRegion) const -> RegionType { IndexType inputIndex = inputLargestPossibleRegion.GetIndex(); SizeType inputSize = inputLargestPossibleRegion.GetSize(); IndexType outputIndex = outputRequestedRegion.GetIndex(); SizeType outputSize = outputRequestedRegion.GetSize(); IndexType requestIndex; SizeType requestSize; for (unsigned int i = 0; i < ImageDimension; ++i) { // Check if the output region is entirely below the low index of // the image region. if (outputIndex[i] + static_cast(outputSize[i]) <= inputIndex[i]) { // Include an image layer one pixel thick closest to the outputRequestedRegion requestIndex[i] = inputIndex[i]; requestSize[i] = 1; } // Check if the output is entirely above the high index of the // image region. else if (outputIndex[i] >= inputIndex[i] + static_cast(inputSize[i])) { // Include an image layer one pixel thick closest to the outputRequestedRegion requestIndex[i] = inputIndex[i] + static_cast(inputSize[i]) - 1; requestSize[i] = 1; } // The output region intersects the image region. else { requestIndex[i] = inputIndex[i]; requestSize[i] = inputSize[i]; // First check the start index if (requestIndex[i] < outputIndex[i]) { // How much do we need to adjust OffsetValueType crop = outputIndex[i] - requestIndex[i]; // Adjust the start index and the size of the current region requestIndex[i] += crop; requestSize[i] -= static_cast(crop); } // Now check the final size if (requestIndex[i] + static_cast(requestSize[i]) > outputIndex[i] + static_cast(outputSize[i])) { // How much do we need to adjust OffsetValueType crop = requestIndex[i] + static_cast(requestSize[i]) - outputIndex[i] - static_cast(outputSize[i]); // Adjust the size requestSize[i] -= static_cast(crop); } } } RegionType inputRequestedRegion(requestIndex, requestSize); return inputRequestedRegion; } template auto ZeroFluxNeumannBoundaryCondition::GetPixel(const IndexType & index, const TInputImage * image) const -> OutputPixelType { RegionType imageRegion = image->GetLargestPossibleRegion(); IndexType imageIndex = imageRegion.GetIndex(); SizeType imageSize = imageRegion.GetSize(); IndexType lookupIndex; for (unsigned int i = 0; i < ImageDimension; ++i) { IndexValueType lowerIndex = imageIndex[i]; IndexValueType upperIndex = imageIndex[i] + static_cast(imageSize[i]) - 1; if (index[i] < lowerIndex) { lookupIndex[i] = lowerIndex; } else if (index[i] > upperIndex) { lookupIndex[i] = upperIndex; } else // in bounds { lookupIndex[i] = index[i]; } } return static_cast(image->GetPixel(lookupIndex)); } } // end namespace itk #endif