mirror of https://github.com/CGAL/cgal
Add functions to get node indices & retrieve nodes by index
This commit is contained in:
parent
6dec072b00
commit
14726a1e41
|
|
@ -436,12 +436,22 @@ public:
|
||||||
\brief provides read-write access to the root node, and by
|
\brief provides read-write access to the root node, and by
|
||||||
extension the rest of the tree.
|
extension the rest of the tree.
|
||||||
|
|
||||||
todo: why wasn't this provided previously?
|
|
||||||
|
|
||||||
\return a reference to the root node of the tree.
|
\return a reference to the root node of the tree.
|
||||||
*/
|
*/
|
||||||
Node& root() { return m_nodes[0]; }
|
Node& root() { return m_nodes[0]; }
|
||||||
|
|
||||||
|
std::size_t index(const Node& node) const {
|
||||||
|
return std::distance(m_nodes.data(), &node);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node& operator[](std::size_t index) const {
|
||||||
|
return m_nodes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Node& operator[](std::size_t index) {
|
||||||
|
return m_nodes[index];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns the deepest level reached by a leaf node in this tree (root being level 0).
|
\brief returns the deepest level reached by a leaf node in this tree (root being level 0).
|
||||||
*/
|
*/
|
||||||
|
|
@ -665,6 +675,86 @@ public:
|
||||||
return node.m_children.get();
|
return node.m_children.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Node* next_sibling(const Node* n) const {
|
||||||
|
|
||||||
|
// todo: maybe this should take a reference?
|
||||||
|
if (nullptr == n)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// If this node has no parent, it has no siblings
|
||||||
|
if (n->is_root())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Find out which child this is
|
||||||
|
std::size_t index = n->local_coordinates().to_ulong();
|
||||||
|
|
||||||
|
constexpr static int degree = Node::Degree::value;
|
||||||
|
|
||||||
|
// Return null if this is the last child
|
||||||
|
if (int(index) == degree - 1)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Otherwise, return the next child
|
||||||
|
return &(children(parent(*n))[index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node* next_sibling_up(const Node* n) const {
|
||||||
|
|
||||||
|
if (!n || n->is_root()) return nullptr;
|
||||||
|
|
||||||
|
auto up = &parent(*n);
|
||||||
|
while (nullptr != up) {
|
||||||
|
|
||||||
|
if (nullptr != next_sibling(up))
|
||||||
|
return next_sibling(up);
|
||||||
|
|
||||||
|
// todo: this could be cleaned up; it's probably not necessary to involve pointers here
|
||||||
|
up = up->is_root() ? nullptr : &parent(*up);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node* deepest_first_child(const Node* n) const {
|
||||||
|
|
||||||
|
if (n == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Find the deepest child on the left
|
||||||
|
auto first = n;
|
||||||
|
while (!first->is_leaf())
|
||||||
|
first = &children(*first)[0];
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Node* first_child_at_depth(const Node* n, std::size_t depth) const {
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::stack<const Node*> todo;
|
||||||
|
todo.push(n);
|
||||||
|
|
||||||
|
if (n->depth() == depth)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
while (!todo.empty()) {
|
||||||
|
const Node* node = todo.top();
|
||||||
|
todo.pop();
|
||||||
|
|
||||||
|
if (node->depth() == depth)
|
||||||
|
return node;
|
||||||
|
|
||||||
|
if (!node->is_leaf())
|
||||||
|
for (int i = 0; i < Node::Degree::value; ++i)
|
||||||
|
todo.push(&((*node)[std::size_t(Node::Degree::value - 1 - i)]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief splits the node into subnodes.
|
\brief splits the node into subnodes.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,94 +31,6 @@ class Orthtree;
|
||||||
|
|
||||||
namespace Orthtrees {
|
namespace Orthtrees {
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
|
||||||
|
|
||||||
// todo: all of these could be members of Orthtree
|
|
||||||
|
|
||||||
template <typename Tree>
|
|
||||||
const typename Tree::Node* next_sibling(const Tree& orthtree, const typename Tree::Node* n) {
|
|
||||||
|
|
||||||
// todo: maybe this should take a reference?
|
|
||||||
if (nullptr == n)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// If this node has no parent, it has no siblings
|
|
||||||
if (n->is_root())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// Find out which child this is
|
|
||||||
std::size_t index = n->local_coordinates().to_ulong();
|
|
||||||
|
|
||||||
constexpr static int degree = Tree::Node::Degree::value;
|
|
||||||
// Return null if this is the last child
|
|
||||||
if (int(index) == degree - 1)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// Otherwise, return the next child
|
|
||||||
return &(orthtree.children(orthtree.parent(*n))[index + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Tree>
|
|
||||||
const typename Tree::Node* next_sibling_up(const Tree& orthtree, const typename Tree::Node* n) {
|
|
||||||
|
|
||||||
if (!n || n->is_root()) return nullptr;
|
|
||||||
|
|
||||||
auto up = &orthtree.parent(*n);
|
|
||||||
while (nullptr != up) {
|
|
||||||
|
|
||||||
if (nullptr != next_sibling(orthtree, up))
|
|
||||||
return next_sibling(orthtree, up);
|
|
||||||
|
|
||||||
// todo: this could be cleaned up; it's probably not necessary to involve pointers here
|
|
||||||
up = up->is_root() ? nullptr : &orthtree.parent(*up);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Tree>
|
|
||||||
const typename Tree::Node* deepest_first_child(const Tree& orthtree, const typename Tree::Node* n) {
|
|
||||||
|
|
||||||
if (n == nullptr)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// Find the deepest child on the left
|
|
||||||
auto first = n;
|
|
||||||
while (!first->is_leaf())
|
|
||||||
first = &orthtree.children(*first)[0];
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Tree>
|
|
||||||
const typename Tree::Node* first_child_at_depth(const Tree& orthtree, const typename Tree::Node* n, std::size_t depth) {
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
std::stack<const typename Tree::Node*> todo;
|
|
||||||
todo.push(n);
|
|
||||||
|
|
||||||
if (n->depth() == depth)
|
|
||||||
return n;
|
|
||||||
|
|
||||||
while (!todo.empty()) {
|
|
||||||
const typename Tree::Node* node = todo.top();
|
|
||||||
todo.pop();
|
|
||||||
|
|
||||||
if (node->depth() == depth)
|
|
||||||
return node;
|
|
||||||
|
|
||||||
if (!node->is_leaf())
|
|
||||||
for (int i = 0; i < Tree::Node::Degree::value; ++i)
|
|
||||||
todo.push(&((*node)[std::size_t(Tree::Node::Degree::value - 1 - i)]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \endcond
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\ingroup PkgOrthtreeTraversal
|
\ingroup PkgOrthtreeTraversal
|
||||||
\brief A class used for performing a preorder traversal.
|
\brief A class used for performing a preorder traversal.
|
||||||
|
|
@ -147,11 +59,11 @@ public:
|
||||||
|
|
||||||
if (n->is_leaf()) {
|
if (n->is_leaf()) {
|
||||||
|
|
||||||
auto next = next_sibling(m_orthtree, n);
|
auto next = m_orthtree.next_sibling(n);
|
||||||
|
|
||||||
if (nullptr == next) {
|
if (nullptr == next) {
|
||||||
|
|
||||||
return next_sibling_up(m_orthtree, n);
|
return m_orthtree.next_sibling_up(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|
@ -221,15 +133,15 @@ public:
|
||||||
Leaves_traversal(const Tree& orthtree) : m_orthtree(orthtree) {}
|
Leaves_traversal(const Tree& orthtree) : m_orthtree(orthtree) {}
|
||||||
|
|
||||||
const Node* first() const {
|
const Node* first() const {
|
||||||
return deepest_first_child(m_orthtree, &m_orthtree.root());
|
return m_orthtree.deepest_first_child(&m_orthtree.root());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node* next(const Node* n) const {
|
const Node* next(const Node* n) const {
|
||||||
|
|
||||||
auto next = deepest_first_child(m_orthtree, next_sibling(m_orthtree, n));
|
auto next = m_orthtree.deepest_first_child(m_orthtree.next_sibling(n));
|
||||||
|
|
||||||
if (!next)
|
if (!next)
|
||||||
next = deepest_first_child(m_orthtree, next_sibling_up(m_orthtree, n));
|
next = m_orthtree.deepest_first_child(m_orthtree.next_sibling_up(n));
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
@ -262,21 +174,21 @@ public:
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* first() const {
|
const Node* first() const {
|
||||||
return first_child_at_depth(m_orthtree, m_orthtree.root(), m_depth);
|
return m_orthtree.first_child_at_depth(m_orthtree.root(), m_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* next(const Node* n) const {
|
const Node* next(const Node* n) const {
|
||||||
const Node* next = next_sibling(m_orthtree, n);
|
const Node* next = m_orthtree.next_sibling(n);
|
||||||
|
|
||||||
if (!next) {
|
if (!next) {
|
||||||
const Node* up = n;
|
const Node* up = n;
|
||||||
do {
|
do {
|
||||||
up = next_sibling_up(m_orthtree, up);
|
up = m_orthtree.next_sibling_up(up);
|
||||||
if (!up)
|
if (!up)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
next = first_child_at_depth(m_orthtree, up, m_depth);
|
next = m_orthtree.first_child_at_depth(up, m_depth);
|
||||||
} while (!next);
|
} while (!next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue