/*========================================================================= * * 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 itkHilbertPath_hxx #define itkHilbertPath_hxx #include "itkPrintHelper.h" namespace itk { template HilbertPath::HilbertPath() = default; template void HilbertPath::ConstructHilbertPath() { const SizeValueType numberOfPathVertices(static_cast(1) << static_cast(Dimension * this->m_HilbertOrder)); this->m_HilbertPath.resize(numberOfPathVertices); SizeValueType counter = 0; typename HilbertPathType::iterator it; for (it = this->m_HilbertPath.begin(); it != this->m_HilbertPath.end(); ++it) { *it = this->TransformPathIndexToMultiDimensionalIndex(counter++); } } template auto HilbertPath::TransformPathIndexToMultiDimensionalIndex(const PathIndexType id) -> IndexType { PathIndexType d = 0; PathIndexType e = 0; IndexType index; index.Fill(0); for (PathIndexType i = 0; i < this->m_HilbertOrder; ++i) { PathIndexType w = this->GetBitRange(id, Dimension * this->m_HilbertOrder, i * Dimension, (i + 1) * Dimension); PathIndexType l = this->GetGrayCode(w); l = this->GetInverseTransform(e, d, Dimension, l); for (PathIndexType j = 0; j < Dimension; ++j) { PathIndexType b = this->GetBitRange(l, Dimension, j, j + 1); index[j] = this->SetBit(index[j], this->m_HilbertOrder, i, b); } e ^= this->GetLeftBitRotation(this->GetEntry(w), d + 1, Dimension); d = (d + this->GetDirection(w, Dimension) + 1) % Dimension; } return index; } template auto HilbertPath::TransformMultiDimensionalIndexToPathIndex(const IndexType & index) -> PathIndexType { PathIndexType id = 0; PathIndexType d = 0; PathIndexType e = 0; for (PathIndexType i = 0; i < this->m_HilbertOrder; ++i) { PathIndexType l = 0; for (PathIndexType j = 0; j < Dimension; ++j) { PathIndexType b = this->GetBitRange(index[Dimension - j - 1], this->m_HilbertOrder, i, i + 1); l |= b << j; } l = this->GetTransform(e, d, Dimension, l); PathIndexType w = this->GetInverseGrayCode(l); e ^= this->GetLeftBitRotation(this->GetEntry(w), d + 1, Dimension); d = (d + this->GetDirection(w, Dimension) + 1) % Dimension; id = (id << Dimension) | w; } return id; } template auto HilbertPath::GetTransform(const PathIndexType entry, const PathIndexType direction, const PathIndexType width, const PathIndexType x) -> PathIndexType { return (this->GetRightBitRotation(x ^ entry, direction + 1, width)); } template auto HilbertPath::GetInverseTransform(const PathIndexType entry, const PathIndexType direction, const PathIndexType width, const PathIndexType x) -> PathIndexType { return (this->GetLeftBitRotation(x, direction + 1, width) ^ entry); } template auto HilbertPath::GetBitRange(const PathIndexType x, const PathIndexType width, const PathIndexType start, const PathIndexType end) -> PathIndexType { return (x >> (width - end) & ((1 << (end - start)) - 1)); } template auto HilbertPath::GetLeftBitRotation(PathIndexType x, PathIndexType i, const PathIndexType width) -> PathIndexType { return (((x << (i % width)) | (x >> (width - (i % width)))) & ((1 << width) - 1)); } template auto HilbertPath::GetRightBitRotation(PathIndexType x, PathIndexType i, const PathIndexType width) -> PathIndexType { return (((x >> (i % width)) | (x << (width - (i % width)))) & ((1 << width) - 1)); } template auto HilbertPath::SetBit(const PathIndexType x, const PathIndexType width, const PathIndexType i, const PathIndexType b) -> PathIndexType { if (b != 0) { return (x | (1 << (width - i - 1))); } else { return (x & ~(1 << (width - i - 1))); } } template auto HilbertPath::GetGrayCode(const PathIndexType x) -> PathIndexType { return (x ^ (x >> 1)); } template auto HilbertPath::GetInverseGrayCode(const PathIndexType x) -> PathIndexType { if (x == 0) { return x; } PathIndexType m = static_cast(std::ceil(std::log(static_cast(x)) / std::log(2.0))) + 1; PathIndexType i = x; PathIndexType j = 1; while (j < m) { i ^= (x >> j); ++j; } return i; } template auto HilbertPath::GetTrailingSetBits(const PathIndexType x, const PathIndexType width) -> PathIndexType { PathIndexType i = 0; PathIndexType y = x; while (y & 1 && i <= width) { y >>= 1; ++i; } return i; } template auto HilbertPath::GetDirection(const PathIndexType x, const PathIndexType n) -> PathIndexType { if (x == 0) { return 0; } else if (x % 2 == 0) { return (this->GetTrailingSetBits(x - 1, n) % n); } else { return (this->GetTrailingSetBits(x, n) % n); } } template auto HilbertPath::GetEntry(const PathIndexType x) -> PathIndexType { if (x == 0) { return 0; } else { return (this->GetGrayCode(2 * static_cast((x - 1) / 2))); } } template void HilbertPath::PrintSelf(std::ostream & os, Indent indent) const { using namespace print_helper; Superclass::PrintSelf(os, indent); os << "HilbertOrder: " << static_cast::PrintType>(m_HilbertOrder) << std::endl; os << "HilbertPath: " << m_HilbertPath << std::endl; } } // end namespace itk #endif