Program Listing for File ndtree_inl.h

Return to documentation for file (library/cpp/include/wavemap/core/data_structure/ndtree/impl/ndtree_inl.h)

#ifndef WAVEMAP_CORE_DATA_STRUCTURE_NDTREE_IMPL_NDTREE_INL_H_
#define WAVEMAP_CORE_DATA_STRUCTURE_NDTREE_IMPL_NDTREE_INL_H_

#include <stack>
#include <utility>
#include <vector>

#include "wavemap/core/data_structure/pointcloud.h"
#include "wavemap/core/indexing/index_conversions.h"

namespace wavemap {
template <typename NodeDataT, int dim>
template <typename... RootNodeArgs>
Ndtree<NodeDataT, dim>::Ndtree(int max_height, RootNodeArgs&&... args)
    : max_height_(max_height), root_node_(std::forward<RootNodeArgs>(args)...) {
  CHECK_LE(max_height_, morton::kMaxTreeHeight<dim>);
}

template <typename NodeDataT, int dim>
size_t Ndtree<NodeDataT, dim>::size() const {
  auto subtree_iterator = getIterator<TraversalOrder::kDepthFirstPreorder>();
  return std::distance(subtree_iterator.begin(), subtree_iterator.end());
}

template <typename NodeDataT, int dim>
void Ndtree<NodeDataT, dim>::prune() {
  for (NodeType& node : getIterator<TraversalOrder::kDepthFirstPostorder>()) {
    if (node.hasChildrenArray()) {
      bool has_non_empty_child = false;
      for (NdtreeIndexRelativeChild child_idx = 0;
           child_idx < NodeType::kNumChildren; ++child_idx) {
        NodeType* child_ptr = node.getChild(child_idx);
        if (child_ptr) {
          if (child_ptr->empty()) {
            node.eraseChild(child_idx);
          } else {
            has_non_empty_child = true;
          }
        }
      }
      // Free up the children array if it only contains null pointers
      if (!has_non_empty_child) {
        node.deleteChildrenArray();
      }
    }
  }
}

template <typename NodeDataT, int dim>
size_t Ndtree<NodeDataT, dim>::getMemoryUsage() const {
  size_t memory_usage = 0u;
  for (const NodeType& node :
       getIterator<TraversalOrder::kDepthFirstPreorder>()) {
    memory_usage += node.getMemoryUsage();
  }
  return memory_usage;
}

template <typename NodeDataT, int dim>
bool Ndtree<NodeDataT, dim>::eraseNode(const IndexType& index) {
  IndexType parent_index = index.computeParentIndex();
  NodeType* parent_node = getNode(parent_index);
  if (parent_node) {
    return parent_node->eraseChild(index.computeRelativeChildIndex());
  }
  return false;
}

template <typename NodeDataT, int dim>
typename Ndtree<NodeDataT, dim>::NodeType* Ndtree<NodeDataT, dim>::getNode(
    const IndexType& index) {
  return const_cast<NodeType*>(std::as_const(*this).getNode(index));
}

template <typename NodeDataT, int dim>
const typename Ndtree<NodeDataT, dim>::NodeType*
Ndtree<NodeDataT, dim>::getNode(const IndexType& index) const {
  const NodeType* node = &root_node_;
  const MortonIndex morton_code = convert::nodeIndexToMorton(index);
  for (int node_height = max_height_; node && index.height < node_height;
       --node_height) {
    const NdtreeIndexRelativeChild child_index =
        NdtreeIndex<dim>::computeRelativeChildIndex(morton_code, node_height);
    node = node->getChild(child_index);
  }
  return node;
}

template <typename NodeDataT, int dim>
template <typename... DefaultArgs>
typename Ndtree<NodeDataT, dim>::NodeType&
Ndtree<NodeDataT, dim>::getOrAllocateNode(const Ndtree::IndexType& index,
                                          DefaultArgs&&... args) {
  NodeType* node = &root_node_;
  const MortonIndex morton_code = convert::nodeIndexToMorton(index);
  for (int node_height = max_height_; index.height < node_height;
       --node_height) {
    const NdtreeIndexRelativeChild child_index =
        NdtreeIndex<dim>::computeRelativeChildIndex(morton_code, node_height);
    // Get the child, allocating if needed
    node = &node->getOrAllocateChild(child_index,
                                     std::forward<DefaultArgs>(args)...);
  }
  return *node;
}

template <typename NodeDataT, int dim>
std::pair<typename Ndtree<NodeDataT, dim>::NodeType*, IndexElement>
Ndtree<NodeDataT, dim>::getNodeOrAncestor(const Ndtree::IndexType& index) {
  auto rv = std::as_const(*this).getNodeOrAncestor(index);
  return {const_cast<NodeType*>(rv.first), rv.second};
}

template <typename NodeDataT, int dim>
std::pair<const typename Ndtree<NodeDataT, dim>::NodeType*, IndexElement>
Ndtree<NodeDataT, dim>::getNodeOrAncestor(
    const Ndtree::IndexType& index) const {
  const NodeType* node = &root_node_;
  const MortonIndex morton_code = convert::nodeIndexToMorton(index);
  for (int node_height = max_height_; index.height < node_height;
       --node_height) {
    const NdtreeIndexRelativeChild child_index =
        NdtreeIndex<dim>::computeRelativeChildIndex(morton_code, node_height);
    // Check if the child is allocated
    const NodeType* child = node->getChild(child_index);
    if (!child) {
      return {node, node_height};
    }
    node = child;
  }
  return {node, index.height};
}

template <typename NodeDataT, int dim>
template <TraversalOrder traversal_order>
auto Ndtree<NodeDataT, dim>::getIterator() {
  return Subtree<NodeType, traversal_order>(&root_node_);
}

template <typename NodeDataT, int dim>
template <TraversalOrder traversal_order>
auto Ndtree<NodeDataT, dim>::getIterator() const {
  return Subtree<const NodeType, traversal_order>(&root_node_);
}
}  // namespace wavemap

#endif  // WAVEMAP_CORE_DATA_STRUCTURE_NDTREE_IMPL_NDTREE_INL_H_