/*========================================================================= * * 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 itkConstShapedNeighborhoodIterator_hxx #define itkConstShapedNeighborhoodIterator_hxx namespace itk { template void ConstShapedNeighborhoodIterator::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "ActiveIndexList: ["; for (auto it = m_ActiveIndexList.begin(); it != m_ActiveIndexList.end(); ++it) { os << indent.GetNextIndent() << *it << ' '; } os << "] "; os << indent << "CenterIsActive: " << (m_CenterIsActive ? "On" : "Off") << std::endl; } template void ConstShapedNeighborhoodIterator::ActivateIndex(NeighborIndexType n) { const OffsetValueType * OffsetTable = this->m_ConstImage->GetOffsetTable(); // Insert so that the list remains ordered. auto it = m_ActiveIndexList.begin(); if (m_ActiveIndexList.empty()) { m_ActiveIndexList.push_front(n); } else { while (n > *it) { ++it; if (it == m_ActiveIndexList.end()) { break; } } if (it == m_ActiveIndexList.end()) { m_ActiveIndexList.insert(it, n); } else if (n != *it) { m_ActiveIndexList.insert(it, n); } } // Did we just activate the index at the center of the neighborhood? if (n == this->GetCenterNeighborhoodIndex()) { m_CenterIsActive = true; } // Set the pointer in the neighborhood location just activated. this->GetElement(n) = this->GetCenterPointer(); for (unsigned int i = 0; i < Dimension; ++i) { this->GetElement(n) += OffsetTable[i] * this->GetOffset(n)[i]; } } template void ConstShapedNeighborhoodIterator::DeactivateIndex(NeighborIndexType n) { auto it = m_ActiveIndexList.begin(); if (m_ActiveIndexList.empty()) { return; } else { while (n != *it) { ++it; if (it == m_ActiveIndexList.end()) { return; } } m_ActiveIndexList.erase(it); } // Did we just deactivate the index at the center of the neighborhood? if (n == this->GetCenterNeighborhoodIndex()) { m_CenterIsActive = false; } } template template void ConstShapedNeighborhoodIterator::CreateActiveListFromNeighborhood( const Neighborhood & neighborhood) { if (this->GetRadius() != neighborhood.GetRadius()) { itkGenericExceptionMacro("Radius of shaped iterator(" << this->GetRadius() << ") does not equal radius of neighborhood(" << neighborhood.GetRadius() << ')'); } typename Neighborhood::ConstIterator nit; NeighborIndexType idx = 0; for (nit = neighborhood.Begin(); nit != neighborhood.End(); ++nit, ++idx) { if (*nit) { this->ActivateOffset(GetOffset(idx)); } else { this->DeactivateOffset(GetOffset(idx)); } } } template ConstShapedNeighborhoodIterator & ConstShapedNeighborhoodIterator::operator++() { // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. this->m_IsInBoundsValid = false; if (this->m_BoundaryCondition->RequiresCompleteNeighborhood()) { // Some Boundary Conditions, such as ZeroFluxNeumann can return // values from anywhere in the neighborhood, thus we can not do // the shaped optimization. NeighborhoodIterator::operator++(); } else { IndexListConstIterator it; // Center pointer must be updated whether or not it is active. if (!m_CenterIsActive) { this->GetElement(this->GetCenterNeighborhoodIndex())++; } // Increment pointers for only the active pixels. for (it = m_ActiveIndexList.begin(); it != m_ActiveIndexList.end(); ++it) { (this->GetElement(*it))++; } // Check loop bounds, wrap & add pointer offsets if needed. for (unsigned int ii = 0; ii < Dimension; ++ii) { this->m_Loop[ii]++; if (this->m_Loop[ii] == this->m_Bound[ii]) { this->m_Loop[ii] = this->m_BeginIndex[ii]; if (!m_CenterIsActive) { this->GetElement(this->GetCenterNeighborhoodIndex()) += this->m_WrapOffset[ii]; } for (it = m_ActiveIndexList.begin(); it != m_ActiveIndexList.end(); ++it) { (this->GetElement(*it)) += this->m_WrapOffset[ii]; } } else { break; } } } return *this; } template ConstShapedNeighborhoodIterator & ConstShapedNeighborhoodIterator::operator--() { unsigned int i; IndexListConstIterator it; // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. this->m_IsInBoundsValid = false; if (this->m_BoundaryCondition->RequiresCompleteNeighborhood()) { // Some Boundary Conditions, such as ZeroFluxNeumann can return // values from anywhere in the neighborhood, thus we can not do // the shaped optimization. NeighborhoodIterator::operator--(); } else { // Center pointer must be updated whether or not it is active. if (!m_CenterIsActive) { this->GetElement(this->GetCenterNeighborhoodIndex())--; } // Decrement pointers for only the active pixels. for (it = m_ActiveIndexList.begin(); it != m_ActiveIndexList.end(); ++it) { (this->GetElement(*it))--; } // Check loop bounds, wrap & add pointer offsets if needed. for (i = 0; i < Dimension; ++i) { if (this->m_Loop[i] == this->m_BeginIndex[i]) { this->m_Loop[i] = this->m_Bound[i] - 1; if (!m_CenterIsActive) { this->GetElement(this->GetCenterNeighborhoodIndex()) -= this->m_WrapOffset[i]; } for (it = m_ActiveIndexList.begin(); it != m_ActiveIndexList.end(); ++it) { (this->GetElement(*it)) -= this->m_WrapOffset[i]; } } else { this->m_Loop[i]--; break; } } } return *this; } template ConstShapedNeighborhoodIterator & ConstShapedNeighborhoodIterator::operator+=(const OffsetType & idx) { unsigned int i; IndexListConstIterator it; OffsetValueType accumulator = 0; const OffsetValueType * stride = this->GetImagePointer()->GetOffsetTable(); // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. this->m_IsInBoundsValid = false; if (this->m_BoundaryCondition->RequiresCompleteNeighborhood()) { // Some Boundary Conditions, such as ZeroFluxNeumann can return // values from anywhere in the neighborhood, thus we can not do // the shaped optimization. NeighborhoodIterator::operator+=(idx); } else { // Offset from the increment in the lowest dimension accumulator += idx[0]; // Offsets from the stride lengths in each dimension. // // Because the image offset table is based on its buffer size and // not its requested region size, we don't have to worry about // adding in the wrapping offsets. for (i = 1; i < Dimension; ++i) { accumulator += idx[i] * stride[i]; } // Center pointer is always updated even if not active. if (!m_CenterIsActive) { this->GetElement(this->GetCenterNeighborhoodIndex()) += accumulator; } // Increment pointers only for those active pixels for (it = m_ActiveIndexList.begin(); it != m_ActiveIndexList.end(); ++it) { (this->GetElement(*it)) += accumulator; } // Update loop counter values this->m_Loop += idx; } return *this; } template ConstShapedNeighborhoodIterator & ConstShapedNeighborhoodIterator::operator-=(const OffsetType & idx) { unsigned int i; IndexListConstIterator it; OffsetValueType accumulator = 0; const OffsetValueType * stride = this->GetImagePointer()->GetOffsetTable(); // Repositioning neighborhood, previous bounds check on neighborhood // location is invalid. this->m_IsInBoundsValid = false; if (this->m_BoundaryCondition->RequiresCompleteNeighborhood()) { // Some Boundary Conditions, such as ZeroFluxNeumann can return // values from anywhere in the neighborhood, thus we can not do // the shaped optimization. NeighborhoodIterator::operator-=(idx); } else { // Offset from the increment in the lowest dimension accumulator += idx[0]; // Offsets from the stride lengths in each dimension. // // Because the image offset table is based on its buffer size and // not its requested region size, we don't have to worry about // adding in the wrapping offsets. for (i = 1; i < Dimension; ++i) { accumulator += idx[i] * stride[i]; } // Center pointer is always updated even if not active. if (!m_CenterIsActive) { this->GetElement(this->GetCenterNeighborhoodIndex()) -= accumulator; } // Increment pointers only for those active pixels for (it = m_ActiveIndexList.begin(); it != m_ActiveIndexList.end(); ++it) { (this->GetElement(*it)) -= accumulator; } // Update loop counter values this->m_Loop -= idx; } return *this; } } // namespace itk #endif