/*========================================================================= * * 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 itkConstNeighborhoodIteratorWithOnlyIndex_hxx #define itkConstNeighborhoodIteratorWithOnlyIndex_hxx namespace itk { template bool ConstNeighborhoodIteratorWithOnlyIndex::InBounds() const { if (m_IsInBoundsValid) { return m_IsInBounds; } bool ans = true; for (DimensionValueType i = 0; i < Dimension; ++i) { if (m_Loop[i] < m_InnerBoundsLow[i] || m_Loop[i] >= m_InnerBoundsHigh[i]) { m_InBounds[i] = ans = false; } else { m_InBounds[i] = true; } } m_IsInBounds = ans; m_IsInBoundsValid = true; return ans; } template bool ConstNeighborhoodIteratorWithOnlyIndex::IndexInBounds(const NeighborIndexType n, OffsetType & internalIndex, OffsetType & offset) const { if (!m_NeedToUseBoundaryCondition) { return true; } else if (this->InBounds()) // Is this whole neighborhood in bounds? { return true; } else { bool flag = true; internalIndex = this->ComputeInternalIndex(n); // Is this pixel in bounds? for (DimensionValueType i = 0; i < Dimension; ++i) { if (m_InBounds[i]) { offset[i] = 0; // this dimension in bounds } else // part of this dimension spills out of bounds { // Calculate overlap for this dimension const OffsetValueType OverlapLow = m_InnerBoundsLow[i] - m_Loop[i]; if (internalIndex[i] < OverlapLow) { flag = false; offset[i] = OverlapLow - internalIndex[i]; } else { const auto overlapHigh = static_cast(this->GetSize(i) - ((m_Loop[i] + 2) - m_InnerBoundsHigh[i])); if (overlapHigh < internalIndex[i]) { flag = false; offset[i] = overlapHigh - internalIndex[i]; } else { offset[i] = 0; } } } } return flag; } } template auto ConstNeighborhoodIteratorWithOnlyIndex::ComputeInternalIndex(NeighborIndexType n) const -> OffsetType { OffsetType ans; auto r = static_cast(n); for (long i = static_cast(Dimension) - 1; i >= 0; --i) { ans[i] = static_cast(r / this->GetStride(i)); r = r % this->GetStride(i); } return ans; } template auto ConstNeighborhoodIteratorWithOnlyIndex::GetBoundingBoxAsImageRegion() const -> RegionType { const IndexValueType zero{}; const RegionType ans(this->GetIndex(zero), this->GetSize()); return ans; } template ConstNeighborhoodIteratorWithOnlyIndex::ConstNeighborhoodIteratorWithOnlyIndex(const Self & orig) : Neighborhood(orig) { m_Bound = orig.m_Bound; m_BeginIndex = orig.m_BeginIndex; m_ConstImage = orig.m_ConstImage; m_EndIndex = orig.m_EndIndex; m_Loop = orig.m_Loop; m_Region = orig.m_Region; m_NeedToUseBoundaryCondition = orig.m_NeedToUseBoundaryCondition; for (DimensionValueType i = 0; i < Dimension; ++i) { m_InBounds[i] = orig.m_InBounds[i]; } m_IsInBoundsValid = orig.m_IsInBoundsValid; m_IsInBounds = orig.m_IsInBounds; m_InnerBoundsLow = orig.m_InnerBoundsLow; m_InnerBoundsHigh = orig.m_InnerBoundsHigh; } template ConstNeighborhoodIteratorWithOnlyIndex::ConstNeighborhoodIteratorWithOnlyIndex(const SizeType & radius, const ImageType * ptr, const RegionType & region) { this->Initialize(radius, ptr, region); } template void ConstNeighborhoodIteratorWithOnlyIndex::SetEndIndex() { if (m_Region.GetNumberOfPixels() > 0) { m_EndIndex = m_Region.GetIndex(); m_EndIndex[Dimension - 1] = m_Region.GetIndex()[Dimension - 1] + static_cast(m_Region.GetSize()[Dimension - 1]); } else { // Region has no pixels, so set the end index to be the begin index m_EndIndex = m_Region.GetIndex(); } } template void ConstNeighborhoodIteratorWithOnlyIndex::GoToBegin() { this->SetLocation(m_BeginIndex); } template void ConstNeighborhoodIteratorWithOnlyIndex::GoToEnd() { this->SetLocation(m_EndIndex); } template void ConstNeighborhoodIteratorWithOnlyIndex::Initialize(const SizeType & radius, const ImageType * ptr, const RegionType & region) { m_ConstImage = ptr; m_Region = region; this->SetRadius(radius); this->SetBeginIndex(region.GetIndex()); this->SetLocation(region.GetIndex()); this->SetBound(region.GetSize()); this->SetEndIndex(); // now determine whether boundary conditions are going to be needed const IndexType bStart = ptr->GetBufferedRegion().GetIndex(); const SizeType bSize = ptr->GetBufferedRegion().GetSize(); const IndexType rStart = region.GetIndex(); const SizeType rSize = region.GetSize(); m_NeedToUseBoundaryCondition = false; for (DimensionValueType i = 0; i < Dimension; ++i) { const auto overlapLow = static_cast((rStart[i] - static_cast(radius[i])) - bStart[i]); const auto overlapHigh = static_cast( (bStart[i] + bSize[i]) - (rStart[i] + rSize[i] + static_cast(radius[i]))); if (overlapLow < 0) // out of bounds condition, define a region of { m_NeedToUseBoundaryCondition = true; break; } if (overlapHigh < 0) { m_NeedToUseBoundaryCondition = true; break; } } m_IsInBoundsValid = false; m_IsInBounds = false; } template ConstNeighborhoodIteratorWithOnlyIndex & ConstNeighborhoodIteratorWithOnlyIndex::operator=(const Self & orig) { if (this != &orig) { Superclass::operator=(orig); m_Bound = orig.m_Bound; m_ConstImage = orig.m_ConstImage; m_EndIndex = orig.m_EndIndex; m_Loop = orig.m_Loop; m_Region = orig.m_Region; m_BeginIndex = orig.m_BeginIndex; m_NeedToUseBoundaryCondition = orig.m_NeedToUseBoundaryCondition; m_InnerBoundsLow = orig.m_InnerBoundsLow; m_InnerBoundsHigh = orig.m_InnerBoundsHigh; for (DimensionValueType i = 0; i < Dimension; ++i) { m_InBounds[i] = orig.m_InBounds[i]; } m_IsInBoundsValid = orig.m_IsInBoundsValid; m_IsInBounds = orig.m_IsInBounds; } return *this; } template bool ConstNeighborhoodIteratorWithOnlyIndex::operator<(const Self & it) const { for (DimensionValueType i = 1; i <= Dimension; ++i) { if (this->GetIndex()[Dimension - i] < it.GetIndex()[Dimension - i]) { return true; } if (this->GetIndex()[Dimension - i] > it.GetIndex()[Dimension - i]) { return false; } } return false; } template bool ConstNeighborhoodIteratorWithOnlyIndex::operator<=(const Self & it) const { if (this->operator==(it)) { return true; } return this->operator<(it); } template bool ConstNeighborhoodIteratorWithOnlyIndex::operator>(const Self & it) const { for (DimensionValueType i = 1; i <= Dimension; ++i) { if (this->GetIndex()[Dimension - i] > it.GetIndex()[Dimension - i]) { return true; } if (this->GetIndex()[Dimension - i] < it.GetIndex()[Dimension - i]) { return false; } } return false; } template bool ConstNeighborhoodIteratorWithOnlyIndex::operator>=(const Self & it) const { if (this->operator==(it)) { return true; } return this->operator>(it); } template bool ConstNeighborhoodIteratorWithOnlyIndex::IsAtEnd() const { // m_EndIndex is at end of iteration when its greatest dimension // is at the bound for that dimension. if (this->GetIndex()[Dimension - 1] > this->m_EndIndex[Dimension - 1]) { ExceptionObject e(__FILE__, __LINE__); std::ostringstream msg; msg << "In method IsAtEnd, GetIndex()[Dimension - 1] = " << GetIndex()[Dimension - 1] << " is greater than m_EndIndex[Dimension - 1] = " << this->m_EndIndex[Dimension - 1] << std::endl << " " << *this; e.SetDescription(msg.str().c_str()); throw e; } return (this->GetIndex()[Dimension - 1] == this->m_EndIndex[Dimension - 1]); } template ConstNeighborhoodIteratorWithOnlyIndex & ConstNeighborhoodIteratorWithOnlyIndex::operator++() { // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. m_IsInBoundsValid = false; // Check loop bounds, wrap. for (DimensionValueType i = 0; i < Dimension; ++i) { m_Loop[i]++; if (m_Loop[i] == m_Bound[i]) { // Let the last dimension stay at m_Bound[i], // signifying we are at the end. if (i < (Dimension - 1)) { m_Loop[i] = m_BeginIndex[i]; } } else { break; } } return *this; } template ConstNeighborhoodIteratorWithOnlyIndex & ConstNeighborhoodIteratorWithOnlyIndex::operator--() { // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. m_IsInBoundsValid = false; // Check loop bounds, wrap. for (DimensionValueType i = 0; i < Dimension; ++i) { if (m_Loop[i] == m_BeginIndex[i]) { m_Loop[i] = m_Bound[i] - 1; } else { m_Loop[i]--; break; } } return *this; } template void ConstNeighborhoodIteratorWithOnlyIndex::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); DimensionValueType i; os << indent; os << "ConstNeighborhoodIteratorWithOnlyIndex {this= " << this; os << ", m_Region = { Start = {"; for (i = 0; i < Dimension; ++i) { os << m_Region.GetIndex()[i] << ' '; } os << "}, Size = { "; for (i = 0; i < Dimension; ++i) { os << m_Region.GetSize()[i] << ' '; } os << "} }"; os << ", m_BeginIndex = { "; for (i = 0; i < Dimension; ++i) { os << m_BeginIndex[i] << ' '; } os << "} , m_EndIndex = { "; for (i = 0; i < Dimension; ++i) { os << m_EndIndex[i] << ' '; } os << "} , m_Loop = { "; for (i = 0; i < Dimension; ++i) { os << m_Loop[i] << ' '; } os << "}, m_Bound = { "; for (i = 0; i < Dimension; ++i) { os << m_Bound[i] << ' '; } os << "}, m_IsInBounds = {" << m_IsInBounds; os << "}, m_IsInBoundsValid = {" << m_IsInBoundsValid; os << indent << ", m_InnerBoundsLow = { "; for (i = 0; i < Dimension; ++i) { os << m_InnerBoundsLow[i] << ' '; } os << "}, m_InnerBoundsHigh = { "; for (i = 0; i < Dimension; ++i) { os << m_InnerBoundsHigh[i] << ' '; } os << "} }" << std::endl; } template void ConstNeighborhoodIteratorWithOnlyIndex::SetBound(const SizeType & size) { SizeType radius = this->GetRadius(); const IndexType imageBRStart = m_ConstImage->GetBufferedRegion().GetIndex(); SizeType imageBRSize = m_ConstImage->GetBufferedRegion().GetSize(); // Set the bounds and the wrapping offsets. Inner bounds are the loop // indices where the iterator will begin to overlap the edge of the image // buffered region. for (DimensionValueType i = 0; i < Dimension; ++i) { m_Bound[i] = m_BeginIndex[i] + static_cast(size[i]); m_InnerBoundsHigh[i] = static_cast(imageBRStart[i] + static_cast(imageBRSize[i]) - static_cast(radius[i])); m_InnerBoundsLow[i] = static_cast(imageBRStart[i] + static_cast(radius[i])); } } template ConstNeighborhoodIteratorWithOnlyIndex & ConstNeighborhoodIteratorWithOnlyIndex::operator+=(const OffsetType & idx) { // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. m_IsInBoundsValid = false; // Update loop counter values m_Loop += idx; return *this; } template ConstNeighborhoodIteratorWithOnlyIndex & ConstNeighborhoodIteratorWithOnlyIndex::operator-=(const OffsetType & idx) { // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. m_IsInBoundsValid = false; // Update loop counter values m_Loop -= idx; return *this; } } // namespace itk #endif