/*========================================================================= * * 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 itkOctree_hxx #define itkOctree_hxx namespace itk { template Octree::Octree() : m_Tree() { m_TrueDims[0] = 0; m_TrueDims[1] = 1; m_TrueDims[2] = 2; m_Tree.SetParentOctree(this); } template Octree::~Octree() { /*Nothing to be done here*/ } template void Octree::SetTrueDims(const unsigned int Dim0, const unsigned int Dim1, const unsigned int Dim2) { this->m_TrueDims[0] = Dim0; this->m_TrueDims[1] = Dim1; this->m_TrueDims[2] = Dim2; } /** This is moving bits to get the values of the 8 octants * Possible values are the 3 bits to be set. * 0 000 Contains origin * 1 001 * 2 010 * 3 011 * 4 100 * 5 101 * 6 110 * 7 111 Contains extents * ....^^^ * ....|| The LSB is 1 if requested X voxel is greater than X centerline of subcube * ....| The middle bit is 1 if requested Y voxel is greater than Y centerline of subcube * .... The MSB is 1 if requested Z voxel is greater than Z centerline of subcube * \author Hans J. Johnson, adapted from Vincent A. Magnotta * \param VoxX The desired voxel * \param VoxY The desired voxel * \param VoxZ The desired voxel * \param CenterLineX The division line between octants * \param CenterLineY The division line between octants * \param CenterLineZ The division line between octants * \return The octant that the voxel falls into. */ inline unsigned int OCTREE_OCTANT(const unsigned int VoxX, const unsigned int CenterLineX, const unsigned int VoxY, const unsigned int CenterLineY, const unsigned int VoxZ, const unsigned int CenterLineZ) { return ( ((static_cast(VoxZ >= CenterLineZ) << 2) | (static_cast(VoxY >= CenterLineY) << 1)) | (static_cast(VoxX >= CenterLineX))); } /** * \defgroup Octant directional identifying functions * These functions determine if the directions are in the "lower" or * "upper" portion of the Octree in the given directions. * @{ */ inline unsigned int XF(const unsigned int octantID) { return octantID & 1; // Just return 1 if 0th bit is a one } inline unsigned int YF(const unsigned int octantID) { return (octantID >> 1) & 1; // Just return 1 if 1st bit is a one } inline unsigned int ZF(const unsigned int octantID) { return (octantID >> 2) & 1; // Just return 1 if 2nd bit is a one } /** @} */ // End of defgroup template int Octree::GetValue(const unsigned int Dim0, const unsigned int Dim1, const unsigned int Dim2) { if ((Dim2 >= this->m_TrueDims[2]) || (Dim1 >= this->m_TrueDims[1]) || (Dim0 >= this->m_TrueDims[0])) { return 0; } // Define CurrentOctreeNode at the Octree head Node OctreeNode * CurrentOctreeNode = &m_Tree; // Define the origin of current OctreeNode unsigned int ox = 0, oy = 0, oz = 0; // Define the halfwidth, this will be changed inside of while loop unsigned int halfwidth = this->m_Width; while ((CurrentOctreeNode->IsNodeColored()) == false) { // NOTE: halfwidth=halfwidth/2 is the same as halfwidth >> 1 halfwidth = halfwidth >> 1; const unsigned int octantID = OCTREE_OCTANT(Dim0, ox + halfwidth, Dim1, oy + halfwidth, Dim2, oz + halfwidth); // Determine new origin for next child. ox = ox + XF(octantID) * halfwidth; oy = oy + YF(octantID) * halfwidth; oz = oz + ZF(octantID) * halfwidth; CurrentOctreeNode = &CurrentOctreeNode->GetChild(static_cast(octantID)); } return CurrentOctreeNode->GetColor(); } template OctreeNodeBranch * Octree::maskToOctree(const TPixel * Mask, unsigned int width, unsigned int x, unsigned int y, unsigned int z, unsigned int xsize, unsigned int ysize, unsigned int zsize) { if ((x >= xsize) || (y >= ysize) || (z >= zsize)) { return m_ColorTable + B2_MASKFILE_BLACK; } if (width == 1) { return m_ColorTable + m_MappingFunction.Evaluate(&Mask[z * ysize * xsize + y * xsize + x]); } width /= 2; OctreeNodeBranch * nodeArray[8]; nodeArray[0] = this->maskToOctree(Mask, width, x, y, z, xsize, ysize, zsize); nodeArray[1] = this->maskToOctree(Mask, width, x + width, y, z, xsize, ysize, zsize); nodeArray[2] = this->maskToOctree(Mask, width, x, y + width, z, xsize, ysize, zsize); nodeArray[3] = this->maskToOctree(Mask, width, x + width, y + width, z, xsize, ysize, zsize); nodeArray[4] = this->maskToOctree(Mask, width, x, y, z + width, xsize, ysize, zsize); nodeArray[5] = this->maskToOctree(Mask, width, x + width, y, z + width, xsize, ysize, zsize); nodeArray[6] = this->maskToOctree(Mask, width, x, y + width, z + width, xsize, ysize, zsize); nodeArray[7] = this->maskToOctree(Mask, width, x + width, y + width, z + width, xsize, ysize, zsize); if ((nodeArray[0] == nodeArray[1]) && (nodeArray[0] == nodeArray[2]) && (nodeArray[0] == nodeArray[3]) && (nodeArray[0] == nodeArray[4]) && (nodeArray[0] == nodeArray[5]) && (nodeArray[0] == nodeArray[6]) && (nodeArray[0] == nodeArray[7])) { return nodeArray[0]; } else { auto * q = new OctreeNodeBranch(this); { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::ZERO); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::ZERO)]); } { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::ONE); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::ONE)]); } { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::TWO); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::TWO)]); } { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::THREE); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::THREE)]); } { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::FOUR); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::FOUR)]); } { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::FIVE); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::FIVE)]); } { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::SIX); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::SIX)]); } { OctreeNode * newbranch = q->GetLeaf(OctreeNode::LeafIdentifierEnum::SEVEN); newbranch->SetBranch(nodeArray[static_cast(OctreeNode::LeafIdentifierEnum::SEVEN)]); } return (q); } } template void Octree::BuildFromBuffer(const void * frombuffer, const unsigned int xsize, const unsigned int ysize, const unsigned int zsize) { unsigned int maxSize = xsize >= ysize ? (xsize >= zsize ? xsize : zsize) : (ysize >= zsize ? ysize : zsize); unsigned int width = 1; unsigned int depth = 0; while (width < maxSize) { width *= 2; ++depth; } this->SetDepth(depth); this->SetWidth(width); m_TrueDims[0] = xsize; m_TrueDims[1] = ysize; m_TrueDims[2] = zsize; const auto * bufcast = static_cast(frombuffer); OctreeNodeBranch * branch = this->maskToOctree(bufcast, width, 0, 0, 0, xsize, ysize, zsize); m_Tree.SetBranch(branch); } template void Octree::BuildFromImage(ImageType * fromImage) { const typename Image::RegionType & region = fromImage->GetLargestPossibleRegion(); const SizeValueType xsize = region.GetSize(0); const SizeValueType ysize = region.GetSize(1); const SizeValueType zsize = region.GetSize(2); this->BuildFromBuffer(static_cast(fromImage->GetBufferPointer()), xsize, ysize, zsize); } template auto Octree::GetImage() -> ImageTypePointer { typename ImageType::SizeType imageSize = { { 0, 0, 0 } }; SizeValueType sizes[3]; sizes[0] = m_TrueDims[0]; sizes[1] = m_TrueDims[1]; sizes[2] = m_TrueDims[2]; imageSize.SetSize(sizes); const typename ImageType::IndexType imageIndex = { { 0, 0, 0 } }; const typename ImageType::RegionType region(imageIndex, imageSize); auto img = ImageType::New(); img->SetRegions(region); img->Allocate(); typename ImageType::IndexType setIndex; for (unsigned int i = 0; i < m_TrueDims[0]; ++i) { setIndex[0] = i; for (unsigned int j = 0; j < m_TrueDims[0]; ++j) { setIndex[1] = j; for (unsigned int k = 0; k < m_TrueDims[0]; ++k) { setIndex[2] = k; img->SetPixel(setIndex, (TPixel)this->GetValue(i, j, k)); } } } return img; } template OctreeNode * Octree::GetTree() { return &m_Tree; } template void Octree::SetWidth(unsigned int width) { m_Width = width; } template void Octree::SetDepth(unsigned int depth) { m_Depth = depth; } template unsigned int Octree::GetWidth() { return m_Width; } template unsigned int Octree::GetDepth() { return m_Depth; } template const OctreeNodeBranch * Octree::GetColorTable() const { return m_ColorTable; } template int Octree::GetColorTableSize() const { return ColorTableSize; } } // namespace itk #endif