mirror of https://github.com/CGAL/cgal
Make node trivially copiable and simplify APIs
This commit is contained in:
parent
398fbb989c
commit
0747b09e23
|
|
@ -53,15 +53,15 @@ int main(int argc, char **argv) {
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
// Retrieve one of the deeper children
|
// Retrieve one of the deeper children
|
||||||
const Octree::Node &cur = octree[3][2];
|
Octree::Node cur = octree[3][2];
|
||||||
std::cout << "Navigation relative to a child node" << std::endl;
|
std::cout << "Navigation relative to a child node" << std::endl;
|
||||||
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
|
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
|
||||||
std::cout << "the third child of the fourth child: " << std::endl;
|
std::cout << "the third child of the fourth child: " << std::endl;
|
||||||
std::cout << cur << std::endl;
|
std::cout << cur << std::endl;
|
||||||
std::cout << "the third child: " << std::endl;
|
std::cout << "the third child: " << std::endl;
|
||||||
std::cout << *cur.parent() << std::endl;
|
std::cout << cur.parent() << std::endl;
|
||||||
std::cout << "the next sibling of the third child of the fourth child: " << std::endl;
|
std::cout << "the next sibling of the third child of the fourth child: " << std::endl;
|
||||||
std::cout << (*cur.parent())[cur.index().to_ulong() + 1] << std::endl;
|
std::cout << cur.parent()[cur.index().to_ulong() + 1] << std::endl;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <CGAL/Orthtree/Split_predicate.h>
|
#include <CGAL/Orthtree/Split_predicate.h>
|
||||||
#include <CGAL/Orthtree/Traversal.h>
|
#include <CGAL/Orthtree/Traversal.h>
|
||||||
#include <CGAL/Orthtree/Traversal_iterator.h>
|
#include <CGAL/Orthtree/Traversal_iterator.h>
|
||||||
|
#include <CGAL/Orthtree/IO.h>
|
||||||
|
|
||||||
#include <CGAL/bounding_box.h>
|
#include <CGAL/bounding_box.h>
|
||||||
|
|
||||||
|
|
@ -107,7 +108,7 @@ public:
|
||||||
/*!
|
/*!
|
||||||
* \brief A predicate that determines whether a node needs to be split when refining a tree
|
* \brief A predicate that determines whether a node needs to be split when refining a tree
|
||||||
*/
|
*/
|
||||||
typedef std::function<bool(const Node &)> Split_predicate;
|
typedef std::function<bool(Node)> Split_predicate;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A model of `ConstRange` whose value type is `Node`.
|
* \brief A model of `ConstRange` whose value type is `Node`.
|
||||||
|
|
@ -115,7 +116,7 @@ public:
|
||||||
#ifdef DOXYGEN_RUNNING
|
#ifdef DOXYGEN_RUNNING
|
||||||
typedef unspecified_type Node_range;
|
typedef unspecified_type Node_range;
|
||||||
#else
|
#else
|
||||||
typedef boost::iterator_range<Traversal_iterator<const Node>> Node_range;
|
typedef boost::iterator_range<Traversal_iterator<Node> > Node_range;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
|
@ -123,7 +124,7 @@ public:
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that determines the next node in a traversal given the current one
|
* \brief A function that determines the next node in a traversal given the current one
|
||||||
*/
|
*/
|
||||||
typedef std::function<const Node *(const Node *)> Node_traversal_method_const;
|
typedef std::function<Node(Node)> Node_traversal_method_const;
|
||||||
|
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
|
|
@ -176,6 +177,7 @@ public:
|
||||||
: m_traits (traits)
|
: m_traits (traits)
|
||||||
, m_range (point_range)
|
, m_range (point_range)
|
||||||
, m_point_map (point_map)
|
, m_point_map (point_map)
|
||||||
|
, m_root(Node(), 0)
|
||||||
{
|
{
|
||||||
Array bbox_min;
|
Array bbox_min;
|
||||||
for (FT& f : bbox_min)
|
for (FT& f : bbox_min)
|
||||||
|
|
@ -207,7 +209,7 @@ public:
|
||||||
for (std::size_t i = 0 ; i < Dimension::value; ++ i)
|
for (std::size_t i = 0 ; i < Dimension::value; ++ i)
|
||||||
{
|
{
|
||||||
bbox_min[i] = bbox_centroid[i] - max_length;
|
bbox_min[i] = bbox_centroid[i] - max_length;
|
||||||
bbox_max[i] = bbox_centroid[i] - max_length;
|
bbox_max[i] = bbox_centroid[i] + max_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Construct_point_d_from_array construct_point_d_from_array
|
Construct_point_d_from_array construct_point_d_from_array
|
||||||
|
|
@ -245,32 +247,32 @@ public:
|
||||||
m_side_per_depth.resize(1);
|
m_side_per_depth.resize(1);
|
||||||
|
|
||||||
// Initialize a queue of nodes that need to be refined
|
// Initialize a queue of nodes that need to be refined
|
||||||
std::queue<Node *> todo;
|
std::queue<Node> todo;
|
||||||
todo.push(&m_root);
|
todo.push(m_root);
|
||||||
|
|
||||||
// Process items in the queue until it's consumed fully
|
// Process items in the queue until it's consumed fully
|
||||||
while (!todo.empty()) {
|
while (!todo.empty()) {
|
||||||
|
|
||||||
// Get the next element
|
// Get the next element
|
||||||
auto current = todo.front();
|
Node current = todo.front();
|
||||||
todo.pop();
|
todo.pop();
|
||||||
|
|
||||||
// Check if this node needs to be processed
|
// Check if this node needs to be processed
|
||||||
if (split_predicate(*current)) {
|
if (split_predicate(current)) {
|
||||||
|
|
||||||
// Check if we've reached a new max depth
|
// Check if we've reached a new max depth
|
||||||
if (current->depth() == max_depth_reached()) {
|
if (current.depth() == max_depth_reached()) {
|
||||||
|
|
||||||
// Update the side length map
|
// Update the side length map
|
||||||
m_side_per_depth.push_back(*(m_side_per_depth.end() - 1) / 2);
|
m_side_per_depth.push_back(*(m_side_per_depth.end() - 1) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split the node, redistributing its points to its children
|
// Split the node, redistributing its points to its children
|
||||||
split((*current));
|
split(current);
|
||||||
|
|
||||||
// Process each of its children
|
// Process each of its children
|
||||||
for (int i = 0; i < Degree::value; ++i)
|
for (int i = 0; i < Degree::value; ++i)
|
||||||
todo.push(&(*current)[i]);
|
todo.push(current[i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -299,52 +301,52 @@ public:
|
||||||
void grade() {
|
void grade() {
|
||||||
|
|
||||||
// Collect all the leaf nodes
|
// Collect all the leaf nodes
|
||||||
std::queue<Node *> leaf_nodes;
|
std::queue<Node> leaf_nodes;
|
||||||
for (auto &leaf : traverse(Orthtrees::Traversal::Leaves())) {
|
for (Node leaf : traverse(Orthtrees::Traversal::Leaves())) {
|
||||||
// TODO: I'd like to find a better (safer) way of doing this
|
// TODO: I'd like to find a better (safer) way of doing this
|
||||||
leaf_nodes.push(const_cast<Node *>(&leaf));
|
leaf_nodes.push(leaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over the nodes
|
// Iterate over the nodes
|
||||||
while (!leaf_nodes.empty()) {
|
while (!leaf_nodes.empty()) {
|
||||||
|
|
||||||
// Get the next node
|
// Get the next node
|
||||||
Node *node = leaf_nodes.front();
|
Node node = leaf_nodes.front();
|
||||||
leaf_nodes.pop();
|
leaf_nodes.pop();
|
||||||
|
|
||||||
// Skip this node if it isn't a leaf anymore
|
// Skip this node if it isn't a leaf anymore
|
||||||
if (!node->is_leaf())
|
if (!node.is_leaf())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Iterate over each of the neighbors
|
// Iterate over each of the neighbors
|
||||||
for (int direction = 0; direction < 6; ++direction) {
|
for (int direction = 0; direction < 6; ++direction) {
|
||||||
|
|
||||||
// Get the neighbor
|
// Get the neighbor
|
||||||
auto *neighbor = node->adjacent_node(direction);
|
Node neighbor = node.adjacent_node(direction);
|
||||||
|
|
||||||
// If it doesn't exist, skip it
|
// If it doesn't exist, skip it
|
||||||
if (!neighbor)
|
if (neighbor.is_null())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skip if this neighbor is a direct sibling (it's guaranteed to be the same depth)
|
// Skip if this neighbor is a direct sibling (it's guaranteed to be the same depth)
|
||||||
// TODO: This check might be redundant, if it doesn't affect performance maybe I could remove it
|
// TODO: This check might be redundant, if it doesn't affect performance maybe I could remove it
|
||||||
if (neighbor->parent() == node->parent())
|
if (neighbor.parent() == node.parent())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If it's already been split, skip it
|
// If it's already been split, skip it
|
||||||
if (!neighbor->is_leaf())
|
if (!neighbor.is_leaf())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if the neighbor breaks our grading rule
|
// Check if the neighbor breaks our grading rule
|
||||||
// TODO: could the rule be parametrized?
|
// TODO: could the rule be parametrized?
|
||||||
if ((node->depth() - neighbor->depth()) > 1) {
|
if ((node.depth() - neighbor.depth()) > 1) {
|
||||||
|
|
||||||
// Split the neighbor
|
// Split the neighbor
|
||||||
split(*neighbor);
|
split(neighbor);
|
||||||
|
|
||||||
// Add newly created children to the queue
|
// Add newly created children to the queue
|
||||||
for (int i = 0; i < Degree::value; ++i) {
|
for (int i = 0; i < Degree::value; ++i) {
|
||||||
leaf_nodes.push(&(*neighbor)[i]);
|
leaf_nodes.push(neighbor[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -357,12 +359,9 @@ public:
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief provides read-only access to the root node, and by
|
\brief returns the root node.
|
||||||
extension the rest of the tree.
|
|
||||||
|
|
||||||
\return a const reference to the root node of the tree.
|
|
||||||
*/
|
*/
|
||||||
const Node &root() const { return m_root; }
|
Node root() const { return m_root; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief convenience function to access the child nodes of the root
|
\brief convenience function to access the child nodes of the root
|
||||||
|
|
@ -373,7 +372,7 @@ public:
|
||||||
\param index the index of the child node.
|
\param index the index of the child node.
|
||||||
\return a reference to the node.
|
\return a reference to the node.
|
||||||
*/
|
*/
|
||||||
const Node &operator[](std::size_t index) const { return m_root[index]; }
|
Node operator[](std::size_t index) const { return m_root[index]; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Finds the deepest level reached by a leaf node in this tree.
|
\brief Finds the deepest level reached by a leaf node in this tree.
|
||||||
|
|
@ -394,13 +393,13 @@ public:
|
||||||
template<typename Traversal>
|
template<typename Traversal>
|
||||||
Node_range traverse(const Traversal &traversal = Traversal()) const {
|
Node_range traverse(const Traversal &traversal = Traversal()) const {
|
||||||
|
|
||||||
const Node *first = traversal.first(&m_root);
|
Node first = traversal.first(m_root);
|
||||||
|
|
||||||
Node_traversal_method_const next = std::bind(&Traversal::template next<Node>,
|
Node_traversal_method_const next = std::bind(&Traversal::template next<Node>,
|
||||||
traversal, _1);
|
traversal, _1);
|
||||||
|
|
||||||
return boost::make_iterator_range(Traversal_iterator<const Node>(first, next),
|
return boost::make_iterator_range(Traversal_iterator<Node>(first, next),
|
||||||
Traversal_iterator<const Node>());
|
Traversal_iterator<Node>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -444,19 +443,19 @@ public:
|
||||||
\param point query point.
|
\param point query point.
|
||||||
\return the node which contains the point.
|
\return the node which contains the point.
|
||||||
*/
|
*/
|
||||||
const Node& locate(const Point &point) const {
|
Node locate(const Point &point) const {
|
||||||
|
|
||||||
// Make sure the point is enclosed by the orthtree
|
// Make sure the point is enclosed by the orthtree
|
||||||
CGAL_precondition (CGAL::do_intersect(point, bbox(m_root)));
|
CGAL_precondition (CGAL::do_intersect(point, bbox(m_root)));
|
||||||
|
|
||||||
// Start at the root node
|
// Start at the root node
|
||||||
auto *node_for_point = &m_root;
|
auto node_for_point = m_root;
|
||||||
|
|
||||||
// Descend the tree until reaching a leaf node
|
// Descend the tree until reaching a leaf node
|
||||||
while (!node_for_point->is_leaf()) {
|
while (!node_for_point->is_leaf()) {
|
||||||
|
|
||||||
// Find the point to split around
|
// Find the point to split around
|
||||||
Point center = barycenter(*node_for_point);
|
Point center = barycenter(node_for_point);
|
||||||
|
|
||||||
// Find the index of the correct sub-node
|
// Find the index of the correct sub-node
|
||||||
typename Node::Index index;
|
typename Node::Index index;
|
||||||
|
|
@ -465,11 +464,11 @@ public:
|
||||||
index[dimension ++] = (get<0>(r) < get<1>(r));
|
index[dimension ++] = (get<0>(r) < get<1>(r));
|
||||||
|
|
||||||
// Find the correct sub-node of the current node
|
// Find the correct sub-node of the current node
|
||||||
node_for_point = &(*node_for_point)[index.to_ulong()];
|
node_for_point = node_for_point[index.to_ulong()];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the result
|
// Return the result
|
||||||
return *node_for_point;
|
return node_for_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -560,7 +559,7 @@ public:
|
||||||
|
|
||||||
// TODO: Document this
|
// TODO: Document this
|
||||||
// TODO: Could this method name be reduced to just "center" ?
|
// TODO: Could this method name be reduced to just "center" ?
|
||||||
Point barycenter(const Node &node) const {
|
Point barycenter(const Node& node) const {
|
||||||
|
|
||||||
// Determine the side length of this node
|
// Determine the side length of this node
|
||||||
FT size = m_side_per_depth[node.depth()];
|
FT size = m_side_per_depth[node.depth()];
|
||||||
|
|
@ -570,9 +569,11 @@ public:
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
for (const FT& f : cartesian_range(m_bbox_min))
|
for (const FT& f : cartesian_range(m_bbox_min))
|
||||||
{
|
{
|
||||||
|
std::cerr << node.location()[i] << " ";
|
||||||
bary[i] = node.location()[i] * size + (size / 2.0) + f;
|
bary[i] = node.location()[i] * size + (size / 2.0) + f;
|
||||||
++ i;
|
++ i;
|
||||||
}
|
}
|
||||||
|
std::cerr << std::endl;
|
||||||
|
|
||||||
// Convert that location into a point
|
// Convert that location into a point
|
||||||
Construct_point_d_from_array construct_point_d_from_array
|
Construct_point_d_from_array construct_point_d_from_array
|
||||||
|
|
@ -615,7 +616,7 @@ private: // functions :
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void split(Node &node) {
|
void split(Node& node) {
|
||||||
|
|
||||||
// Make sure the node hasn't already been split
|
// Make sure the node hasn't already been split
|
||||||
assert(node.is_leaf());
|
assert(node.is_leaf());
|
||||||
|
|
@ -625,6 +626,7 @@ private: // functions :
|
||||||
|
|
||||||
// Find the point to around which the node is split
|
// Find the point to around which the node is split
|
||||||
Point center = barycenter(node);
|
Point center = barycenter(node);
|
||||||
|
std::cerr << center << std::endl;
|
||||||
|
|
||||||
// Add the node's points to its children
|
// Add the node's points to its children
|
||||||
reassign_points(node, node.points().begin(), node.points().end(), center);
|
reassign_points(node, node.points().begin(), node.points().end(), center);
|
||||||
|
|
@ -709,7 +711,7 @@ private: // functions :
|
||||||
|
|
||||||
// Fill the list with child nodes
|
// Fill the list with child nodes
|
||||||
for (int index = 0; index < Degree::value; ++index) {
|
for (int index = 0; index < Degree::value; ++index) {
|
||||||
auto &child_node = node[index];
|
Node child_node = node[index];
|
||||||
|
|
||||||
// Add a child to the list, with its distance
|
// Add a child to the list, with its distance
|
||||||
children_with_distances.push_back(
|
children_with_distances.push_back(
|
||||||
|
|
@ -725,7 +727,7 @@ private: // functions :
|
||||||
|
|
||||||
// Loop over the children
|
// Loop over the children
|
||||||
for (auto child_with_distance : children_with_distances) {
|
for (auto child_with_distance : children_with_distances) {
|
||||||
auto &child_node = node[child_with_distance.index.to_ulong()];
|
Node child_node = node[child_with_distance.index.to_ulong()];
|
||||||
|
|
||||||
// Check whether the bounding box of the child intersects with the search bounds
|
// Check whether the bounding box of the child intersects with the search bounds
|
||||||
if (do_intersect(child_node, search_bounds)) {
|
if (do_intersect(child_node, search_bounds)) {
|
||||||
|
|
@ -746,7 +748,7 @@ private: // functions :
|
||||||
|
|
||||||
// if this node is a leaf, than it's considered an intersecting node
|
// if this node is a leaf, than it's considered an intersecting node
|
||||||
if (node.is_leaf()) {
|
if (node.is_leaf()) {
|
||||||
*output++ = &node;
|
*output++ = node;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
#include <CGAL/license/Orthtree.h>
|
#include <CGAL/license/Orthtree.h>
|
||||||
|
|
||||||
#include <CGAL/Orthtree/IO.h>
|
|
||||||
|
|
||||||
#include <boost/range/iterator_range.hpp>
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
|
||||||
|
|
@ -27,14 +26,15 @@
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief represents a single node of the tree. Alternatively referred to as a cell, orthant, or subtree
|
\brief represents a single node of the tree. Alternatively referred to as a cell, orthant, or subtree
|
||||||
*
|
|
||||||
* \details The role of the node isn't fully stable yet
|
\details The role of the node isn't fully stable yet
|
||||||
*
|
|
||||||
* \tparam Point_index is the datatype the node will contain
|
\tparam Point_index is the datatype the node will contain
|
||||||
*/
|
*/
|
||||||
template<class Traits, class PointRange, class PointMap>
|
template<typename Traits, typename PointRange, typename PointMap>
|
||||||
class Orthtree<Traits, PointRange, PointMap>::Node {
|
class Orthtree<Traits, PointRange, PointMap>::Node
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -79,69 +79,26 @@ public:
|
||||||
*/
|
*/
|
||||||
typedef boost::iterator_range<typename PointRange::iterator> Point_range;
|
typedef boost::iterator_range<typename PointRange::iterator> Point_range;
|
||||||
|
|
||||||
// TODO: Should I use enum classes?
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief the index of a node relative to its parent (a position defined by the corners of a cube)
|
|
||||||
*
|
|
||||||
* Corners are mapped to numbers as 3-bit integers, in "zyx" order.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* > right-top-back --> x=1, y=1, z=0 --> zyx = 011 --> 3
|
|
||||||
*
|
|
||||||
* The following diagram may be a useful reference:
|
|
||||||
*
|
|
||||||
* 6 7
|
|
||||||
* +--------+
|
|
||||||
* /| /| y+
|
|
||||||
* / | / | * z+
|
|
||||||
* 2 +--------+ 3| | *
|
|
||||||
* | | | | |/
|
|
||||||
* | +-----|--+ +-----* x+
|
|
||||||
* | / 4 | / 5
|
|
||||||
* |/ |/
|
|
||||||
* +--------+
|
|
||||||
* 0 1
|
|
||||||
*
|
|
||||||
* This lookup table may also be helpful:
|
|
||||||
*
|
|
||||||
* | Child | bitset | number | Enum |
|
|
||||||
* | --------------------- | ------ | ------ | --------------------- |
|
|
||||||
* | left, bottom, back | 000 | 0 | LEFT_BOTTOM_BACK |
|
|
||||||
* | right, bottom, back | 001 | 1 | RIGHT_BOTTOM_BACK |
|
|
||||||
* | left, top, back | 010 | 2 | LEFT_TOP_BACK |
|
|
||||||
* | right, top, back | 011 | 3 | RIGHT_TOP_BACK |
|
|
||||||
* | left, bottom, front | 100 | 4 | LEFT_BOTTOM_FRONT |
|
|
||||||
* | right, bottom, front | 101 | 5 | RIGHT_BOTTOM_FRONT |
|
|
||||||
* | left, top, front | 110 | 6 | LEFT_TOP_FRONT |
|
|
||||||
* | right, top, front | 111 | 7 | RIGHT_TOP_FRONT |
|
|
||||||
*/
|
|
||||||
enum Child {
|
|
||||||
LEFT_BOTTOM_BACK,
|
|
||||||
RIGHT_BOTTOM_BACK,
|
|
||||||
LEFT_TOP_BACK,
|
|
||||||
RIGHT_TOP_BACK,
|
|
||||||
LEFT_BOTTOM_FRONT,
|
|
||||||
RIGHT_BOTTOM_FRONT,
|
|
||||||
LEFT_TOP_FRONT,
|
|
||||||
RIGHT_TOP_FRONT
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef typename Traits::Adjacency Adjacency;
|
typedef typename Traits::Adjacency Adjacency;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Point_range m_points;
|
// make Node trivially copiabled
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
Point_range points;
|
||||||
|
Self parent;
|
||||||
|
std::uint8_t depth;
|
||||||
|
Int_location location;
|
||||||
|
std::unique_ptr<Children> children;
|
||||||
|
|
||||||
const Self *m_parent;
|
Data (Self parent)
|
||||||
|
: parent (parent), depth (0) { }
|
||||||
|
};
|
||||||
|
|
||||||
std::uint8_t m_depth;
|
std::shared_ptr<Data> m_data;
|
||||||
|
|
||||||
Int_location m_location;
|
|
||||||
|
|
||||||
std::unique_ptr<Children> m_children;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -150,6 +107,9 @@ public:
|
||||||
/// \name Construction
|
/// \name Construction
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
// Default creates null node
|
||||||
|
Node() { }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief creates a new node, optionally as the child of a parent
|
\brief creates a new node, optionally as the child of a parent
|
||||||
|
|
||||||
|
|
@ -163,19 +123,20 @@ public:
|
||||||
\param parent A reference to the node containing this one
|
\param parent A reference to the node containing this one
|
||||||
\param index This node's relationship to its parent
|
\param index This node's relationship to its parent
|
||||||
*/
|
*/
|
||||||
explicit Node(Self *parent = nullptr, Index index = 0) : m_parent(parent), m_depth(0) {
|
explicit Node(Self parent, Index index)
|
||||||
|
: m_data (new Data(parent)) {
|
||||||
|
|
||||||
if (parent) {
|
if (!parent.is_null()) {
|
||||||
|
|
||||||
m_depth = parent->m_depth + 1;
|
m_data->depth = parent.m_data->depth + 1;
|
||||||
|
|
||||||
for (int i = 0; i < Dimension::value; i++)
|
for (int i = 0; i < Dimension::value; i++)
|
||||||
m_location[i] = (2 * parent->m_location[i]) + index[i];
|
m_data->location[i] = (2 * parent.m_data->location[i]) + index[i];
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for (int i = 0; i < Dimension::value; i++)
|
for (int i = 0; i < Dimension::value; i++)
|
||||||
m_location[i] = 0;
|
m_data->location[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
@ -196,10 +157,11 @@ public:
|
||||||
|
|
||||||
assert(is_leaf());
|
assert(is_leaf());
|
||||||
|
|
||||||
m_children = std::make_unique<Children>();
|
m_data->children = std::make_unique<Children>();
|
||||||
for (int index = 0; index < Degree::value; index++) {
|
for (int index = 0; index < Degree::value; index++) {
|
||||||
|
|
||||||
(*m_children)[index] = std::move(Self(this, {Index(index)}));
|
(*m_data->children)[index] = std::move(Self(*this, {Index(index)}));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,7 +173,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void unsplit() {
|
void unsplit() {
|
||||||
|
|
||||||
m_children.reset();
|
m_data->children.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
@ -223,46 +185,31 @@ public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns this node's parent.
|
\brief returns this node's parent.
|
||||||
\pre `!is_root()`
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
const Self* parent() const
|
Self parent() const
|
||||||
{
|
{
|
||||||
CGAL_precondition (!is_root());
|
CGAL_precondition (!is_null());
|
||||||
return m_parent;
|
return m_data->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns the nth child fo this node.
|
\brief returns the nth child fo this node.
|
||||||
|
|
||||||
|
\pre `!is_null()`
|
||||||
\pre `!is_leaf()`
|
\pre `!is_leaf()`
|
||||||
\pre `0 <= index && index < Degree::value`
|
\pre `0 <= index && index < Degree::value`
|
||||||
|
|
||||||
The operator can be chained. For example, `n[5][2][3]` returns the
|
The operator can be chained. For example, `n[5][2][3]` returns the
|
||||||
third child of the second child of the fifth child of a node `n`.
|
third child of the second child of the fifth child of a node `n`.
|
||||||
*/
|
*/
|
||||||
Self& operator[] (std::size_t index) {
|
Self operator[](std::size_t index) const {
|
||||||
|
|
||||||
|
CGAL_precondition (!is_null());
|
||||||
CGAL_precondition (!is_leaf());
|
CGAL_precondition (!is_leaf());
|
||||||
CGAL_precondition (0 <= index && index < Degree::value);
|
CGAL_precondition (0 <= index && index < Degree::value);
|
||||||
|
|
||||||
return (*m_children)[index];
|
return (*m_data->children)[index];
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief returns the nth child fo this node.
|
|
||||||
|
|
||||||
\pre `!is_leaf()`
|
|
||||||
\pre `0 <= index && index < Degree::value`
|
|
||||||
|
|
||||||
The operator can be chained. For example, `n[5][2][3]` returns the
|
|
||||||
third child of the second child of the fifth child of a node `n`.
|
|
||||||
*/
|
|
||||||
const Self& operator[](std::size_t index) const {
|
|
||||||
|
|
||||||
CGAL_precondition (!is_leaf());
|
|
||||||
CGAL_precondition (0 <= index && index < Degree::value);
|
|
||||||
|
|
||||||
return (*m_children)[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
@ -272,22 +219,31 @@ public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns this node's depth.
|
\brief returns this node's depth.
|
||||||
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
std::uint8_t depth() const { return m_depth; }
|
std::uint8_t depth() const
|
||||||
|
{
|
||||||
|
CGAL_precondition (!is_null());
|
||||||
|
return m_data->depth;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns this node's location.
|
\brief returns this node's location.
|
||||||
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
Int_location location() const {
|
Int_location location() const
|
||||||
|
{
|
||||||
return m_location;
|
CGAL_precondition (!is_null());
|
||||||
|
return m_data->location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns this node's index in relation to its parent.
|
\brief returns this node's index in relation to its parent.
|
||||||
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
Index index() const {
|
Index index() const {
|
||||||
|
|
||||||
|
CGAL_precondition (!is_null());
|
||||||
// TODO: There must be a better way of doing this!
|
// TODO: There must be a better way of doing this!
|
||||||
|
|
||||||
Index result;
|
Index result;
|
||||||
|
|
@ -299,72 +255,91 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns `true` if the node has no parent, `false` otherwise.
|
\brief returns `true` if the node is null, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
bool is_root() const { return (!m_parent); }
|
bool is_null() const { return (m_data == nullptr); }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief returns `true` if the node has no parent, `false` otherwise.
|
||||||
|
\pre `!is_null()`
|
||||||
|
*/
|
||||||
|
bool is_root() const
|
||||||
|
{
|
||||||
|
CGAL_precondition(!is_null());
|
||||||
|
return m_data->parent.is_null();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns `true` if the node has no children, `false` otherwise.
|
\brief returns `true` if the node has no children, `false` otherwise.
|
||||||
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
bool is_leaf() const { return (!m_children); }
|
bool is_leaf() const
|
||||||
|
{
|
||||||
|
CGAL_precondition(!is_null());
|
||||||
|
return (!m_data->children);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief find the directly adjacent node in a specific direction
|
\brief find the directly adjacent node in a specific direction
|
||||||
*
|
|
||||||
* Adjacent nodes are found according to several properties:
|
\pre `!is_null()`
|
||||||
* - Adjacent nodes may be larger than the seek node, but never smaller
|
\pre `direction.to_ulong < 2 * Dimension::value`
|
||||||
* - A node can have no more than 6 different adjacent nodes (left, right, up, down, front, back)
|
|
||||||
* - A node is free to have fewer than 6 adjacent nodes
|
Adjacent nodes are found according to several properties:
|
||||||
* (e.g. edge nodes have no neighbors in some directions, the root node has none at all).
|
- Adjacent nodes may be larger than the seek node, but never smaller
|
||||||
* - Adjacent nodes are not required to be leaf nodes
|
- A node can have no more than 6 different adjacent nodes (left, right, up, down, front, back)
|
||||||
*
|
- A node is free to have fewer than 6 adjacent nodes
|
||||||
*
|
(e.g. edge nodes have no neighbors in some directions, the root node has none at all).
|
||||||
* Here's a diagram demonstrating the concept for a quadtree.
|
- Adjacent nodes are not required to be leaf nodes
|
||||||
* Because it's in 2d space, the seek node has only four neighbors (up, down, left, right)
|
|
||||||
*
|
Here's a diagram demonstrating the concept for a quadtree.
|
||||||
* +---------------+---------------+
|
Because it's in 2d space, the seek node has only four neighbors (up, down, left, right)
|
||||||
* | | |
|
|
||||||
* | | |
|
+---------------+---------------+
|
||||||
* | | |
|
| | |
|
||||||
* | A | |
|
| | |
|
||||||
* | | |
|
| | |
|
||||||
* | | |
|
| A | |
|
||||||
* | | |
|
| | |
|
||||||
* +-------+-------+---+---+-------+
|
| | |
|
||||||
* | | | | | |
|
| | |
|
||||||
* | A | (S) +---A---+ |
|
+-------+-------+---+---+-------+
|
||||||
* | | | | | |
|
| | | | | |
|
||||||
* +---+---+-------+---+---+-------+
|
| A | (S) +---A---+ |
|
||||||
* | | | | | |
|
| | | | | |
|
||||||
* +---+---+ A | | |
|
+---+---+-------+---+---+-------+
|
||||||
* | | | | | |
|
| | | | | |
|
||||||
* +---+---+-------+-------+-------+
|
+---+---+ A | | |
|
||||||
*
|
| | | | | |
|
||||||
* (S) : Seek node
|
+---+---+-------+-------+-------+
|
||||||
* A : Adjacent node
|
|
||||||
*
|
(S) : Seek node
|
||||||
* Note how the top adjacent node is larger than the seek node.
|
A : Adjacent node
|
||||||
* The right adjacent node is the same size, even though it contains further subdivisions.
|
|
||||||
*
|
Note how the top adjacent node is larger than the seek node.
|
||||||
* This implementation returns a pointer to the adjacent node if it's found.
|
The right adjacent node is the same size, even though it contains further subdivisions.
|
||||||
* If there is no adjacent node in that direction, it returns nullptr.
|
|
||||||
*
|
This implementation returns a pointer to the adjacent node if it's found.
|
||||||
* \todo explain how direction is encoded
|
If there is no adjacent node in that direction, it returns nullptr.
|
||||||
*
|
|
||||||
* \param direction which way to find the adjacent node relative to this one
|
\todo explain how direction is encoded
|
||||||
* \return a pointer to the adjacent node if it exists
|
|
||||||
|
\param direction which way to find the adjacent node relative to this one
|
||||||
|
\return a pointer to the adjacent node if it exists
|
||||||
*/
|
*/
|
||||||
const Self *adjacent_node(std::bitset<Dimension::value> direction) const {
|
Self adjacent_node (std::bitset<Dimension::value> direction) const
|
||||||
|
{
|
||||||
|
CGAL_precondition(!is_null());
|
||||||
|
|
||||||
// Direction: LEFT RIGHT DOWN UP BACK FRONT
|
// Direction: LEFT RIGHT DOWN UP BACK FRONT
|
||||||
// direction: 000 001 010 011 100 101
|
// direction: 000 001 010 011 100 101
|
||||||
|
|
||||||
// Nodes only have up to 6 different adjacent nodes (since cubes have 6 sides)
|
// Nodes only have up to 2*dim different adjacent nodes (since cubes have 6 sides)
|
||||||
assert(direction.to_ulong() < 6);
|
CGAL_precondition(direction.to_ulong() < Dimension::value * 2);
|
||||||
|
|
||||||
// The root node has no adjacent nodes!
|
// The root node has no adjacent nodes!
|
||||||
if (is_root())
|
if (is_root())
|
||||||
return nullptr;
|
return Self();
|
||||||
|
|
||||||
// The least significant bit indicates the sign (which side of the node)
|
// The least significant bit indicates the sign (which side of the node)
|
||||||
bool sign = direction[0];
|
bool sign = direction[0];
|
||||||
|
|
@ -382,43 +357,29 @@ public:
|
||||||
if (index()[dimension] != sign) {
|
if (index()[dimension] != sign) {
|
||||||
|
|
||||||
// This means the adjacent node is a direct sibling, the offset can be applied easily!
|
// This means the adjacent node is a direct sibling, the offset can be applied easily!
|
||||||
return &(*parent())[index().to_ulong() + offset];
|
return parent()[index().to_ulong() + offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the parent's neighbor in that direction if it exists
|
// Find the parent's neighbor in that direction if it exists
|
||||||
auto *adjacent_node_of_parent = parent()->adjacent_node(direction);
|
Self adjacent_node_of_parent = parent().adjacent_node(direction);
|
||||||
|
|
||||||
// If the parent has no neighbor, then this node doesn't have one
|
// If the parent has no neighbor, then this node doesn't have one
|
||||||
if (!adjacent_node_of_parent)
|
if (adjacent_node_of_parent.is_null())
|
||||||
return nullptr;
|
return Node();
|
||||||
|
|
||||||
// If the parent's adjacent node has no children, then it's this node's adjacent node
|
// If the parent's adjacent node has no children, then it's this node's adjacent node
|
||||||
if (adjacent_node_of_parent->is_leaf())
|
if (adjacent_node_of_parent.is_leaf())
|
||||||
return adjacent_node_of_parent;
|
return adjacent_node_of_parent;
|
||||||
|
|
||||||
// Return the nearest node of the parent by subtracting the offset instead of adding
|
// Return the nearest node of the parent by subtracting the offset instead of adding
|
||||||
return &(*adjacent_node_of_parent)[index().to_ulong() - offset];
|
return adjacent_node_of_parent[index().to_ulong() - offset];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief equivalent to adjacent_node, with a Direction rather than a bitset
|
* \brief equivalent to adjacent_node, with a Direction rather than a bitset
|
||||||
*/
|
*/
|
||||||
const Self *adjacent_node(Adjacency adjacency) const {
|
Self adjacent_node(Adjacency adjacency) const {
|
||||||
return adjacent_node(std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief equivalent to adjacent_node, except non-const
|
|
||||||
*/
|
|
||||||
Self *adjacent_node(std::bitset<Dimension::value> direction) {
|
|
||||||
return const_cast<Self *>(const_cast<const Self *>(this)->adjacent_node(direction));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief equivalent to adjacent_node, with a Direction rather than a bitset and non-const
|
|
||||||
*/
|
|
||||||
Self *adjacent_node(Adjacency adjacency) {
|
|
||||||
return adjacent_node(std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
return adjacent_node(std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,44 +392,44 @@ public:
|
||||||
* \brief access to the content held by this node
|
* \brief access to the content held by this node
|
||||||
* \return a reference to the collection of point indices
|
* \return a reference to the collection of point indices
|
||||||
*/
|
*/
|
||||||
Point_range &points() { return m_points; }
|
Point_range &points() { return m_data->points; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief access to the points via iterator
|
* \brief access to the points via iterator
|
||||||
* \return the iterator at the start of the collection of point indices held by this node
|
* \return the iterator at the start of the collection of point indices held by this node
|
||||||
*/
|
*/
|
||||||
typename Point_range::iterator begin() { return m_points.begin(); }
|
typename Point_range::iterator begin() { return m_data->points.begin(); }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief access to the points via iterator
|
* \brief access to the points via iterator
|
||||||
* \return the iterator at the end of the collection of point indices held by this node
|
* \return the iterator at the end of the collection of point indices held by this node
|
||||||
*/
|
*/
|
||||||
typename Point_range::iterator end() { return m_points.end(); }
|
typename Point_range::iterator end() { return m_data->points.end(); }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief read-only access to the content held by this node
|
* \brief read-only access to the content held by this node
|
||||||
* \return a read-only reference to the collection of point indices
|
* \return a read-only reference to the collection of point indices
|
||||||
*/
|
*/
|
||||||
const Point_range &points() const { return m_points; }
|
const Point_range &points() const { return m_data->points; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief read-only access to the points via iterator
|
* \brief read-only access to the points via iterator
|
||||||
* \return the iterator at the start of the collection of point indices held by this node
|
* \return the iterator at the start of the collection of point indices held by this node
|
||||||
*/
|
*/
|
||||||
typename Point_range::iterator begin() const { return m_points.begin(); }
|
typename Point_range::iterator begin() const { return m_data->points.begin(); }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief read-only access to the points via iterator
|
* \brief read-only access to the points via iterator
|
||||||
* \return the iterator at the end of the collection of point indices held by this node
|
* \return the iterator at the end of the collection of point indices held by this node
|
||||||
*/
|
*/
|
||||||
typename Point_range::iterator end() const { return m_points.end(); }
|
typename Point_range::iterator end() const { return m_data->points.end(); }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief check whether this node contains any points
|
* \brief check whether this node contains any points
|
||||||
* \return if this node contains no points
|
* \return if this node contains no points
|
||||||
*/
|
*/
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return m_points.empty();
|
return m_data->points.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -476,7 +437,7 @@ public:
|
||||||
* \return the number of points this node owns
|
* \return the number of points this node owns
|
||||||
*/
|
*/
|
||||||
std::size_t size() const {
|
std::size_t size() const {
|
||||||
return std::distance(m_points.begin(), m_points.end());
|
return std::distance(m_data->points.begin(), m_data->points.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
@ -495,9 +456,12 @@ public:
|
||||||
bool operator==(const Self &rhs) const {
|
bool operator==(const Self &rhs) const {
|
||||||
|
|
||||||
// TODO: Should I compare the values they contain
|
// TODO: Should I compare the values they contain
|
||||||
// if (m_points != rhs.m_points)
|
// if (m_data->points != rhs.m_data->points)
|
||||||
// return false;
|
// return false;
|
||||||
|
|
||||||
|
if (is_null() || rhs.is_null())
|
||||||
|
return (is_null() == rhs.is_null());
|
||||||
|
|
||||||
// If one node is a leaf, and the other isn't, they're not the same
|
// If one node is a leaf, and the other isn't, they're not the same
|
||||||
if (is_leaf() != rhs.is_leaf())
|
if (is_leaf() != rhs.is_leaf())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -509,7 +473,7 @@ public:
|
||||||
for (int i = 0; i < Degree::value; ++i) {
|
for (int i = 0; i < Degree::value; ++i) {
|
||||||
|
|
||||||
// If any child cell is different, they're not the same
|
// If any child cell is different, they're not the same
|
||||||
if ((*m_children)[i] != rhs[i])
|
if ((*m_data->children)[i] != rhs[i])
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,57 +25,57 @@ namespace Orthtrees {
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* next_sibling(const Node* n) {
|
Node next_sibling(Node n) {
|
||||||
|
|
||||||
// Passing null returns the first node
|
// Passing null returns the first node
|
||||||
if (nullptr == n)
|
if (n.is_null())
|
||||||
return nullptr;
|
return Node();
|
||||||
|
|
||||||
// If this node has no parent, it has no siblings
|
// If this node has no parent, it has no siblings
|
||||||
if (nullptr == n->parent())
|
if (n.parent().is_null())
|
||||||
return nullptr;
|
return Node();
|
||||||
|
|
||||||
// Find out which child this is
|
// Find out which child this is
|
||||||
std::size_t index = n->index().to_ulong();
|
std::size_t index = n.index().to_ulong();
|
||||||
|
|
||||||
constexpr static int degree = Node::Degree::value;
|
constexpr static int degree = Node::Degree::value;
|
||||||
// Return null if this is the last child
|
// Return null if this is the last child
|
||||||
if (index == degree - 1)
|
if (index == degree - 1)
|
||||||
return nullptr;
|
return Node();
|
||||||
|
|
||||||
// Otherwise, return the next child
|
// Otherwise, return the next child
|
||||||
return &((*n->parent())[index + 1]);
|
return n.parent()[index + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* next_sibling_up(const Node* n) {
|
Node next_sibling_up(Node n) {
|
||||||
|
|
||||||
if (!n)
|
if (n.is_null())
|
||||||
return nullptr;
|
return Node();
|
||||||
|
|
||||||
auto up = n->parent();
|
Node up = n.parent();
|
||||||
|
|
||||||
while (nullptr != up) {
|
while (!up.is_null()) {
|
||||||
|
|
||||||
if (nullptr != next_sibling(up))
|
if (!next_sibling(up).is_null())
|
||||||
return next_sibling(up);
|
return next_sibling(up);
|
||||||
|
|
||||||
up = up->parent();
|
up = up.parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return Node();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* deepest_first_child(const Node* n) {
|
Node deepest_first_child(Node n) {
|
||||||
|
|
||||||
if (!n)
|
if (n.is_null())
|
||||||
return nullptr;
|
return Node();
|
||||||
|
|
||||||
// Find the deepest child on the left
|
// Find the deepest child on the left
|
||||||
auto first = n;
|
Node first = n;
|
||||||
while (!first->is_leaf())
|
while (!first.is_leaf())
|
||||||
first = &(*first)[0];
|
first = first[0];
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ struct Preorder {
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* first(const Node* root) const {
|
Node first(Node root) const {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,25 +109,20 @@ struct Preorder {
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* next(const Node* n) const {
|
Node next(Node n) const {
|
||||||
|
|
||||||
if (n->is_leaf()) {
|
if (n.is_leaf()) {
|
||||||
|
|
||||||
auto next = next_sibling(n);
|
Node next = next_sibling(n);
|
||||||
|
|
||||||
if (nullptr == next) {
|
|
||||||
|
|
||||||
|
if (next.is_null())
|
||||||
return next_sibling_up(n);
|
return next_sibling_up(n);
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Return the first child of this node
|
|
||||||
return &(*n)[0];
|
|
||||||
}
|
}
|
||||||
|
else // Return the first child of this node
|
||||||
|
return n[0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -145,7 +140,7 @@ struct Postorder {
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* first(const Node* root) const {
|
Node first(Node root) const {
|
||||||
|
|
||||||
return deepest_first_child(root);
|
return deepest_first_child(root);
|
||||||
}
|
}
|
||||||
|
|
@ -158,12 +153,12 @@ struct Postorder {
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* next(const Node* n) const {
|
Node next(Node n) const {
|
||||||
|
|
||||||
auto next = deepest_first_child(next_sibling(n));
|
Node next = deepest_first_child(next_sibling(n));
|
||||||
|
|
||||||
if (!next)
|
if (!next)
|
||||||
next = n->parent();
|
next = n.parent();
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +178,7 @@ struct Leaves {
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* first(const Node* root) const {
|
Node first(Node root) const {
|
||||||
|
|
||||||
return deepest_first_child(root);
|
return deepest_first_child(root);
|
||||||
}
|
}
|
||||||
|
|
@ -196,11 +191,11 @@ struct Leaves {
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* next(const Node* n) const {
|
Node next(Node n) const {
|
||||||
|
|
||||||
auto next = deepest_first_child(next_sibling(n));
|
Node next = deepest_first_child(next_sibling(n));
|
||||||
|
|
||||||
if (!next)
|
if (next.is_null())
|
||||||
next = deepest_first_child(next_sibling_up(n));
|
next = deepest_first_child(next_sibling_up(n));
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ public:
|
||||||
*
|
*
|
||||||
* \todo
|
* \todo
|
||||||
*/
|
*/
|
||||||
typedef std::function<Value *(Value *)> Traversal_function;
|
typedef std::function<Value(Value)> Traversal_function;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ public:
|
||||||
*
|
*
|
||||||
* \todo
|
* \todo
|
||||||
*/
|
*/
|
||||||
Traversal_iterator() : m_value(nullptr), m_next() {}
|
Traversal_iterator() : m_value(), m_next() {}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief
|
* \brief
|
||||||
|
|
@ -68,7 +68,7 @@ public:
|
||||||
* \param first
|
* \param first
|
||||||
* \param next
|
* \param next
|
||||||
*/
|
*/
|
||||||
Traversal_iterator(Value *first, const Traversal_function &next) : m_value(first), m_next(next) {}
|
Traversal_iterator(Value first, const Traversal_function &next) : m_value(first), m_next(next) {}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
@ -84,12 +84,12 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
Value &dereference() const {
|
Value &dereference() const {
|
||||||
return *m_value;
|
return const_cast<Value&>(m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Value *m_value;
|
Value m_value;
|
||||||
Traversal_function m_next;
|
Traversal_function m_next;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ public:
|
||||||
{
|
{
|
||||||
Point_d operator() (const Array& array) const
|
Point_d operator() (const Array& array) const
|
||||||
{
|
{
|
||||||
return Point_d ( /* todo */ );
|
return Point_d (array.begin(), array.end());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -102,7 +102,8 @@ public:
|
||||||
Bbox_d operator() (const Array& min,
|
Bbox_d operator() (const Array& min,
|
||||||
const Array& max) const
|
const Array& max) const
|
||||||
{
|
{
|
||||||
return Bbox_d ( /* todo */ );
|
return Bbox_d (Point_d (min.begin(), min.end()),
|
||||||
|
Point_d (max.begin(), max.end()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue