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,11 +35,13 @@ namespace CGAL {
|
|||
\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`
|
||||
*/
|
||||
template <typename GeomTraits, typename PointRange,
|
||||
typename PointMap = Identity_property_map
|
||||
<typename std::iterator_traits<typename PointRange::iterator>::value_type> >
|
||||
template <
|
||||
typename GeomTraits,
|
||||
typename PointRange,
|
||||
typename PointMap = Identity_property_map<typename std::iterator_traits<typename PointRange::iterator>::value_type>
|
||||
>
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
class Octree;
|
||||
class Octree;
|
||||
#else
|
||||
using Octree = Orthtree<Orthtree_traits_3<GeomTraits>, PointRange, PointMap>;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@
|
|||
#include <vector>
|
||||
#include <math.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace CGAL
|
||||
{
|
||||
|
||||
/*!
|
||||
\ingroup PkgOrthtreeClasses
|
||||
|
|
@ -63,8 +64,8 @@ namespace CGAL {
|
|||
\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 `Traits_::Point_d`
|
||||
*/
|
||||
template<typename Traits_, typename PointRange_,
|
||||
typename PointMap_ = Identity_property_map<typename Traits_::Point_d> >
|
||||
template <typename Traits_, typename PointRange_,
|
||||
typename PointMap_ = Identity_property_map<typename Traits_::Point_d> >
|
||||
class Orthtree
|
||||
{
|
||||
|
||||
|
|
@ -88,9 +89,9 @@ public:
|
|||
/// \cond SKIP_IN_MANUAL
|
||||
typedef typename Traits::Array Array; ///< Array type.
|
||||
typedef typename Traits::Construct_point_d_from_array
|
||||
Construct_point_d_from_array;
|
||||
Construct_point_d_from_array;
|
||||
typedef typename Traits::Construct_bbox_d
|
||||
Construct_bbox_d;
|
||||
Construct_bbox_d;
|
||||
/// \endcond
|
||||
/// @}
|
||||
|
||||
|
|
@ -105,7 +106,7 @@ public:
|
|||
/*!
|
||||
* \brief Degree of the tree (number of children of non-leaf nodes).
|
||||
*/
|
||||
typedef Dimension_tag<(2 << (Dimension::value-1))> Degree;
|
||||
typedef Dimension_tag<(2 << (Dimension::value - 1))> Degree;
|
||||
|
||||
/*!
|
||||
* \brief The Sub-tree / Orthant type.
|
||||
|
|
@ -123,7 +124,7 @@ public:
|
|||
#ifdef DOXYGEN_RUNNING
|
||||
typedef unspecified_type Node_range;
|
||||
#else
|
||||
typedef boost::iterator_range<Traversal_iterator<Node> > Node_range;
|
||||
typedef boost::iterator_range<Traversal_iterator<const Node>> Node_range;
|
||||
#endif
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
|
@ -131,7 +132,7 @@ public:
|
|||
/*!
|
||||
* \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
|
||||
|
||||
|
|
@ -193,48 +194,48 @@ public:
|
|||
PointMap point_map = PointMap(),
|
||||
const FT enlarge_ratio = 1.2,
|
||||
Traits traits = Traits())
|
||||
: m_traits (traits)
|
||||
, m_range (point_range)
|
||||
, m_point_map (point_map)
|
||||
, m_root(Node(), 0)
|
||||
: m_traits(traits)
|
||||
, m_range(point_range)
|
||||
, m_point_map(point_map)
|
||||
, m_root() // todo: can this be default-constructed?
|
||||
{
|
||||
Array bbox_min;
|
||||
Array bbox_max;
|
||||
|
||||
// init bbox with first values found
|
||||
{
|
||||
const Point& p = get (m_point_map, *(point_range.begin()));
|
||||
const Point& p = get(m_point_map, *(point_range.begin()));
|
||||
std::size_t i = 0;
|
||||
for (const FT& x : cartesian_range(p))
|
||||
for (const FT& x: cartesian_range(p))
|
||||
{
|
||||
bbox_min[i] = x;
|
||||
bbox_max[i] = x;
|
||||
++ i;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
for (const Range_type& r : point_range)
|
||||
for (const Range_type& r: point_range)
|
||||
{
|
||||
const Point& p = get (m_point_map, r);
|
||||
const Point& p = get(m_point_map, r);
|
||||
std::size_t i = 0;
|
||||
for (const FT& x : cartesian_range(p))
|
||||
for (const FT& x: cartesian_range(p))
|
||||
{
|
||||
bbox_min[i] = (std::min)(x, bbox_min[i]);
|
||||
bbox_max[i] = (std::max)(x, bbox_max[i]);
|
||||
++ i;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
Array bbox_centroid;
|
||||
FT max_length = FT(0);
|
||||
for (std::size_t i = 0 ; i < Dimension::value; ++ i)
|
||||
for (std::size_t i = 0; i < Dimension::value; ++i)
|
||||
{
|
||||
bbox_centroid[i] = (bbox_min[i] + bbox_max[i]) / FT(2);
|
||||
max_length = (std::max)(max_length, bbox_max[i] - bbox_min[i]);
|
||||
}
|
||||
max_length *= enlarge_ratio / FT(2);
|
||||
|
||||
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_max[i] = bbox_centroid[i] + max_length;
|
||||
|
|
@ -254,47 +255,31 @@ public:
|
|||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
// copy constructor
|
||||
Orthtree (const Orthtree& other)
|
||||
: m_traits (other.m_traits)
|
||||
, m_range (other.m_range)
|
||||
, m_point_map (other.m_point_map)
|
||||
, m_root (other.m_root.deep_copy())
|
||||
, m_bbox_min (other.m_bbox_min)
|
||||
, m_side_per_depth(other.m_side_per_depth)
|
||||
{ }
|
||||
Orthtree(const Orthtree& other)
|
||||
: m_traits(other.m_traits)
|
||||
, m_range(other.m_range)
|
||||
, m_point_map(other.m_point_map)
|
||||
, m_root(other.m_root.deep_copy())
|
||||
, m_bbox_min(other.m_bbox_min)
|
||||
, m_side_per_depth(other.m_side_per_depth) {}
|
||||
|
||||
// move constructor
|
||||
Orthtree (Orthtree&& other)
|
||||
: m_traits (other.m_traits)
|
||||
, m_range (other.m_range)
|
||||
, m_point_map (other.m_point_map)
|
||||
, m_root (other.m_root)
|
||||
, m_bbox_min (other.m_bbox_min)
|
||||
, m_side_per_depth(other.m_side_per_depth)
|
||||
{
|
||||
other.m_root = Node(Node(), 0);
|
||||
Orthtree(Orthtree&& other)
|
||||
: m_traits(other.m_traits)
|
||||
, m_range(other.m_range)
|
||||
, m_point_map(other.m_point_map)
|
||||
, m_root(other.m_root)
|
||||
, m_bbox_min(other.m_bbox_min)
|
||||
, m_side_per_depth(other.m_side_per_depth) {
|
||||
other.m_root = Node{};
|
||||
}
|
||||
|
||||
// Non-necessary but just to be clear on the rule of 5:
|
||||
|
||||
// assignment operators deleted (PointRange is a ref)
|
||||
Orthtree& operator= (const 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();
|
||||
}
|
||||
}
|
||||
Orthtree& operator=(const Orthtree& other) = delete;
|
||||
|
||||
Orthtree& operator=(Orthtree&& other) = delete;
|
||||
|
||||
// move constructor
|
||||
/// \endcond
|
||||
|
|
@ -320,52 +305,39 @@ public:
|
|||
void refine(const Split_predicate& split_predicate) {
|
||||
|
||||
// If the tree has already been refined, reset it
|
||||
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();
|
||||
}
|
||||
if (!m_root.is_leaf())
|
||||
m_root.unsplit();
|
||||
}
|
||||
|
||||
// Reset the side length map, too
|
||||
m_side_per_depth.resize(1);
|
||||
|
||||
// Initialize a queue of nodes that need to be refined
|
||||
std::queue<Node> todo;
|
||||
todo.push(m_root);
|
||||
std::queue<Node *> todo;
|
||||
todo.push(&m_root);
|
||||
|
||||
// Process items in the queue until it's consumed fully
|
||||
while (!todo.empty()) {
|
||||
|
||||
// Get the next element
|
||||
Node current = todo.front();
|
||||
auto current = todo.front();
|
||||
todo.pop();
|
||||
|
||||
// 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
|
||||
if (current.depth() == depth()) {
|
||||
if (current->depth() == depth()) {
|
||||
|
||||
// Update the side length map
|
||||
m_side_per_depth.push_back(*(m_side_per_depth.end() - 1) / 2);
|
||||
}
|
||||
|
||||
// Split the node, redistributing its points to its children
|
||||
split(current);
|
||||
split((*current));
|
||||
|
||||
// Process each of its children
|
||||
for (int i = 0; i < Degree::value; ++i)
|
||||
todo.push(current[i]);
|
||||
todo.push(&(*current)[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -401,52 +373,52 @@ public:
|
|||
void grade() {
|
||||
|
||||
// Collect all the leaf nodes
|
||||
std::queue<Node> leaf_nodes;
|
||||
for (Node leaf : traverse(Orthtrees::Leaves_traversal())) {
|
||||
std::queue<Node *> leaf_nodes;
|
||||
for (const Node &leaf : traverse(Orthtrees::Leaves_traversal())) {
|
||||
// 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
|
||||
while (!leaf_nodes.empty()) {
|
||||
|
||||
// Get the next node
|
||||
Node node = leaf_nodes.front();
|
||||
Node *node = leaf_nodes.front();
|
||||
leaf_nodes.pop();
|
||||
|
||||
// Skip this node if it isn't a leaf anymore
|
||||
if (!node.is_leaf())
|
||||
if (!node->is_leaf())
|
||||
continue;
|
||||
|
||||
// Iterate over each of the neighbors
|
||||
for (int direction = 0; direction < 6; ++direction) {
|
||||
|
||||
// Get the neighbor
|
||||
Node neighbor = node.adjacent_node(direction);
|
||||
auto *neighbor = node->adjacent_node(direction);
|
||||
|
||||
// If it doesn't exist, skip it
|
||||
if (neighbor.is_null())
|
||||
if (!neighbor)
|
||||
continue;
|
||||
|
||||
// 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
|
||||
if (neighbor.parent() == node.parent())
|
||||
if (neighbor->parent() == node->parent())
|
||||
continue;
|
||||
|
||||
// If it's already been split, skip it
|
||||
if (!neighbor.is_leaf())
|
||||
if (!neighbor->is_leaf())
|
||||
continue;
|
||||
|
||||
// Check if the neighbor breaks our grading rule
|
||||
// TODO: could the rule be parametrized?
|
||||
if ((node.depth() - neighbor.depth()) > 1) {
|
||||
if ((node->depth() - neighbor->depth()) > 1) {
|
||||
|
||||
// Split the neighbor
|
||||
split(neighbor);
|
||||
split(*neighbor);
|
||||
|
||||
// Add newly created children to the queue
|
||||
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
|
||||
|
|
@ -472,9 +457,9 @@ public:
|
|||
\sa `Node::operator[]()`
|
||||
|
||||
\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).
|
||||
|
|
@ -497,13 +482,13 @@ public:
|
|||
template<typename Traversal>
|
||||
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
|
||||
= [&](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),
|
||||
Traversal_iterator<Node>());
|
||||
return boost::make_iterator_range(Traversal_iterator<const Node>(first, next),
|
||||
Traversal_iterator<const Node>());
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -547,19 +532,19 @@ public:
|
|||
\param point query 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
|
||||
CGAL_precondition (CGAL::do_intersect(point, bbox(m_root)));
|
||||
|
||||
// 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
|
||||
while (!node_for_point.is_leaf()) {
|
||||
while (!node_for_point->is_leaf()) {
|
||||
|
||||
// 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
|
||||
typename Node::Local_coordinates index;
|
||||
|
|
@ -568,11 +553,11 @@ public:
|
|||
index[dimension ++] = (get<0>(r) < get<1>(r));
|
||||
|
||||
// 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 node_for_point;
|
||||
return *node_for_point;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -582,15 +567,15 @@ public:
|
|||
`query`.
|
||||
|
||||
\tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects.
|
||||
\param query a query point.
|
||||
\param k the number of neighbors.
|
||||
\param output the output iterator.
|
||||
\param query query point.
|
||||
\param k number of neighbors.
|
||||
\param output output iterator.
|
||||
*/
|
||||
template<typename OutputIterator>
|
||||
OutputIterator nearest_neighbors (const Point& query,
|
||||
std::size_t k,
|
||||
OutputIterator output) const {
|
||||
Sphere query_sphere (query, (std::numeric_limits<FT>::max)());
|
||||
template <typename OutputIterator>
|
||||
OutputIterator nearest_neighbors(const Point& query,
|
||||
std::size_t k,
|
||||
OutputIterator output) const {
|
||||
Sphere query_sphere(query, (std::numeric_limits<FT>::max)());
|
||||
return nearest_k_neighbors_in_radius(query_sphere, k, output);
|
||||
}
|
||||
|
||||
|
|
@ -604,8 +589,8 @@ public:
|
|||
\param query query sphere.
|
||||
\param output output iterator.
|
||||
*/
|
||||
template<typename OutputIterator>
|
||||
OutputIterator nearest_neighbors (const Sphere& query, OutputIterator output) const {
|
||||
template <typename OutputIterator>
|
||||
OutputIterator nearest_neighbors(const Sphere& query, OutputIterator output) const {
|
||||
Sphere query_sphere = query;
|
||||
return nearest_k_neighbors_in_radius(query_sphere,
|
||||
(std::numeric_limits<std::size_t>::max)(), output);
|
||||
|
|
@ -625,7 +610,7 @@ public:
|
|||
\param output output iterator.
|
||||
*/
|
||||
template<typename Query, typename OutputIterator>
|
||||
OutputIterator intersected_nodes (const Query& query, OutputIterator output) const {
|
||||
OutputIterator intersected_nodes(const Query& query, OutputIterator output) const {
|
||||
return intersected_nodes_recursive(query, root(), output);
|
||||
}
|
||||
|
||||
|
|
@ -666,7 +651,7 @@ public:
|
|||
|
||||
// TODO: Document this
|
||||
// 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
|
||||
FT size = m_side_per_depth[node.depth()];
|
||||
|
|
@ -677,7 +662,7 @@ public:
|
|||
for (const FT& f : cartesian_range(m_bbox_min))
|
||||
{
|
||||
bary[i] = FT(node.global_coordinates()[i]) * size + size / FT(2) + f;
|
||||
++ i;
|
||||
++i;
|
||||
}
|
||||
|
||||
// Convert that location into a point
|
||||
|
|
@ -703,11 +688,12 @@ private: // functions :
|
|||
// Split the point collection around the center point on this dimension
|
||||
Range_iterator split_point = std::partition
|
||||
(begin, end,
|
||||
[&](const Range_type &a) -> bool {
|
||||
// This should be done with cartesian iterator but it seems
|
||||
// complicated to do efficiently
|
||||
[&](const Range_type& a) -> bool
|
||||
{
|
||||
// This should be done with cartesian iterator but it seems
|
||||
// complicated to do efficiently
|
||||
return (get(m_point_map, a)[int(dimension)] < center[int(dimension)]);
|
||||
});
|
||||
});
|
||||
|
||||
// Further subdivide the first side of the split
|
||||
std::bitset<Dimension::value> coord_left = coord;
|
||||
|
|
@ -721,7 +707,7 @@ private: // functions :
|
|||
|
||||
}
|
||||
|
||||
void split(Node& node) {
|
||||
void split(Node &node) {
|
||||
|
||||
// Make sure the node hasn't already been split
|
||||
CGAL_precondition (node.is_leaf());
|
||||
|
|
@ -755,18 +741,19 @@ private: // functions :
|
|||
Point point;
|
||||
FT distance;
|
||||
};
|
||||
struct Node_index_with_distance {
|
||||
|
||||
struct Node_index_with_distance
|
||||
{
|
||||
typename Node::Local_coordinates index;
|
||||
FT distance;
|
||||
|
||||
Node_index_with_distance (const typename Node::Local_coordinates& index,
|
||||
const FT& distance)
|
||||
: index(index), distance(distance)
|
||||
{ }
|
||||
Node_index_with_distance(const typename Node::Local_coordinates& index,
|
||||
const FT& distance)
|
||||
: index(index), distance(distance) {}
|
||||
};
|
||||
|
||||
void nearest_k_neighbors_recursive(Sphere& search_bounds, const Node &node,
|
||||
std::vector<Point_with_distance> &results, FT epsilon = 0) const {
|
||||
void nearest_k_neighbors_recursive(Sphere &search_bounds, const Node& node,
|
||||
std::vector<Point_with_distance>& results, FT epsilon = 0) const {
|
||||
|
||||
// Check whether the node has children
|
||||
if (node.is_leaf()) {
|
||||
|
|
@ -820,7 +807,7 @@ private: // functions :
|
|||
|
||||
// Fill the list with child nodes
|
||||
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
|
||||
children_with_distances.emplace_back(typename Node::Local_coordinates(index),
|
||||
|
|
@ -834,7 +821,7 @@ private: // functions :
|
|||
|
||||
// Loop over the children
|
||||
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
|
||||
if (do_intersect(child_node, search_bounds)) {
|
||||
|
|
@ -853,9 +840,9 @@ private: // functions :
|
|||
// Check if the current node intersects with the query
|
||||
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()) {
|
||||
*output++ = node;
|
||||
*output++ = &node;
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
@ -884,9 +871,9 @@ private: // functions :
|
|||
\param k the number of points to find
|
||||
\param output the output iterator to add the found points to (in order of increasing distance)
|
||||
*/
|
||||
template<typename OutputIterator>
|
||||
template <typename OutputIterator>
|
||||
OutputIterator nearest_k_neighbors_in_radius
|
||||
(Sphere& query_sphere,
|
||||
(Sphere &query_sphere,
|
||||
std::size_t k, OutputIterator output) const {
|
||||
|
||||
// Create an empty list of points
|
||||
|
|
@ -907,18 +894,16 @@ private: // functions :
|
|||
public:
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
void dump_to_polylines (std::ostream& os) const
|
||||
{
|
||||
for (const Node& n : traverse<Orthtrees::Preorder_traversal>())
|
||||
void dump_to_polylines(std::ostream& os) const {
|
||||
for (const Node& n: traverse<Orthtrees::Preorder_traversal>())
|
||||
if (n.is_leaf())
|
||||
{
|
||||
Bbox box = bbox(n);
|
||||
dump_box_to_polylines (box, os);
|
||||
dump_box_to_polylines(box, os);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
os << "5 "
|
||||
<< box.xmin() << " " << box.ymin() << " 0 "
|
||||
|
|
@ -927,8 +912,8 @@ public:
|
|||
<< box.xmax() << " " << box.ymin() << " 0 "
|
||||
<< 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
|
||||
os << "5 "
|
||||
<< box.xmin() << " " << box.ymin() << " " << box.zmin() << " "
|
||||
|
|
@ -960,12 +945,12 @@ public:
|
|||
<< 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
|
||||
auto nodes = orthtree.traverse(Orthtrees::Preorder_traversal());
|
||||
// Iterate over the range
|
||||
for (auto &n : nodes) {
|
||||
for (auto& n: nodes)
|
||||
{
|
||||
// Show the depth
|
||||
for (int i = 0; i < n.depth(); ++i)
|
||||
os << ". ";
|
||||
|
|
|
|||
|
|
@ -27,42 +27,20 @@
|
|||
namespace CGAL {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace Orthtrees
|
||||
{
|
||||
namespace Orthtrees {
|
||||
|
||||
// Non-documented, or testing purpose only
|
||||
struct Node_access
|
||||
{
|
||||
struct Node_access {
|
||||
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);
|
||||
}
|
||||
|
||||
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>
|
||||
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();
|
||||
}
|
||||
}
|
||||
static void split(Node& node) { return node.split(); }
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -79,9 +57,8 @@ struct Node_access
|
|||
|
||||
\cgalModels `ConstRange`
|
||||
*/
|
||||
template<typename Traits, typename PointRange, typename PointMap>
|
||||
class Orthtree<Traits, PointRange, PointMap>::Node
|
||||
{
|
||||
template <typename Traits, typename PointRange, typename PointMap>
|
||||
class Orthtree<Traits, PointRange, PointMap>::Node {
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -144,20 +121,25 @@ private:
|
|||
typedef boost::iterator_range<iterator> Point_range;
|
||||
/// \endcond
|
||||
|
||||
// make Node trivially copiabled
|
||||
struct Data
|
||||
{
|
||||
Point_range points;
|
||||
Self parent;
|
||||
std::uint8_t depth;
|
||||
Global_coordinates global_coordinates;
|
||||
std::unique_ptr<Children> children;
|
||||
// make Node trivially copiable
|
||||
// struct Data
|
||||
// {
|
||||
// Point_range points;
|
||||
// Self parent;
|
||||
// std::uint8_t depth;
|
||||
// Global_coordinates global_coordinates;
|
||||
// std::unique_ptr<Children> children;
|
||||
//
|
||||
// Data (Self parent)
|
||||
// : parent (parent), depth (0) { }
|
||||
// };
|
||||
// Data* m_data;
|
||||
|
||||
Data (Self parent)
|
||||
: parent (parent), depth (0) { }
|
||||
};
|
||||
|
||||
Data* m_data;
|
||||
Point_range m_points;
|
||||
Self* m_parent; // todo: use optional<reference_wrapper<Self>> instead of Self *
|
||||
std::uint8_t m_depth;
|
||||
Global_coordinates m_global_coordinates;
|
||||
std::shared_ptr<Children> m_children;
|
||||
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
|
@ -173,8 +155,9 @@ private:
|
|||
* \brief Access to the content held by this node
|
||||
* \return a reference to the collection of point indices
|
||||
*/
|
||||
Point_range &points() { return m_data->points; }
|
||||
const Point_range &points() const { return m_data->points; }
|
||||
Point_range& points() { return m_points; }
|
||||
|
||||
const Point_range& points() const { return m_points; }
|
||||
|
||||
/// \name Construction
|
||||
/// @{
|
||||
|
|
@ -194,42 +177,38 @@ private:
|
|||
\param parent the node containing this one
|
||||
\param index this node's relationship to its parent
|
||||
*/
|
||||
explicit Node(Self parent, Local_coordinates local_coordinates)
|
||||
: m_data (new Data(parent)) {
|
||||
explicit Node(Self* parent, Local_coordinates local_coordinates)
|
||||
: m_parent(parent) {
|
||||
|
||||
if (!parent.is_null()) {
|
||||
|
||||
m_data->depth = parent.m_data->depth + 1;
|
||||
if (parent != nullptr) {
|
||||
m_depth = parent->m_depth + 1;
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i < Dimension::value; i++)
|
||||
m_global_coordinates[i] = 0;
|
||||
}
|
||||
else
|
||||
for (int i = 0; i < Dimension::value; i++)
|
||||
m_data->global_coordinates[i] = 0;
|
||||
}
|
||||
|
||||
void free() { delete m_data; }
|
||||
|
||||
Node deep_copy(Self parent = Node()) const
|
||||
{
|
||||
if (is_null())
|
||||
return Node();
|
||||
Node deep_copy(Self parent = Node()) const {
|
||||
|
||||
Node out;
|
||||
out.m_data = new Data(parent);
|
||||
|
||||
out.m_data->points = m_data->points;
|
||||
out.m_data->depth = m_data->depth;
|
||||
out.m_data->global_coordinates = m_data->global_coordinates;
|
||||
std::unique_ptr<Children> children;
|
||||
if (!is_leaf())
|
||||
{
|
||||
out.m_data->children = std::make_unique<Children>();
|
||||
out.m_parent = m_parent;
|
||||
out.m_points = m_points;
|
||||
out.m_depth = m_depth;
|
||||
out.m_global_coordinates = m_global_coordinates;
|
||||
|
||||
if (!is_leaf()) {
|
||||
out.m_children = std::make_shared<Children>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -251,10 +230,10 @@ private:
|
|||
|
||||
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++) {
|
||||
|
||||
(*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() {
|
||||
|
||||
m_data->children.reset();
|
||||
m_children.reset();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
|
@ -279,10 +258,12 @@ public:
|
|||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
// 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
|
||||
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
|
||||
|
||||
/// \name Type & Location
|
||||
|
|
@ -291,36 +272,30 @@ public:
|
|||
/*!
|
||||
\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.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
bool is_root() const
|
||||
{
|
||||
CGAL_precondition(!is_null());
|
||||
return m_data->parent.is_null();
|
||||
bool is_root() const {
|
||||
return m_parent == nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns `true` if the node has no children, `false` otherwise.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
bool is_leaf() const
|
||||
{
|
||||
CGAL_precondition(!is_null());
|
||||
return (!m_data->children);
|
||||
bool is_leaf() const {
|
||||
return (!m_children);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns this node's depth.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
std::uint8_t depth() const
|
||||
{
|
||||
CGAL_precondition (!is_null());
|
||||
return m_data->depth;
|
||||
std::uint8_t depth() const {
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -329,12 +304,9 @@ public:
|
|||
*/
|
||||
Local_coordinates local_coordinates() const {
|
||||
|
||||
CGAL_precondition (!is_null());
|
||||
// TODO: There must be a better way of doing this!
|
||||
|
||||
Local_coordinates result;
|
||||
|
||||
for (std::size_t i = 0; i < Dimension::value; ++ i)
|
||||
for (std::size_t i = 0; i < Dimension::value; ++i)
|
||||
result[i] = global_coordinates()[i] & 1;
|
||||
|
||||
return result;
|
||||
|
|
@ -344,10 +316,8 @@ public:
|
|||
\brief returns this node's global coordinates.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
Global_coordinates global_coordinates() const
|
||||
{
|
||||
CGAL_precondition (!is_null());
|
||||
return m_data->global_coordinates;
|
||||
Global_coordinates global_coordinates() const {
|
||||
return m_global_coordinates;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -356,18 +326,16 @@ public:
|
|||
|
||||
/*!
|
||||
\brief returns this node's parent.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
Self parent() const
|
||||
{
|
||||
CGAL_precondition (!is_null());
|
||||
return m_data->parent;
|
||||
\pre `!is_root()`
|
||||
*/
|
||||
const Self* parent() const {
|
||||
CGAL_precondition (!is_root());
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns the nth child of this node.
|
||||
|
||||
\pre `!is_null()`
|
||||
\pre `!is_leaf()`
|
||||
\pre `0 <= index && index < Degree::value`
|
||||
|
||||
|
|
@ -418,13 +386,29 @@ public:
|
|||
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`.
|
||||
*/
|
||||
Self operator[](std::size_t index) const {
|
||||
Self& operator[](std::size_t index) {
|
||||
|
||||
CGAL_precondition (!is_null());
|
||||
CGAL_precondition (!is_leaf());
|
||||
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.
|
||||
*/
|
||||
Self adjacent_node (Local_coordinates direction) const
|
||||
{
|
||||
CGAL_precondition(!is_null());
|
||||
const Self* adjacent_node(Local_coordinates direction) const {
|
||||
|
||||
// Direction: LEFT RIGHT DOWN UP BACK FRONT
|
||||
// direction: 000 001 010 011 100 101
|
||||
|
|
@ -489,8 +471,7 @@ public:
|
|||
CGAL_precondition(direction.to_ulong() < Dimension::value * 2);
|
||||
|
||||
// The root node has no adjacent nodes!
|
||||
if (is_root())
|
||||
return Self();
|
||||
if (is_root()) return nullptr;
|
||||
|
||||
// The least significant bit indicates the sign (which side of the node)
|
||||
bool sign = direction[0];
|
||||
|
|
@ -506,24 +487,22 @@ public:
|
|||
|
||||
// Check if this child has the opposite sign along the direction's axis
|
||||
if (local_coordinates()[dimension] != sign) {
|
||||
|
||||
// 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
|
||||
Self adjacent_node_of_parent = parent().adjacent_node(direction);
|
||||
// Find the parent's neighbor in that direction, if it exists
|
||||
const Self* adjacent_node_of_parent = parent()->adjacent_node(direction);
|
||||
|
||||
// If the parent has no neighbor, then this node doesn't have one
|
||||
if (adjacent_node_of_parent.is_null())
|
||||
return Node();
|
||||
if (!adjacent_node_of_parent) return nullptr;
|
||||
|
||||
// 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 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
|
||||
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)));
|
||||
}
|
||||
|
||||
|
|
@ -544,27 +537,27 @@ public:
|
|||
\brief checks whether the node is empty of points or not.
|
||||
*/
|
||||
bool empty() const {
|
||||
return m_data->points.empty();
|
||||
return m_points.empty();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns the number of points of this node.
|
||||
*/
|
||||
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
|
||||
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
|
||||
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.
|
||||
*
|
||||
* \todo
|
||||
* \todo This seems out of date, the implementation I see compares for direct equality
|
||||
*
|
||||
* \param rhs node to compare with
|
||||
* \return whether the nodes have different topology.
|
||||
*/
|
||||
bool operator==(const Self &rhs) const {
|
||||
return m_data == rhs.m_data;
|
||||
bool operator==(const Self& rhs) const {
|
||||
|
||||
// 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)
|
||||
{
|
||||
CGAL_assertion (!a.is_null() && !b.is_null());
|
||||
// todo: this does what the documentation for operator== claims to do!
|
||||
static bool is_topology_equal(const Self& a, const Self& b) {
|
||||
|
||||
// If one node is a leaf, and the other isn't, they're not the same
|
||||
if (a.is_leaf() != b.is_leaf())
|
||||
|
|
@ -607,8 +605,7 @@ public:
|
|||
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);
|
||||
}
|
||||
/// \endcond
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public:
|
|||
*
|
||||
* \todo
|
||||
*/
|
||||
typedef std::function<Value(Value)> Traversal_function;
|
||||
typedef std::function<Value *(Value *)> Traversal_function;
|
||||
|
||||
/// @}
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ public:
|
|||
*
|
||||
* \todo
|
||||
*/
|
||||
Traversal_iterator() : m_value(), m_next() {}
|
||||
Traversal_iterator() : m_value(nullptr), m_next() {}
|
||||
|
||||
/*!
|
||||
* \brief
|
||||
|
|
@ -68,7 +68,7 @@ public:
|
|||
* \param first
|
||||
* \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 {
|
||||
return const_cast<Value&>(m_value);
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Value m_value;
|
||||
Value *m_value;
|
||||
Traversal_function m_next;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace CGAL {
|
|||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
// Forward declaration
|
||||
template<typename T, typename PR, typename PM>
|
||||
template <typename T, typename PR, typename PM>
|
||||
class Orthtree;
|
||||
/// \endcond
|
||||
|
||||
|
|
@ -33,86 +33,85 @@ namespace Orthtrees {
|
|||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template <typename Node>
|
||||
Node next_sibling(Node n) {
|
||||
const Node* next_sibling(const Node* n) {
|
||||
|
||||
// Passing null returns the first node
|
||||
if (n.is_null())
|
||||
return Node();
|
||||
if (nullptr == n)
|
||||
return nullptr;
|
||||
|
||||
// If this node has no parent, it has no siblings
|
||||
if (n.parent().is_null())
|
||||
return Node();
|
||||
if (n->is_root())
|
||||
return nullptr;
|
||||
|
||||
// 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;
|
||||
// Return null if this is the last child
|
||||
if (int(index) == degree - 1)
|
||||
return Node();
|
||||
return nullptr;
|
||||
|
||||
// Otherwise, return the next child
|
||||
return n.parent()[index + 1];
|
||||
return &((*n->parent())[index + 1]);
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
Node next_sibling_up(Node n) {
|
||||
const Node* next_sibling_up(const Node* n) {
|
||||
|
||||
if (n.is_null())
|
||||
return Node();
|
||||
if (!n || n->is_root()) return nullptr;
|
||||
|
||||
Node up = n.parent();
|
||||
auto up = n->parent();
|
||||
while (nullptr != up) {
|
||||
|
||||
while (!up.is_null()) {
|
||||
|
||||
if (!next_sibling(up).is_null())
|
||||
if (nullptr != 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>
|
||||
Node deepest_first_child(Node n) {
|
||||
const Node* deepest_first_child(const Node* n) {
|
||||
|
||||
if (n.is_null())
|
||||
return Node();
|
||||
if (!n)
|
||||
return nullptr;
|
||||
|
||||
// Find the deepest child on the left
|
||||
Node first = n;
|
||||
while (!first.is_leaf())
|
||||
first = first[0];
|
||||
auto first = n;
|
||||
while (!first->is_leaf())
|
||||
first = &(*first)[0];
|
||||
return first;
|
||||
}
|
||||
|
||||
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())
|
||||
return Node();
|
||||
if (!n)
|
||||
return nullptr;
|
||||
|
||||
std::stack<Node> todo;
|
||||
std::stack<const Node*> todo;
|
||||
todo.push(n);
|
||||
|
||||
if (n.depth() == depth)
|
||||
if (n->depth() == depth)
|
||||
return n;
|
||||
|
||||
while (!todo.empty())
|
||||
{
|
||||
Node node = todo.top();
|
||||
while (!todo.empty()) {
|
||||
const Node* node = todo.top();
|
||||
todo.pop();
|
||||
|
||||
if (node.depth() == depth)
|
||||
if (node->depth() == depth)
|
||||
return node;
|
||||
|
||||
if (!node.is_leaf())
|
||||
for (int i = 0; i < Node::Degree::value; ++ i)
|
||||
todo.push(node[std::size_t(Node::Degree::value - 1 - i)]);
|
||||
if (!node->is_leaf())
|
||||
for (int i = 0; i < Node::Degree::value; ++i)
|
||||
todo.push(&((*node)[std::size_t(Node::Degree::value - 1 - i)]));
|
||||
}
|
||||
|
||||
return Node();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
|
@ -128,25 +127,30 @@ Node first_child_at_depth(Node n, std::size_t depth) {
|
|||
struct Preorder_traversal {
|
||||
|
||||
template <typename Node>
|
||||
Node first(Node root) const {
|
||||
const Node* first(const Node* root) const {
|
||||
return root;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
} 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 {
|
||||
|
||||
template <typename Node>
|
||||
Node first(Node root) const {
|
||||
const Node* first(const Node* root) const {
|
||||
|
||||
return deepest_first_child(root);
|
||||
}
|
||||
|
||||
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())
|
||||
next = n.parent();
|
||||
if (!next)
|
||||
next = n->parent();
|
||||
|
||||
return next;
|
||||
}
|
||||
|
|
@ -189,17 +193,17 @@ struct Postorder_traversal {
|
|||
struct Leaves_traversal {
|
||||
|
||||
template <typename Node>
|
||||
Node first(Node root) const {
|
||||
const Node* first(const Node* root) const {
|
||||
|
||||
return deepest_first_child(root);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
return next;
|
||||
|
|
@ -226,29 +230,28 @@ public:
|
|||
/*!
|
||||
constructs a `depth`-level traversal.
|
||||
*/
|
||||
Level_traversal (std::size_t depth) : depth(depth) { }
|
||||
Level_traversal(std::size_t depth) : depth(depth) {}
|
||||
|
||||
template <typename Node>
|
||||
Node first(Node root) const {
|
||||
const Node* first(const Node* root) const {
|
||||
return first_child_at_depth(root, depth);
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
Node next(Node n) const {
|
||||
const Node* next(const Node* n) const {
|
||||
// fixme: leftover from debugging?
|
||||
std::cerr << depth << " ";
|
||||
Node next = next_sibling(n);
|
||||
const Node* next = next_sibling(n);
|
||||
|
||||
if (next.is_null())
|
||||
{
|
||||
Node up = n;
|
||||
do
|
||||
{
|
||||
if (!next) {
|
||||
const Node* up = n;
|
||||
do {
|
||||
up = next_sibling_up(up);
|
||||
if (up.is_null())
|
||||
return Node();
|
||||
if (!up)
|
||||
return nullptr;
|
||||
|
||||
next = first_child_at_depth(up, depth);
|
||||
}
|
||||
while (next.is_null());
|
||||
} while (!next);
|
||||
}
|
||||
|
||||
return next;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ typedef CGAL::Simple_cartesian<double> Kernel;
|
|||
typedef Kernel::Point_3 Point;
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||
Octree;
|
||||
Octree;
|
||||
typedef Octree::Node Node;
|
||||
typedef Octree::Traits Traits;
|
||||
|
||||
|
|
@ -42,33 +42,36 @@ int main(void) {
|
|||
std::cout << octree << std::endl;
|
||||
|
||||
// Root node should have no siblings
|
||||
assert(octree.root().adjacent_node(0).is_null());
|
||||
assert(octree.root().adjacent_node(1).is_null());
|
||||
assert(octree.root().adjacent_node(2).is_null());
|
||||
assert(octree.root().adjacent_node(3).is_null());
|
||||
assert(octree.root().adjacent_node(4).is_null());
|
||||
assert(octree.root().adjacent_node(5).is_null());
|
||||
assert(octree.root().adjacent_node(0) == nullptr);
|
||||
assert(octree.root().adjacent_node(1) == nullptr);
|
||||
assert(octree.root().adjacent_node(2) == nullptr);
|
||||
assert(octree.root().adjacent_node(3) == nullptr);
|
||||
assert(octree.root().adjacent_node(4) == nullptr);
|
||||
assert(octree.root().adjacent_node(5) == nullptr);
|
||||
|
||||
// Left Top Front node should have siblings to the Right, Down, and 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::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(left_top_back.adjacent_node(Traits::LEFT).is_null());
|
||||
assert(left_top_back.adjacent_node(Traits::UP).is_null());
|
||||
assert(left_top_back.adjacent_node(Traits::BACK).is_null());
|
||||
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_TOP_FRONT] == left_top_back.adjacent_node(Traits::FRONT));
|
||||
assert(left_top_back.adjacent_node(Traits::LEFT) == nullptr);
|
||||
assert(left_top_back.adjacent_node(Traits::UP) == nullptr);
|
||||
assert(left_top_back.adjacent_node(Traits::BACK) == nullptr);
|
||||
|
||||
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];
|
||||
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::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::RIGHT).is_null());
|
||||
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::DOWN).is_null());
|
||||
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::FRONT).is_null());
|
||||
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::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::RIGHT) != nullptr);
|
||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::UP) != nullptr);
|
||||
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) != 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ std::size_t count_jumps(Octree &octree) {
|
|||
|
||||
auto adjacent_node = node.adjacent_node(direction);
|
||||
|
||||
if (adjacent_node.is_null())
|
||||
if (adjacent_node == nullptr)
|
||||
continue;
|
||||
|
||||
if ((node.depth() - adjacent_node.depth()) > 1)
|
||||
if ((node.depth() - adjacent_node->depth()) > 1)
|
||||
jumps++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,14 +46,14 @@ int main(void) {
|
|||
auto query = Point{1, 1, 1};
|
||||
|
||||
// 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));
|
||||
|
||||
// A point should only intersect one node
|
||||
assert(1 == nodes.size());
|
||||
|
||||
// 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
|
||||
|
|
@ -63,15 +63,15 @@ int main(void) {
|
|||
auto query = Kernel::Sphere_3(Point{1, 0.5, 1}, 1.0);
|
||||
|
||||
// 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));
|
||||
|
||||
// Check the results
|
||||
assert(4 == nodes.size());
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == nodes[0]);
|
||||
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == nodes[1]);
|
||||
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == nodes[2]);
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == nodes[3]);
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == *nodes[0]);
|
||||
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[1]);
|
||||
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == *nodes[2]);
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[3]);
|
||||
}
|
||||
|
||||
// Intersection with a ray
|
||||
|
|
@ -81,19 +81,19 @@ int main(void) {
|
|||
auto query = Kernel::Ray_3(Point{1, 1, 1}, Point{0, 0, 0});
|
||||
|
||||
// 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));
|
||||
|
||||
// Check the results
|
||||
assert(8 == nodes.size());
|
||||
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::LEFT_TOP_BACK] == nodes[2]);
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == nodes[3]);
|
||||
assert(octree[Octree::Traits::LEFT_BOTTOM_FRONT] == nodes[4]);
|
||||
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == nodes[5]);
|
||||
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == nodes[6]);
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == nodes[7]);
|
||||
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::LEFT_TOP_BACK] == *nodes[2]);
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_BACK] == *nodes[3]);
|
||||
assert(octree[Octree::Traits::LEFT_BOTTOM_FRONT] == *nodes[4]);
|
||||
assert(octree[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[5]);
|
||||
assert(octree[Octree::Traits::LEFT_TOP_FRONT] == *nodes[6]);
|
||||
assert(octree[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[7]);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ typedef Kernel::Point_3 Point;
|
|||
typedef Kernel::FT FT;
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||
Octree;
|
||||
Octree;
|
||||
|
||||
typedef CGAL::Search_traits_3<Kernel> Kd_tree_traits;
|
||||
typedef CGAL::Orthogonal_k_neighbor_search<Kd_tree_traits> Kd_tree_search;
|
||||
|
|
@ -47,7 +47,7 @@ void naive_vs_octree(std::size_t dataset_size) {
|
|||
{
|
||||
|
||||
FT distance_nearest = (std::numeric_limits<FT>::max)();
|
||||
for (auto &p : points.points()) {
|
||||
for (auto& p: points.points()) {
|
||||
|
||||
FT distance_current = CGAL::squared_distance(p, random_point);
|
||||
if (distance_current < distance_nearest) {
|
||||
|
|
@ -72,7 +72,6 @@ void naive_vs_octree(std::size_t dataset_size) {
|
|||
octree.refine(10, 20);
|
||||
auto octree_start_time = high_resolution_clock::now();
|
||||
{
|
||||
// TODO: Write a nearest-neighbor implementation and use it here
|
||||
std::vector<Point> k_neighbors;
|
||||
octree.nearest_neighbors(random_point, 1, std::back_inserter(k_neighbors));
|
||||
octree_nearest = *k_neighbors.begin();
|
||||
|
|
@ -109,9 +108,9 @@ void kdtree_vs_octree(std::size_t dataset_size, std::size_t K) {
|
|||
Kd_tree kd_tree(points.points().begin(), points.points().end());
|
||||
kd_tree.build();
|
||||
auto kd_tree_start_time = high_resolution_clock::now();
|
||||
Kd_tree_search search(kd_tree, random_point, (unsigned int)(K));
|
||||
Kd_tree_search search(kd_tree, random_point, (unsigned int) (K));
|
||||
duration<float> kd_tree_elapsed_time = high_resolution_clock::now() - kd_tree_start_time;
|
||||
for (auto p : search)
|
||||
for (auto p: search)
|
||||
kd_tree_nearest_neighbors.push_back(p.first);
|
||||
|
||||
std::cout << "Kd_tree --> "
|
||||
|
|
@ -143,6 +142,7 @@ void kdtree_vs_octree(std::size_t dataset_size, std::size_t K) {
|
|||
|
||||
int main(void) {
|
||||
|
||||
naive_vs_octree(21);
|
||||
naive_vs_octree(500);
|
||||
naive_vs_octree(1000);
|
||||
naive_vs_octree(10000);
|
||||
|
|
|
|||
|
|
@ -25,12 +25,11 @@ void test_1_point() {
|
|||
octree.refine(10, 1);
|
||||
|
||||
// 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(octree.root());
|
||||
assert(Node::is_topology_equal(single_node, octree.root()));
|
||||
assert(0 == octree.depth());
|
||||
CGAL::Orthtrees::Node_access::free(single_node);
|
||||
}
|
||||
|
||||
void test_2_points() {
|
||||
|
|
@ -45,12 +44,10 @@ void test_2_points() {
|
|||
octree.refine(10, 1);
|
||||
|
||||
// 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);
|
||||
assert(Node::is_topology_equal(other, octree.root()));
|
||||
assert(1 == octree.depth());
|
||||
CGAL::Orthtrees::Node_access::free(other);
|
||||
|
||||
}
|
||||
|
||||
void test_4_points() {
|
||||
|
|
@ -66,13 +63,12 @@ void test_4_points() {
|
|||
octree.refine(10, 1);
|
||||
|
||||
// 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[3]);
|
||||
CGAL::Orthtrees::Node_access::split(other[7]);
|
||||
assert(Node::is_topology_equal(other, octree.root()));
|
||||
assert(2 == octree.depth());
|
||||
CGAL::Orthtrees::Node_access::free(other);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue