mirror of https://github.com/CGAL/cgal
Eliminate heap allocated `Data *m_data`
This required changing return types to `Node *` in many cases. All unit tests have been updated to account for the new interface.
This commit is contained in:
parent
6e901604cb
commit
4f6d249c1f
|
|
@ -35,9 +35,11 @@ namespace CGAL {
|
||||||
\tparam PointRange_ must be a model of range whose value type is the key type of `PointMap`
|
\tparam PointRange_ must be a model of range whose value type is the key type of `PointMap`
|
||||||
\tparam PointMap must be a model of `ReadablePropertyMap` whose value type is `GeomTraits::Point_3`
|
\tparam PointMap must be a model of `ReadablePropertyMap` whose value type is `GeomTraits::Point_3`
|
||||||
*/
|
*/
|
||||||
template <typename GeomTraits, typename PointRange,
|
template <
|
||||||
typename PointMap = Identity_property_map
|
typename GeomTraits,
|
||||||
<typename std::iterator_traits<typename PointRange::iterator>::value_type> >
|
typename PointRange,
|
||||||
|
typename PointMap = Identity_property_map<typename std::iterator_traits<typename PointRange::iterator>::value_type>
|
||||||
|
>
|
||||||
#ifdef DOXYGEN_RUNNING
|
#ifdef DOXYGEN_RUNNING
|
||||||
class Octree;
|
class Octree;
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL
|
||||||
|
{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\ingroup PkgOrthtreeClasses
|
\ingroup PkgOrthtreeClasses
|
||||||
|
|
@ -123,7 +124,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<Node> > Node_range;
|
typedef boost::iterator_range<Traversal_iterator<const Node>> Node_range;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
|
@ -131,7 +132,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<Node(Node)> Node_traversal_method_const;
|
typedef std::function<const Node *(const Node *)> Node_traversal_method_const;
|
||||||
|
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
|
|
@ -196,7 +197,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)
|
, m_root() // todo: can this be default-constructed?
|
||||||
{
|
{
|
||||||
Array bbox_min;
|
Array bbox_min;
|
||||||
Array bbox_max;
|
Array bbox_max;
|
||||||
|
|
@ -260,8 +261,7 @@ public:
|
||||||
, m_point_map(other.m_point_map)
|
, m_point_map(other.m_point_map)
|
||||||
, m_root(other.m_root.deep_copy())
|
, m_root(other.m_root.deep_copy())
|
||||||
, m_bbox_min(other.m_bbox_min)
|
, m_bbox_min(other.m_bbox_min)
|
||||||
, m_side_per_depth(other.m_side_per_depth)
|
, m_side_per_depth(other.m_side_per_depth) {}
|
||||||
{ }
|
|
||||||
|
|
||||||
// move constructor
|
// move constructor
|
||||||
Orthtree(Orthtree&& other)
|
Orthtree(Orthtree&& other)
|
||||||
|
|
@ -270,31 +270,16 @@ public:
|
||||||
, m_point_map(other.m_point_map)
|
, m_point_map(other.m_point_map)
|
||||||
, m_root(other.m_root)
|
, m_root(other.m_root)
|
||||||
, m_bbox_min(other.m_bbox_min)
|
, m_bbox_min(other.m_bbox_min)
|
||||||
, m_side_per_depth(other.m_side_per_depth)
|
, m_side_per_depth(other.m_side_per_depth) {
|
||||||
{
|
other.m_root = Node{};
|
||||||
other.m_root = Node(Node(), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-necessary but just to be clear on the rule of 5:
|
// Non-necessary but just to be clear on the rule of 5:
|
||||||
|
|
||||||
// assignment operators deleted (PointRange is a ref)
|
// assignment operators deleted (PointRange is a ref)
|
||||||
Orthtree& operator=(const Orthtree& other) = delete;
|
Orthtree& operator=(const Orthtree& other) = delete;
|
||||||
|
|
||||||
Orthtree& operator=(Orthtree&& other) = delete;
|
Orthtree& operator=(Orthtree&& other) = delete;
|
||||||
// Destructor
|
|
||||||
~Orthtree()
|
|
||||||
{
|
|
||||||
std::queue<Node> nodes;
|
|
||||||
nodes.push(m_root);
|
|
||||||
while (!nodes.empty())
|
|
||||||
{
|
|
||||||
Node node = nodes.front();
|
|
||||||
nodes.pop();
|
|
||||||
if (!node.is_leaf())
|
|
||||||
for (std::size_t i = 0; i < Degree::value; ++ i)
|
|
||||||
nodes.push (node[i]);
|
|
||||||
node.free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// move constructor
|
// move constructor
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
@ -320,52 +305,39 @@ public:
|
||||||
void refine(const Split_predicate& split_predicate) {
|
void refine(const Split_predicate& split_predicate) {
|
||||||
|
|
||||||
// If the tree has already been refined, reset it
|
// If the tree has already been refined, reset it
|
||||||
if (!m_root.is_leaf()){
|
if (!m_root.is_leaf())
|
||||||
std::queue<Node> nodes;
|
|
||||||
for (std::size_t i = 0; i < Degree::value; ++ i)
|
|
||||||
nodes.push (m_root[i]);
|
|
||||||
while (!nodes.empty())
|
|
||||||
{
|
|
||||||
Node node = nodes.front();
|
|
||||||
nodes.pop();
|
|
||||||
if (!node.is_leaf())
|
|
||||||
for (std::size_t i = 0; i < Degree::value; ++ i)
|
|
||||||
nodes.push (node[i]);
|
|
||||||
node.free();
|
|
||||||
}
|
|
||||||
m_root.unsplit();
|
m_root.unsplit();
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the side length map, too
|
// Reset the side length map, too
|
||||||
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
|
||||||
Node current = todo.front();
|
auto 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() == depth()) {
|
if (current->depth() == depth()) {
|
||||||
|
|
||||||
// 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]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -401,52 +373,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 (Node leaf : traverse(Orthtrees::Leaves_traversal())) {
|
for (const Node &leaf : traverse(Orthtrees::Leaves_traversal())) {
|
||||||
// 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(leaf);
|
leaf_nodes.push(const_cast<Node *>(&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
|
||||||
Node neighbor = node.adjacent_node(direction);
|
auto *neighbor = node->adjacent_node(direction);
|
||||||
|
|
||||||
// If it doesn't exist, skip it
|
// If it doesn't exist, skip it
|
||||||
if (neighbor.is_null())
|
if (!neighbor)
|
||||||
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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -459,9 +431,22 @@ public:
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns the root node.
|
\brief provides read-only access to the root node, and by
|
||||||
|
extension the rest of the tree.
|
||||||
|
|
||||||
|
\return a const reference to the root node of the tree.
|
||||||
*/
|
*/
|
||||||
Node root() const { return m_root; }
|
const Node &root() const { return m_root; }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief provides read-write access to the root node, and by
|
||||||
|
extension the rest of the tree.
|
||||||
|
|
||||||
|
todo: why wasn't this provided previously?
|
||||||
|
|
||||||
|
\return a reference to the root node of the tree.
|
||||||
|
*/
|
||||||
|
Node &root() { 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
|
||||||
|
|
@ -472,9 +457,9 @@ public:
|
||||||
\sa `Node::operator[]()`
|
\sa `Node::operator[]()`
|
||||||
|
|
||||||
\param index the index of the child node.
|
\param index the index of the child node.
|
||||||
\return the accessed node.
|
\return a reference to the node.
|
||||||
*/
|
*/
|
||||||
Node operator[](std::size_t index) const { return m_root[index]; }
|
const Node &operator[](std::size_t index) const { return m_root[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).
|
||||||
|
|
@ -497,13 +482,13 @@ public:
|
||||||
template<typename Traversal>
|
template<typename Traversal>
|
||||||
Node_range traverse(const Traversal &traversal = Traversal()) const {
|
Node_range traverse(const Traversal &traversal = Traversal()) const {
|
||||||
|
|
||||||
Node first = traversal.first(m_root);
|
const Node *first = traversal.first(&m_root);
|
||||||
|
|
||||||
Node_traversal_method_const next
|
Node_traversal_method_const next
|
||||||
= [&](const Node& n) -> Node { return traversal.next(n); };
|
= [&](const Node* n) -> const Node * { return traversal.next(n); };
|
||||||
|
|
||||||
return boost::make_iterator_range(Traversal_iterator<Node>(first, next),
|
return boost::make_iterator_range(Traversal_iterator<const Node>(first, next),
|
||||||
Traversal_iterator<Node>());
|
Traversal_iterator<const Node>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -547,19 +532,19 @@ public:
|
||||||
\param point query point.
|
\param point query point.
|
||||||
\return the node which contains the point.
|
\return the node which contains the point.
|
||||||
*/
|
*/
|
||||||
Node locate(const Point &point) const {
|
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::Local_coordinates index;
|
typename Node::Local_coordinates index;
|
||||||
|
|
@ -568,11 +553,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -582,9 +567,9 @@ public:
|
||||||
`query`.
|
`query`.
|
||||||
|
|
||||||
\tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects.
|
\tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects.
|
||||||
\param query a query point.
|
\param query query point.
|
||||||
\param k the number of neighbors.
|
\param k number of neighbors.
|
||||||
\param output the output iterator.
|
\param output output iterator.
|
||||||
*/
|
*/
|
||||||
template <typename OutputIterator>
|
template <typename OutputIterator>
|
||||||
OutputIterator nearest_neighbors(const Point& query,
|
OutputIterator nearest_neighbors(const Point& query,
|
||||||
|
|
@ -703,7 +688,8 @@ private: // functions :
|
||||||
// Split the point collection around the center point on this dimension
|
// Split the point collection around the center point on this dimension
|
||||||
Range_iterator split_point = std::partition
|
Range_iterator split_point = std::partition
|
||||||
(begin, end,
|
(begin, end,
|
||||||
[&](const Range_type &a) -> bool {
|
[&](const Range_type& a) -> bool
|
||||||
|
{
|
||||||
// This should be done with cartesian iterator but it seems
|
// This should be done with cartesian iterator but it seems
|
||||||
// complicated to do efficiently
|
// complicated to do efficiently
|
||||||
return (get(m_point_map, a)[int(dimension)] < center[int(dimension)]);
|
return (get(m_point_map, a)[int(dimension)] < center[int(dimension)]);
|
||||||
|
|
@ -755,14 +741,15 @@ private: // functions :
|
||||||
Point point;
|
Point point;
|
||||||
FT distance;
|
FT distance;
|
||||||
};
|
};
|
||||||
struct Node_index_with_distance {
|
|
||||||
|
struct Node_index_with_distance
|
||||||
|
{
|
||||||
typename Node::Local_coordinates index;
|
typename Node::Local_coordinates index;
|
||||||
FT distance;
|
FT distance;
|
||||||
|
|
||||||
Node_index_with_distance(const typename Node::Local_coordinates& index,
|
Node_index_with_distance(const typename Node::Local_coordinates& index,
|
||||||
const FT& distance)
|
const FT& distance)
|
||||||
: index(index), distance(distance)
|
: index(index), distance(distance) {}
|
||||||
{ }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void nearest_k_neighbors_recursive(Sphere &search_bounds, const Node& node,
|
void nearest_k_neighbors_recursive(Sphere &search_bounds, const Node& node,
|
||||||
|
|
@ -820,7 +807,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) {
|
||||||
Node child_node = node[index];
|
auto &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.emplace_back(typename Node::Local_coordinates(index),
|
children_with_distances.emplace_back(typename Node::Local_coordinates(index),
|
||||||
|
|
@ -834,7 +821,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) {
|
||||||
Node child_node = node[child_with_distance.index.to_ulong()];
|
auto &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)) {
|
||||||
|
|
@ -853,9 +840,9 @@ private: // functions :
|
||||||
// Check if the current node intersects with the query
|
// Check if the current node intersects with the query
|
||||||
if (CGAL::do_intersect(query, bbox(node))) {
|
if (CGAL::do_intersect(query, bbox(node))) {
|
||||||
|
|
||||||
// if this node is a leaf, than it's considered an intersecting node
|
// if this node is a leaf, then it's considered an intersecting node
|
||||||
if (node.is_leaf()) {
|
if (node.is_leaf()) {
|
||||||
*output++ = node;
|
*output++ = &node;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -907,8 +894,7 @@ private: // functions :
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
void dump_to_polylines (std::ostream& os) const
|
void dump_to_polylines(std::ostream& os) const {
|
||||||
{
|
|
||||||
for (const Node& n: traverse<Orthtrees::Preorder_traversal>())
|
for (const Node& n: traverse<Orthtrees::Preorder_traversal>())
|
||||||
if (n.is_leaf())
|
if (n.is_leaf())
|
||||||
{
|
{
|
||||||
|
|
@ -917,8 +903,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_box_to_polylines (const Bbox_2& box, std::ostream& os) const
|
void dump_box_to_polylines(const Bbox_2& box, std::ostream& os) const {
|
||||||
{
|
|
||||||
// dump in 3D for visualisation
|
// dump in 3D for visualisation
|
||||||
os << "5 "
|
os << "5 "
|
||||||
<< box.xmin() << " " << box.ymin() << " 0 "
|
<< box.xmin() << " " << box.ymin() << " 0 "
|
||||||
|
|
@ -927,8 +912,8 @@ public:
|
||||||
<< box.xmax() << " " << box.ymin() << " 0 "
|
<< box.xmax() << " " << box.ymin() << " 0 "
|
||||||
<< box.xmin() << " " << box.ymin() << " 0" << std::endl;
|
<< box.xmin() << " " << box.ymin() << " 0" << std::endl;
|
||||||
}
|
}
|
||||||
void dump_box_to_polylines (const Bbox_3& box, std::ostream& os) const
|
|
||||||
{
|
void dump_box_to_polylines(const Bbox_3& box, std::ostream& os) const {
|
||||||
// Back face
|
// Back face
|
||||||
os << "5 "
|
os << "5 "
|
||||||
<< box.xmin() << " " << box.ymin() << " " << box.zmin() << " "
|
<< box.xmin() << " " << box.ymin() << " " << box.zmin() << " "
|
||||||
|
|
@ -960,12 +945,12 @@ public:
|
||||||
<< box.xmax() << " " << box.ymax() << " " << box.zmax() << std::endl;
|
<< box.xmax() << " " << box.ymax() << " " << box.zmax() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<< (std::ostream& os, const Self& orthtree)
|
friend std::ostream& operator<<(std::ostream& os, const Self& orthtree) {
|
||||||
{
|
|
||||||
// Create a range of nodes
|
// Create a range of nodes
|
||||||
auto nodes = orthtree.traverse(Orthtrees::Preorder_traversal());
|
auto nodes = orthtree.traverse(Orthtrees::Preorder_traversal());
|
||||||
// Iterate over the range
|
// Iterate over the range
|
||||||
for (auto &n : nodes) {
|
for (auto& n: nodes)
|
||||||
|
{
|
||||||
// Show the depth
|
// Show the depth
|
||||||
for (int i = 0; i < n.depth(); ++i)
|
for (int i = 0; i < n.depth(); ++i)
|
||||||
os << ". ";
|
os << ". ";
|
||||||
|
|
|
||||||
|
|
@ -27,42 +27,20 @@
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
namespace Orthtrees
|
namespace Orthtrees {
|
||||||
{
|
|
||||||
|
|
||||||
// Non-documented, or testing purpose only
|
// Non-documented, or testing purpose only
|
||||||
struct Node_access
|
struct Node_access {
|
||||||
{
|
|
||||||
template <typename Node, typename LC>
|
template <typename Node, typename LC>
|
||||||
static Node create_node (Node parent, LC local_coordinates)
|
static Node create_node(Node* parent, LC local_coordinates) {
|
||||||
{
|
|
||||||
return Node(parent, local_coordinates);
|
return Node(parent, local_coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
static typename Node::Point_range& points(Node node) { return node.points(); }
|
static typename Node::Point_range& points(Node& node) { return node.points(); }
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
static void split(Node node) { return node.split(); }
|
static void split(Node& node) { return node.split(); }
|
||||||
|
|
||||||
template <typename Node>
|
|
||||||
static void free(Node node)
|
|
||||||
{
|
|
||||||
typedef Dimension_tag<(2 << (Node::Dimension::value - 1))> Degree;
|
|
||||||
std::queue<Node> nodes;
|
|
||||||
nodes.push(node);
|
|
||||||
while (!nodes.empty())
|
|
||||||
{
|
|
||||||
Node node = nodes.front();
|
|
||||||
nodes.pop();
|
|
||||||
if (!node.is_leaf()){
|
|
||||||
for (std::size_t i = 0; i < Degree::value; ++ i){
|
|
||||||
nodes.push (node[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node.free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -80,8 +58,7 @@ struct Node_access
|
||||||
\cgalModels `ConstRange`
|
\cgalModels `ConstRange`
|
||||||
*/
|
*/
|
||||||
template <typename Traits, typename PointRange, typename PointMap>
|
template <typename Traits, typename PointRange, typename PointMap>
|
||||||
class Orthtree<Traits, PointRange, PointMap>::Node
|
class Orthtree<Traits, PointRange, PointMap>::Node {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -144,20 +121,25 @@ private:
|
||||||
typedef boost::iterator_range<iterator> Point_range;
|
typedef boost::iterator_range<iterator> Point_range;
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
// make Node trivially copiabled
|
// make Node trivially copiable
|
||||||
struct Data
|
// struct Data
|
||||||
{
|
// {
|
||||||
Point_range points;
|
// Point_range points;
|
||||||
Self parent;
|
// Self parent;
|
||||||
std::uint8_t depth;
|
// std::uint8_t depth;
|
||||||
Global_coordinates global_coordinates;
|
// Global_coordinates global_coordinates;
|
||||||
std::unique_ptr<Children> children;
|
// std::unique_ptr<Children> children;
|
||||||
|
//
|
||||||
|
// Data (Self parent)
|
||||||
|
// : parent (parent), depth (0) { }
|
||||||
|
// };
|
||||||
|
// Data* m_data;
|
||||||
|
|
||||||
Data (Self parent)
|
Point_range m_points;
|
||||||
: parent (parent), depth (0) { }
|
Self* m_parent; // todo: use optional<reference_wrapper<Self>> instead of Self *
|
||||||
};
|
std::uint8_t m_depth;
|
||||||
|
Global_coordinates m_global_coordinates;
|
||||||
Data* m_data;
|
std::shared_ptr<Children> m_children;
|
||||||
|
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
|
@ -173,8 +155,9 @@ private:
|
||||||
* \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_data->points; }
|
Point_range& points() { return m_points; }
|
||||||
const Point_range &points() const { return m_data->points; }
|
|
||||||
|
const Point_range& points() const { return m_points; }
|
||||||
|
|
||||||
/// \name Construction
|
/// \name Construction
|
||||||
/// @{
|
/// @{
|
||||||
|
|
@ -194,42 +177,38 @@ private:
|
||||||
\param parent the node containing this one
|
\param parent 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, Local_coordinates local_coordinates)
|
explicit Node(Self* parent, Local_coordinates local_coordinates)
|
||||||
: m_data (new Data(parent)) {
|
: m_parent(parent) {
|
||||||
|
|
||||||
if (!parent.is_null()) {
|
if (parent != nullptr) {
|
||||||
|
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_data->global_coordinates[i] = (2 * parent.m_data->global_coordinates[i]) + local_coordinates[i];
|
m_global_coordinates[i] = (2 * parent->m_global_coordinates[i]) + local_coordinates[i];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
m_depth = 0;
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
for (int i = 0; i < Dimension::value; i++)
|
for (int i = 0; i < Dimension::value; i++)
|
||||||
m_data->global_coordinates[i] = 0;
|
m_global_coordinates[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free() { delete m_data; }
|
Node deep_copy(Self parent = Node()) const {
|
||||||
|
|
||||||
Node deep_copy(Self parent = Node()) const
|
|
||||||
{
|
|
||||||
if (is_null())
|
|
||||||
return Node();
|
|
||||||
|
|
||||||
Node out;
|
Node out;
|
||||||
out.m_data = new Data(parent);
|
|
||||||
|
|
||||||
out.m_data->points = m_data->points;
|
out.m_parent = m_parent;
|
||||||
out.m_data->depth = m_data->depth;
|
out.m_points = m_points;
|
||||||
out.m_data->global_coordinates = m_data->global_coordinates;
|
out.m_depth = m_depth;
|
||||||
std::unique_ptr<Children> children;
|
out.m_global_coordinates = m_global_coordinates;
|
||||||
if (!is_leaf())
|
|
||||||
{
|
if (!is_leaf()) {
|
||||||
out.m_data->children = std::make_unique<Children>();
|
out.m_children = std::make_shared<Children>();
|
||||||
for (int index = 0; index < Degree::value; index++)
|
for (int index = 0; index < Degree::value; index++)
|
||||||
(*out.m_data->children)[index] = (*this)[index].deep_copy(out);
|
(*out.m_children)[index] = (*m_children)[index].deep_copy(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,10 +230,10 @@ private:
|
||||||
|
|
||||||
CGAL_precondition (is_leaf());
|
CGAL_precondition (is_leaf());
|
||||||
|
|
||||||
m_data->children = std::make_unique<Children>();
|
m_children = std::make_shared<Children>();
|
||||||
for (int index = 0; index < Degree::value; index++) {
|
for (int index = 0; index < Degree::value; index++) {
|
||||||
|
|
||||||
(*m_data->children)[index] = std::move(Self(*this, {Local_coordinates(index)}));
|
(*m_children)[index] = std::move(Self(this, {Local_coordinates(index)}));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,7 +246,7 @@ private:
|
||||||
*/
|
*/
|
||||||
void unsplit() {
|
void unsplit() {
|
||||||
|
|
||||||
m_data->children.reset();
|
m_children.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
@ -279,10 +258,12 @@ public:
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
// Default creates null node
|
// Default creates null node
|
||||||
Node() : m_data(nullptr) { }
|
// todo: default node is no longer null, but still isn't guaranteed to be valid
|
||||||
|
Node() = default;
|
||||||
|
|
||||||
// Comparison operator
|
// Comparison operator
|
||||||
bool operator< (const Node& other) const { return m_data < other.m_data; }
|
// todo: where is this used
|
||||||
|
//bool operator<(const Node& other) const { return m_data < other.m_data; }
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
/// \name Type & Location
|
/// \name Type & Location
|
||||||
|
|
@ -291,36 +272,30 @@ public:
|
||||||
/*!
|
/*!
|
||||||
\brief returns `true` if the node is null, `false` otherwise.
|
\brief returns `true` if the node is null, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
bool is_null() const { return (m_data == nullptr); }
|
//bool is_null() const { return (m_data == nullptr); }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns `true` if the node has no parent, `false` otherwise.
|
\brief returns `true` if the node has no parent, `false` otherwise.
|
||||||
\pre `!is_null()`
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
bool is_root() const
|
bool is_root() const {
|
||||||
{
|
return m_parent == nullptr;
|
||||||
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()`
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
bool is_leaf() const
|
bool is_leaf() const {
|
||||||
{
|
return (!m_children);
|
||||||
CGAL_precondition(!is_null());
|
|
||||||
return (!m_data->children);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns this node's depth.
|
\brief returns this node's depth.
|
||||||
\pre `!is_null()`
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
std::uint8_t depth() const
|
std::uint8_t depth() const {
|
||||||
{
|
return m_depth;
|
||||||
CGAL_precondition (!is_null());
|
|
||||||
return m_data->depth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -329,9 +304,6 @@ public:
|
||||||
*/
|
*/
|
||||||
Local_coordinates local_coordinates() const {
|
Local_coordinates local_coordinates() const {
|
||||||
|
|
||||||
CGAL_precondition (!is_null());
|
|
||||||
// TODO: There must be a better way of doing this!
|
|
||||||
|
|
||||||
Local_coordinates result;
|
Local_coordinates result;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < Dimension::value; ++i)
|
for (std::size_t i = 0; i < Dimension::value; ++i)
|
||||||
|
|
@ -344,10 +316,8 @@ public:
|
||||||
\brief returns this node's global coordinates.
|
\brief returns this node's global coordinates.
|
||||||
\pre `!is_null()`
|
\pre `!is_null()`
|
||||||
*/
|
*/
|
||||||
Global_coordinates global_coordinates() const
|
Global_coordinates global_coordinates() const {
|
||||||
{
|
return m_global_coordinates;
|
||||||
CGAL_precondition (!is_null());
|
|
||||||
return m_data->global_coordinates;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -356,18 +326,16 @@ public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns this node's parent.
|
\brief returns this node's parent.
|
||||||
\pre `!is_null()`
|
\pre `!is_root()`
|
||||||
*/
|
*/
|
||||||
Self parent() const
|
const Self* parent() const {
|
||||||
{
|
CGAL_precondition (!is_root());
|
||||||
CGAL_precondition (!is_null());
|
return m_parent;
|
||||||
return m_data->parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns the nth child of this node.
|
\brief returns the nth child of this node.
|
||||||
|
|
||||||
\pre `!is_null()`
|
|
||||||
\pre `!is_leaf()`
|
\pre `!is_leaf()`
|
||||||
\pre `0 <= index && index < Degree::value`
|
\pre `0 <= index && index < Degree::value`
|
||||||
|
|
||||||
|
|
@ -418,13 +386,29 @@ public:
|
||||||
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) const {
|
Self& operator[](std::size_t index) {
|
||||||
|
|
||||||
CGAL_precondition (!is_null());
|
|
||||||
CGAL_precondition (!is_leaf());
|
CGAL_precondition (!is_leaf());
|
||||||
CGAL_precondition (index < Degree::value);
|
CGAL_precondition (index < Degree::value);
|
||||||
|
|
||||||
return (*m_data->children)[index];
|
return (*m_children)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief returns the nth child of this node.
|
||||||
|
|
||||||
|
\pre `!is_leaf()`
|
||||||
|
\pre `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 (index < Degree::value);
|
||||||
|
|
||||||
|
return (*m_children)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -478,9 +462,7 @@ public:
|
||||||
|
|
||||||
\return the adjacent node if it exists, a null node otherwise.
|
\return the adjacent node if it exists, a null node otherwise.
|
||||||
*/
|
*/
|
||||||
Self adjacent_node (Local_coordinates direction) const
|
const Self* adjacent_node(Local_coordinates 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
|
||||||
|
|
@ -489,8 +471,7 @@ public:
|
||||||
CGAL_precondition(direction.to_ulong() < Dimension::value * 2);
|
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];
|
||||||
|
|
@ -506,24 +487,22 @@ public:
|
||||||
|
|
||||||
// Check if this child has the opposite sign along the direction's axis
|
// Check if this child has the opposite sign along the direction's axis
|
||||||
if (local_coordinates()[dimension] != sign) {
|
if (local_coordinates()[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()[local_coordinates().to_ulong() + offset];
|
return &(*parent())[local_coordinates().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
|
||||||
Self adjacent_node_of_parent = parent().adjacent_node(direction);
|
const 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.is_null())
|
if (!adjacent_node_of_parent) 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[local_coordinates().to_ulong() - offset];
|
return &(*adjacent_node_of_parent)[local_coordinates().to_ulong() - offset];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,7 +510,21 @@ public:
|
||||||
\brief equivalent to `adjacent_node()`, with an adjacency direction
|
\brief equivalent to `adjacent_node()`, with an adjacency direction
|
||||||
rather than a bitset.
|
rather than a bitset.
|
||||||
*/
|
*/
|
||||||
Self adjacent_node(Adjacency adjacency) const {
|
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -544,27 +537,27 @@ public:
|
||||||
\brief checks whether the node is empty of points or not.
|
\brief checks whether the node is empty of points or not.
|
||||||
*/
|
*/
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return m_data->points.empty();
|
return m_points.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns the number of points of this node.
|
\brief returns the number of points of this node.
|
||||||
*/
|
*/
|
||||||
std::size_t size() const {
|
std::size_t size() const {
|
||||||
return std::size_t(std::distance(m_data->points.begin(), m_data->points.end()));
|
return std::size_t(std::distance(m_points.begin(), m_points.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns the iterator at the start of the collection of
|
\brief returns the iterator at the start of the collection of
|
||||||
points held by this node.
|
points held by this node.
|
||||||
*/
|
*/
|
||||||
const_iterator begin() const { return m_data->points.begin(); }
|
const_iterator begin() const { return m_points.begin(); }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief returns the iterator at the end of the collection of
|
\brief returns the iterator at the end of the collection of
|
||||||
points held by this node.
|
points held by this node.
|
||||||
*/
|
*/
|
||||||
const_iterator end() const { return m_data->points.end(); }
|
const_iterator end() const { return m_points.end(); }
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
@ -575,18 +568,23 @@ public:
|
||||||
/*!
|
/*!
|
||||||
* \brief compares the topology of this node to another node.
|
* \brief compares the topology of this node to another node.
|
||||||
*
|
*
|
||||||
* \todo
|
* \todo This seems out of date, the implementation I see compares for direct equality
|
||||||
*
|
*
|
||||||
* \param rhs node to compare with
|
* \param rhs node to compare with
|
||||||
* \return whether the nodes have different topology.
|
* \return whether the nodes have different topology.
|
||||||
*/
|
*/
|
||||||
bool operator==(const Self& rhs) const {
|
bool operator==(const Self& rhs) const {
|
||||||
return m_data == rhs.m_data;
|
|
||||||
|
// todo: This is a trivial implementation, maybe it can be set to =default in c++17?
|
||||||
|
return rhs.m_parent == m_parent &&
|
||||||
|
rhs.m_children == m_children &&
|
||||||
|
rhs.m_points == m_points &&
|
||||||
|
rhs.m_depth == m_depth &&
|
||||||
|
rhs.m_global_coordinates == m_global_coordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_topology_equal (const Self& a, const Self& b)
|
// todo: this does what the documentation for operator== claims to do!
|
||||||
{
|
static bool is_topology_equal(const Self& a, const Self& b) {
|
||||||
CGAL_assertion (!a.is_null() && !b.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 (a.is_leaf() != b.is_leaf())
|
if (a.is_leaf() != b.is_leaf())
|
||||||
|
|
@ -607,8 +605,7 @@ public:
|
||||||
return (a.global_coordinates() == b.global_coordinates());
|
return (a.global_coordinates() == b.global_coordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<< (std::ostream& os, const Self& node)
|
friend std::ostream& operator<<(std::ostream& os, const Self& node) {
|
||||||
{
|
|
||||||
return internal::print_orthtree_node(os, node);
|
return internal::print_orthtree_node(os, node);
|
||||||
}
|
}
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
|
||||||
|
|
@ -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(), m_next() {}
|
Traversal_iterator() : m_value(nullptr), 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 const_cast<Value&>(m_value);
|
return *m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Value m_value;
|
Value *m_value;
|
||||||
Traversal_function m_next;
|
Traversal_function m_next;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,86 +33,85 @@ namespace Orthtrees {
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node next_sibling(Node n) {
|
const Node* next_sibling(const Node* n) {
|
||||||
|
|
||||||
// Passing null returns the first node
|
// Passing null returns the first node
|
||||||
if (n.is_null())
|
if (nullptr == n)
|
||||||
return Node();
|
return nullptr;
|
||||||
|
|
||||||
// If this node has no parent, it has no siblings
|
// If this node has no parent, it has no siblings
|
||||||
if (n.parent().is_null())
|
if (n->is_root())
|
||||||
return Node();
|
return nullptr;
|
||||||
|
|
||||||
// Find out which child this is
|
// Find out which child this is
|
||||||
std::size_t index = n.local_coordinates().to_ulong();
|
std::size_t index = n->local_coordinates().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 (int(index) == degree - 1)
|
if (int(index) == degree - 1)
|
||||||
return Node();
|
return nullptr;
|
||||||
|
|
||||||
// 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>
|
||||||
Node next_sibling_up(Node n) {
|
const Node* next_sibling_up(const Node* n) {
|
||||||
|
|
||||||
if (n.is_null())
|
if (!n || n->is_root()) return nullptr;
|
||||||
return Node();
|
|
||||||
|
|
||||||
Node up = n.parent();
|
auto 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();
|
if (up->is_root()) return nullptr;
|
||||||
|
|
||||||
|
up = up->parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Node();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node deepest_first_child(Node n) {
|
const Node* deepest_first_child(const Node* n) {
|
||||||
|
|
||||||
if (n.is_null())
|
if (!n)
|
||||||
return Node();
|
return nullptr;
|
||||||
|
|
||||||
// Find the deepest child on the left
|
// Find the deepest child on the left
|
||||||
Node first = n;
|
auto first = n;
|
||||||
while (!first.is_leaf())
|
while (!first->is_leaf())
|
||||||
first = first[0];
|
first = &(*first)[0];
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node first_child_at_depth(Node n, std::size_t depth) {
|
const Node& first_child_at_depth(const Node* n, std::size_t depth) {
|
||||||
|
|
||||||
if (n.is_null())
|
if (!n)
|
||||||
return Node();
|
return nullptr;
|
||||||
|
|
||||||
std::stack<Node> todo;
|
std::stack<const Node*> todo;
|
||||||
todo.push(n);
|
todo.push(n);
|
||||||
|
|
||||||
if (n.depth() == depth)
|
if (n->depth() == depth)
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
while (!todo.empty())
|
while (!todo.empty()) {
|
||||||
{
|
const Node* node = todo.top();
|
||||||
Node node = todo.top();
|
|
||||||
todo.pop();
|
todo.pop();
|
||||||
|
|
||||||
if (node.depth() == depth)
|
if (node->depth() == depth)
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
if (!node.is_leaf())
|
if (!node->is_leaf())
|
||||||
for (int i = 0; i < Node::Degree::value; ++i)
|
for (int i = 0; i < Node::Degree::value; ++i)
|
||||||
todo.push(node[std::size_t(Node::Degree::value - 1 - i)]);
|
todo.push(&((*node)[std::size_t(Node::Degree::value - 1 - i)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Node();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
@ -128,25 +127,30 @@ Node first_child_at_depth(Node n, std::size_t depth) {
|
||||||
struct Preorder_traversal {
|
struct Preorder_traversal {
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node first(Node root) const {
|
const Node* first(const Node* root) const {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node next(Node n) const {
|
const Node* next(const Node* n) const {
|
||||||
|
|
||||||
if (n.is_leaf()) {
|
if (n->is_leaf()) {
|
||||||
|
|
||||||
Node next = next_sibling(n);
|
auto 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];
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -161,18 +165,18 @@ struct Preorder_traversal {
|
||||||
struct Postorder_traversal {
|
struct Postorder_traversal {
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node first(Node root) const {
|
const Node* first(const Node* root) const {
|
||||||
|
|
||||||
return deepest_first_child(root);
|
return deepest_first_child(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node next(Node n) const {
|
const Node* next(const Node* n) const {
|
||||||
|
|
||||||
Node next = deepest_first_child(next_sibling(n));
|
auto next = deepest_first_child(next_sibling(n));
|
||||||
|
|
||||||
if (next.is_null())
|
if (!next)
|
||||||
next = n.parent();
|
next = n->parent();
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
@ -189,17 +193,17 @@ struct Postorder_traversal {
|
||||||
struct Leaves_traversal {
|
struct Leaves_traversal {
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node first(Node root) const {
|
const Node* first(const Node* root) const {
|
||||||
|
|
||||||
return deepest_first_child(root);
|
return deepest_first_child(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node next(Node n) const {
|
const Node* next(const Node* n) const {
|
||||||
|
|
||||||
Node next = deepest_first_child(next_sibling(n));
|
auto next = deepest_first_child(next_sibling(n));
|
||||||
|
|
||||||
if (next.is_null())
|
if (!next)
|
||||||
next = deepest_first_child(next_sibling_up(n));
|
next = deepest_first_child(next_sibling_up(n));
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|
@ -229,26 +233,25 @@ public:
|
||||||
Level_traversal(std::size_t depth) : depth(depth) {}
|
Level_traversal(std::size_t depth) : depth(depth) {}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node first(Node root) const {
|
const Node* first(const Node* root) const {
|
||||||
return first_child_at_depth(root, depth);
|
return first_child_at_depth(root, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
Node next(Node n) const {
|
const Node* next(const Node* n) const {
|
||||||
|
// fixme: leftover from debugging?
|
||||||
std::cerr << depth << " ";
|
std::cerr << depth << " ";
|
||||||
Node next = next_sibling(n);
|
const Node* next = next_sibling(n);
|
||||||
|
|
||||||
if (next.is_null())
|
if (!next) {
|
||||||
{
|
const Node* up = n;
|
||||||
Node up = n;
|
do {
|
||||||
do
|
|
||||||
{
|
|
||||||
up = next_sibling_up(up);
|
up = next_sibling_up(up);
|
||||||
if (up.is_null())
|
if (!up)
|
||||||
return Node();
|
return nullptr;
|
||||||
|
|
||||||
next = first_child_at_depth(up, depth);
|
next = first_child_at_depth(up, depth);
|
||||||
}
|
} while (!next);
|
||||||
while (next.is_null());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|
|
||||||
|
|
@ -42,33 +42,36 @@ int main(void) {
|
||||||
std::cout << octree << std::endl;
|
std::cout << octree << std::endl;
|
||||||
|
|
||||||
// Root node should have no siblings
|
// Root node should have no siblings
|
||||||
assert(octree.root().adjacent_node(0).is_null());
|
assert(octree.root().adjacent_node(0) == nullptr);
|
||||||
assert(octree.root().adjacent_node(1).is_null());
|
assert(octree.root().adjacent_node(1) == nullptr);
|
||||||
assert(octree.root().adjacent_node(2).is_null());
|
assert(octree.root().adjacent_node(2) == nullptr);
|
||||||
assert(octree.root().adjacent_node(3).is_null());
|
assert(octree.root().adjacent_node(3) == nullptr);
|
||||||
assert(octree.root().adjacent_node(4).is_null());
|
assert(octree.root().adjacent_node(4) == nullptr);
|
||||||
assert(octree.root().adjacent_node(5).is_null());
|
assert(octree.root().adjacent_node(5) == nullptr);
|
||||||
|
|
||||||
// Left Top Front node should have siblings to the Right, Down, and Back
|
// Left Top Front node should have siblings to the Right, Down, and Back
|
||||||
auto left_top_back = octree.root()[Traits::LEFT_TOP_BACK];
|
auto left_top_back = octree.root()[Traits::LEFT_TOP_BACK];
|
||||||
|
|
||||||
assert(octree.root()[Traits::RIGHT_TOP_BACK] == left_top_back.adjacent_node(Traits::RIGHT));
|
assert(&octree.root()[Traits::RIGHT_TOP_BACK] == left_top_back.adjacent_node(Traits::RIGHT));
|
||||||
assert(octree.root()[Traits::LEFT_BOTTOM_BACK] == left_top_back.adjacent_node(Traits::DOWN));
|
assert(&octree.root()[Traits::LEFT_BOTTOM_BACK] == left_top_back.adjacent_node(Traits::DOWN));
|
||||||
assert(octree.root()[Traits::LEFT_TOP_FRONT] == left_top_back.adjacent_node(Traits::FRONT));
|
assert(&octree.root()[Traits::LEFT_TOP_FRONT] == left_top_back.adjacent_node(Traits::FRONT));
|
||||||
assert(left_top_back.adjacent_node(Traits::LEFT).is_null());
|
assert(left_top_back.adjacent_node(Traits::LEFT) == nullptr);
|
||||||
assert(left_top_back.adjacent_node(Traits::UP).is_null());
|
assert(left_top_back.adjacent_node(Traits::UP) == nullptr);
|
||||||
assert(left_top_back.adjacent_node(Traits::BACK).is_null());
|
assert(left_top_back.adjacent_node(Traits::BACK) == nullptr);
|
||||||
|
|
||||||
std::cout << octree.root()[Traits::LEFT_BOTTOM_BACK] << std::endl;
|
std::cout << octree.root()[Traits::LEFT_BOTTOM_BACK] << std::endl;
|
||||||
|
|
||||||
auto right_top_back_of_left_bottom_back = octree.root()[Traits::LEFT_BOTTOM_BACK][Traits::RIGHT_TOP_BACK];
|
auto right_top_back_of_left_bottom_back = octree.root()[Traits::LEFT_BOTTOM_BACK][Traits::RIGHT_TOP_BACK];
|
||||||
assert(octree.root()[Traits::LEFT_BOTTOM_BACK][Traits::LEFT_TOP_BACK] == right_top_back_of_left_bottom_back.adjacent_node(Traits::LEFT));
|
assert(&octree.root()[Traits::LEFT_BOTTOM_BACK][Traits::LEFT_TOP_BACK] ==
|
||||||
assert(octree.root()[Traits::RIGHT_BOTTOM_BACK] == right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT));
|
right_top_back_of_left_bottom_back.adjacent_node(Traits::LEFT));
|
||||||
assert(!right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT).is_null());
|
assert(&octree.root()[Traits::RIGHT_BOTTOM_BACK] == right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT));
|
||||||
assert(!right_top_back_of_left_bottom_back.adjacent_node(Traits::UP).is_null());
|
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT) != nullptr);
|
||||||
assert(!right_top_back_of_left_bottom_back.adjacent_node(Traits::DOWN).is_null());
|
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::UP) != nullptr);
|
||||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::BACK).is_null());
|
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::DOWN) != nullptr);
|
||||||
assert(!right_top_back_of_left_bottom_back.adjacent_node(Traits::FRONT).is_null());
|
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::FRONT) != nullptr);
|
||||||
|
|
||||||
|
// A node at the back of the tree should have no neighbor to its back
|
||||||
|
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::BACK) == nullptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,10 @@ std::size_t count_jumps(Octree &octree) {
|
||||||
|
|
||||||
auto adjacent_node = node.adjacent_node(direction);
|
auto adjacent_node = node.adjacent_node(direction);
|
||||||
|
|
||||||
if (adjacent_node.is_null())
|
if (adjacent_node == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((node.depth() - adjacent_node.depth()) > 1)
|
if ((node.depth() - adjacent_node->depth()) > 1)
|
||||||
jumps++;
|
jumps++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,14 @@ int main(void) {
|
||||||
auto query = Point{1, 1, 1};
|
auto query = Point{1, 1, 1};
|
||||||
|
|
||||||
// Get a list of nodes intersected
|
// Get a list of nodes intersected
|
||||||
std::vector<Octree::Node> nodes{};
|
std::vector<const Octree::Node *> nodes{};
|
||||||
octree.intersected_nodes(query, std::back_inserter(nodes));
|
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||||
|
|
||||||
// A point should only intersect one node
|
// A point should only intersect one node
|
||||||
assert(1 == nodes.size());
|
assert(1 == nodes.size());
|
||||||
|
|
||||||
// That node should be the node leaf that contains the point
|
// That node should be the node leaf that contains the point
|
||||||
assert(octree.locate(Point(1, 1, 1)) == nodes[0]);
|
assert(octree.locate(Point(1, 1, 1)) == *nodes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersection with a sphere
|
// Intersection with a sphere
|
||||||
|
|
@ -63,15 +63,15 @@ int main(void) {
|
||||||
auto query = Kernel::Sphere_3(Point{1, 0.5, 1}, 1.0);
|
auto query = Kernel::Sphere_3(Point{1, 0.5, 1}, 1.0);
|
||||||
|
|
||||||
// Get a list of nodes intersected
|
// Get a list of nodes intersected
|
||||||
std::vector<Octree::Node> nodes{};
|
std::vector<const Octree::Node *> nodes{};
|
||||||
octree.intersected_nodes(query, std::back_inserter(nodes));
|
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||||
|
|
||||||
// Check the results
|
// Check the results
|
||||||
assert(4 == nodes.size());
|
assert(4 == nodes.size());
|
||||||
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == nodes[0]);
|
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == *nodes[0]);
|
||||||
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == nodes[1]);
|
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[1]);
|
||||||
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == nodes[2]);
|
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == *nodes[2]);
|
||||||
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == nodes[3]);
|
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersection with a ray
|
// Intersection with a ray
|
||||||
|
|
@ -81,19 +81,19 @@ int main(void) {
|
||||||
auto query = Kernel::Ray_3(Point{1, 1, 1}, Point{0, 0, 0});
|
auto query = Kernel::Ray_3(Point{1, 1, 1}, Point{0, 0, 0});
|
||||||
|
|
||||||
// Get a list of nodes intersected
|
// Get a list of nodes intersected
|
||||||
std::vector<Octree::Node> nodes{};
|
std::vector<const Octree::Node *> nodes{};
|
||||||
octree.intersected_nodes(query, std::back_inserter(nodes));
|
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||||
|
|
||||||
// Check the results
|
// Check the results
|
||||||
assert(8 == nodes.size());
|
assert(8 == nodes.size());
|
||||||
assert(octree[Octree::Traits::LEFT_BOTTOM_BACK] == nodes[0]);
|
assert(octree[Octree::Traits::LEFT_BOTTOM_BACK] == *nodes[0]);
|
||||||
assert(octree[Octree::Traits::RIGHT_BOTTOM_BACK][Octree::Traits::LEFT_TOP_FRONT] == nodes[1]);
|
assert(octree[Octree::Traits::RIGHT_BOTTOM_BACK][Octree::Traits::LEFT_TOP_FRONT] == *nodes[1]);
|
||||||
assert(octree[Octree::Traits::LEFT_TOP_BACK] == nodes[2]);
|
assert(octree[Octree::Traits::LEFT_TOP_BACK] == *nodes[2]);
|
||||||
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == nodes[3]);
|
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == *nodes[3]);
|
||||||
assert(octree[Octree::Traits::LEFT_BOTTOM_FRONT] == nodes[4]);
|
assert(octree[Octree::Traits::LEFT_BOTTOM_FRONT] == *nodes[4]);
|
||||||
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == nodes[5]);
|
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[5]);
|
||||||
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == nodes[6]);
|
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == *nodes[6]);
|
||||||
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == nodes[7]);
|
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,6 @@ void naive_vs_octree(std::size_t dataset_size) {
|
||||||
octree.refine(10, 20);
|
octree.refine(10, 20);
|
||||||
auto octree_start_time = high_resolution_clock::now();
|
auto octree_start_time = high_resolution_clock::now();
|
||||||
{
|
{
|
||||||
// TODO: Write a nearest-neighbor implementation and use it here
|
|
||||||
std::vector<Point> k_neighbors;
|
std::vector<Point> k_neighbors;
|
||||||
octree.nearest_neighbors(random_point, 1, std::back_inserter(k_neighbors));
|
octree.nearest_neighbors(random_point, 1, std::back_inserter(k_neighbors));
|
||||||
octree_nearest = *k_neighbors.begin();
|
octree_nearest = *k_neighbors.begin();
|
||||||
|
|
@ -143,6 +142,7 @@ void kdtree_vs_octree(std::size_t dataset_size, std::size_t K) {
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
|
naive_vs_octree(21);
|
||||||
naive_vs_octree(500);
|
naive_vs_octree(500);
|
||||||
naive_vs_octree(1000);
|
naive_vs_octree(1000);
|
||||||
naive_vs_octree(10000);
|
naive_vs_octree(10000);
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,11 @@ void test_1_point() {
|
||||||
octree.refine(10, 1);
|
octree.refine(10, 1);
|
||||||
|
|
||||||
// Check that the topology matches
|
// Check that the topology matches
|
||||||
Node single_node = CGAL::Orthtrees::Node_access::create_node(Node(), 0);
|
Node single_node = CGAL::Orthtrees::Node_access::create_node(static_cast<Node *>(nullptr), 0);
|
||||||
CGAL::Orthtrees::Node_access::points(single_node)
|
CGAL::Orthtrees::Node_access::points(single_node)
|
||||||
= CGAL::Orthtrees::Node_access::points(octree.root());
|
= CGAL::Orthtrees::Node_access::points(octree.root());
|
||||||
assert(Node::is_topology_equal(single_node, octree.root()));
|
assert(Node::is_topology_equal(single_node, octree.root()));
|
||||||
assert(0 == octree.depth());
|
assert(0 == octree.depth());
|
||||||
CGAL::Orthtrees::Node_access::free(single_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_2_points() {
|
void test_2_points() {
|
||||||
|
|
@ -45,12 +44,10 @@ void test_2_points() {
|
||||||
octree.refine(10, 1);
|
octree.refine(10, 1);
|
||||||
|
|
||||||
// The octree should have been split once
|
// The octree should have been split once
|
||||||
Node other = CGAL::Orthtrees::Node_access::create_node(Node(), 0);
|
Node other = CGAL::Orthtrees::Node_access::create_node(static_cast<Node *>(nullptr), 0);
|
||||||
CGAL::Orthtrees::Node_access::split(other);
|
CGAL::Orthtrees::Node_access::split(other);
|
||||||
assert(Node::is_topology_equal(other, octree.root()));
|
assert(Node::is_topology_equal(other, octree.root()));
|
||||||
assert(1 == octree.depth());
|
assert(1 == octree.depth());
|
||||||
CGAL::Orthtrees::Node_access::free(other);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_4_points() {
|
void test_4_points() {
|
||||||
|
|
@ -66,13 +63,12 @@ void test_4_points() {
|
||||||
octree.refine(10, 1);
|
octree.refine(10, 1);
|
||||||
|
|
||||||
// The octree should have been split once on the first level, and twice on the second
|
// The octree should have been split once on the first level, and twice on the second
|
||||||
Node other = CGAL::Orthtrees::Node_access::create_node(Node(), 0);
|
Node other = CGAL::Orthtrees::Node_access::create_node(static_cast<Node *>(nullptr), 0);
|
||||||
CGAL::Orthtrees::Node_access::split(other);
|
CGAL::Orthtrees::Node_access::split(other);
|
||||||
CGAL::Orthtrees::Node_access::split(other[3]);
|
CGAL::Orthtrees::Node_access::split(other[3]);
|
||||||
CGAL::Orthtrees::Node_access::split(other[7]);
|
CGAL::Orthtrees::Node_access::split(other[7]);
|
||||||
assert(Node::is_topology_equal(other, octree.root()));
|
assert(Node::is_topology_equal(other, octree.root()));
|
||||||
assert(2 == octree.depth());
|
assert(2 == octree.depth());
|
||||||
CGAL::Orthtrees::Node_access::free(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue