Add shims for using functions with indices

This commit is contained in:
JacksonCampolattaro 2023-04-12 11:17:57 +02:00
parent 9103affe72
commit 4e3fc7edf6
2 changed files with 92 additions and 41 deletions

View File

@ -87,10 +87,8 @@ public:
/// \cond SKIP_IN_MANUAL /// \cond SKIP_IN_MANUAL
typedef typename Traits::Array Array; ///< Array type. typedef typename Traits::Array Array; ///< Array type.
typedef typename Traits::Construct_point_d_from_array 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;
typedef typename Traits::Construct_bbox_d
Construct_bbox_d;
/// \endcond /// \endcond
/// @} /// @}
@ -107,6 +105,11 @@ public:
*/ */
typedef Dimension_tag<(2 << (Dimension::value - 1))> Degree; typedef Dimension_tag<(2 << (Dimension::value - 1))> Degree;
/*!
* \brief Index of a given node in the tree; the root always has index 0.
*/
typedef std::size_t Node_index;
/*! /*!
* \brief The Sub-tree / Orthant type. * \brief The Sub-tree / Orthant type.
*/ */
@ -197,8 +200,6 @@ public:
, m_range(point_range) , m_range(point_range)
, m_point_map(point_map) { , m_point_map(point_map) {
// fixme: this can be removed once traversal doesn't require pointer stability
//m_nodes.reserve(1'000'000);
m_nodes.emplace_back(); m_nodes.emplace_back();
Array bbox_min; Array bbox_min;
@ -311,7 +312,7 @@ public:
m_side_per_depth.resize(1); m_side_per_depth.resize(1);
// Initialize a queue of nodes that need to be refined // Initialize a queue of nodes that need to be refined
std::queue<std::size_t> todo; std::queue<Node_index> todo;
todo.push(0); todo.push(0);
// Process items in the queue until it's consumed fully // Process items in the queue until it's consumed fully
@ -372,28 +373,27 @@ public:
void grade() { void grade() {
// Collect all the leaf nodes // Collect all the leaf nodes
std::queue<Node*> leaf_nodes; std::queue<Node_index> leaf_nodes;
for (const Node& leaf: traverse(Orthtrees::Leaves_traversal<Self>(*this))) { for (const Node& leaf: traverse(Orthtrees::Leaves_traversal<Self>(*this))) {
// TODO: I'd like to find a better (safer) way of doing this leaf_nodes.push(index(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_index 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 (!m_nodes[node].is_leaf())
continue; continue;
// Iterate over each of the neighbors // Iterate over each of the neighbors
for (int direction = 0; direction < 6; ++direction) { for (int direction = 0; direction < 6; ++direction) {
// Get the neighbor // Get the neighbor
auto* neighbor = adjacent_node(*node, direction); auto neighbor = index(adjacent_node(node, direction));
// If it doesn't exist, skip it // If it doesn't exist, skip it
if (!neighbor) if (!neighbor)
@ -401,23 +401,23 @@ public:
// 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 (&parent(*neighbor) == &parent(*node)) if (parent(neighbor.get()) == parent(node))
continue; continue;
// If it's already been split, skip it // If it's already been split, skip it
if (!neighbor->is_leaf()) if (!m_nodes[neighbor.get()].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 ((m_nodes[node].depth() - m_nodes[neighbor.get()].depth()) > 1) {
// Split the neighbor // Split the neighbor
split(*neighbor); split(neighbor.get());
// 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(&children(*neighbor)[i]); leaf_nodes.push(index(children(neighbor.get())[i]));
} }
} }
} }
@ -445,21 +445,21 @@ public:
*/ */
Node& root() { return m_nodes[0]; } Node& root() { return m_nodes[0]; }
std::size_t index(const Node& node) const { Node_index index(const Node& node) const {
return std::distance(m_nodes.data(), &node); return std::distance(m_nodes.data(), &node);
} }
boost::optional<std::size_t> index(const Node* node) const { boost::optional<Node_index> index(const Node* node) const {
if (node == nullptr) return {}; if (node == nullptr) return {};
return index(*node); return index(*node);
} }
const Node& operator[](std::size_t index) const { const Node& operator[](Node_index index) const {
return m_nodes[index]; return m_nodes[index];
} }
Node& operator[](std::size_t index) { Node& operator[](Node_index index) {
return m_nodes[index]; return m_nodes[index];
} }
@ -486,7 +486,7 @@ public:
const Node* first = traversal.first(); const Node* first = traversal.first();
auto next = [=](const Self& tree, std::size_t index) -> boost::optional<std::size_t> { auto next = [=](const Self& tree, Node_index index) -> boost::optional<Node_index> {
auto n = traversal.next(&tree[index]); auto n = traversal.next(&tree[index]);
if (n == nullptr) return {}; if (n == nullptr) return {};
return tree.index(*n); return tree.index(*n);
@ -528,6 +528,10 @@ public:
return construct_bbox(min_corner, max_corner); return construct_bbox(min_corner, max_corner);
} }
Bbox bbox(Node_index n) const {
return bbox(m_nodes[n]);
}
/// @} /// @}
/// \name Queries /// \name Queries
@ -603,8 +607,7 @@ public:
template <typename OutputIterator> template <typename OutputIterator>
OutputIterator nearest_neighbors(const Sphere& query, OutputIterator output) const { OutputIterator nearest_neighbors(const Sphere& query, OutputIterator output) const {
Sphere query_sphere = query; Sphere query_sphere = query;
return nearest_k_neighbors_in_radius(query_sphere, return nearest_k_neighbors_in_radius(query_sphere, (std::numeric_limits<std::size_t>::max)(), output);
(std::numeric_limits<std::size_t>::max)(), output);
} }
/*! /*!
@ -677,6 +680,11 @@ public:
return m_nodes[node.m_parent_index.get()]; return m_nodes[node.m_parent_index.get()];
} }
Node_index parent(Node_index node) const {
CGAL_precondition (!m_nodes[node].is_root());
return m_nodes[node].m_parent_index.get();
}
// todo: these types can probably be moved out of Node // todo: these types can probably be moved out of Node
using Children = typename Node::Children; using Children = typename Node::Children;
using Children_const = typename Node::Children_const; using Children_const = typename Node::Children_const;
@ -686,11 +694,19 @@ public:
return Children{&m_nodes[node.m_children_index.get()], Degree::value}; return Children{&m_nodes[node.m_children_index.get()], Degree::value};
} }
Children children(Node_index node) {
return children(m_nodes[node]);
}
Children_const children(const Node& node) const { Children_const children(const Node& node) const {
CGAL_precondition (!node.is_leaf()); CGAL_precondition (!node.is_leaf());
return Children_const{&m_nodes[node.m_children_index.get()], Degree::value}; return Children_const{&m_nodes[node.m_children_index.get()], Degree::value};
} }
Children_const children(Node_index node) const {
return children(m_nodes[node]);
}
const Node* next_sibling(const Node* n) const { const Node* next_sibling(const Node* n) const {
// todo: maybe this should take a reference? // todo: maybe this should take a reference?
@ -702,16 +718,20 @@ public:
return nullptr; 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 local_coordinates = 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(local_coordinates) == degree - 1)
return nullptr; return nullptr;
// Otherwise, return the next child // Otherwise, return the next child
return &(children(parent(*n))[index + 1]); return &(children(parent(*n))[local_coordinates + 1]);
}
const Node* next_sibling(Node_index n) const {
return next_sibling(&m_nodes[n]);
} }
const Node* next_sibling_up(const Node* n) const { const Node* next_sibling_up(const Node* n) const {
@ -731,6 +751,10 @@ public:
return nullptr; return nullptr;
} }
const Node* next_sibling_up(Node_index n) const {
return next_sibling_up(&m_nodes[n]);
}
const Node* deepest_first_child(const Node* n) const { const Node* deepest_first_child(const Node* n) const {
if (n == nullptr) if (n == nullptr)
@ -743,12 +767,16 @@ public:
return first; return first;
} }
const Node* deepest_first_child(Node_index n) const {
return deepest_first_child(&m_nodes[n]);
}
const Node* first_child_at_depth(const Node* n, std::size_t depth) const { const Node* first_child_at_depth(const Node* n, std::size_t depth) const {
if (!n) if (!n)
return nullptr; return nullptr;
// todo: use Node_index instead of pointer
std::stack<const Node*> todo; std::stack<const Node*> todo;
todo.push(n); todo.push(n);
@ -770,6 +798,10 @@ public:
return nullptr; return nullptr;
} }
const Node* first_child_at_depth(Node_index n, std::size_t depth) const {
return first_child_at_depth(&m_nodes[n], depth);
}
/*! /*!
\brief splits the node into subnodes. \brief splits the node into subnodes.
@ -782,7 +814,7 @@ public:
*/ */
void split(Node& node) { split(index(node)); } void split(Node& node) { split(index(node)); }
void split(std::size_t n) { void split(Node_index n) {
// Make sure the node hasn't already been split // Make sure the node hasn't already been split
CGAL_precondition (m_nodes[n].is_leaf()); CGAL_precondition (m_nodes[n].is_leaf());
@ -813,7 +845,7 @@ public:
node.m_children_index.reset(); node.m_children_index.reset();
} }
void unsplit(std::size_t n) { void unsplit(Node_index n) {
unsplit(m_nodes[n]); unsplit(m_nodes[n]);
} }
@ -837,6 +869,9 @@ public:
return construct_point_d_from_array(bary); return construct_point_d_from_array(bary);
} }
Point barycenter(Node_index n) const {
return barycenter(m_nodes[n]);
}
// todo: this does what the documentation for operator== claims to do! // todo: this does what the documentation for operator== claims to do!
static bool is_topology_equal(const Node& lhsNode, const Self& lhsTree, const Node& rhsNode, const Self& rhsTree) { static bool is_topology_equal(const Node& lhsNode, const Self& lhsTree, const Node& rhsNode, const Self& rhsTree) {
@ -959,6 +994,10 @@ public:
} }
const Node* adjacent_node(Node_index n, typename Node::Local_coordinates direction) const {
return adjacent_node(m_nodes[n], direction);
}
/*! /*!
\brief equivalent to `adjacent_node()`, with an adjacency direction rather than a bitset. \brief equivalent to `adjacent_node()`, with an adjacency direction rather than a bitset.
*/ */
@ -966,6 +1005,10 @@ public:
return adjacent_node(node, std::bitset<Dimension::value>(static_cast<int>(adjacency))); return adjacent_node(node, std::bitset<Dimension::value>(static_cast<int>(adjacency)));
} }
const Node* adjacent_node(Node_index n, typename Node::Adjacency adjacency) const {
return adjacent_node(m_nodes[n], adjacency);
}
/*! /*!
* \brief equivalent to adjacent_node, except non-const * \brief equivalent to adjacent_node, except non-const
*/ */
@ -1018,15 +1061,25 @@ private: // functions :
} }
void reassign_points(Node_index n, Range_iterator begin, Range_iterator end, const Point& center,
std::bitset<Dimension::value> coord = {},
std::size_t dimension = 0) {
reassign_points(m_nodes[n], begin, end, center, coord, dimension);
}
bool do_intersect(const Node& node, const Sphere& sphere) const { bool do_intersect(const Node& node, const Sphere& sphere) const {
// Create a cubic bounding box from the node // Create a cubic bounding box from the node
Bbox node_cube = bbox(node); Bbox node_cube = bbox(node);
// Check for overlap between the node's box and the sphere as a box, to quickly catch some cases // Check for intersection between the node and the sphere
// FIXME: Activating this causes slower times return CGAL::do_intersect(node_cube, sphere);
// if (!do_overlap(node_cube, sphere.bbox())) }
// return false;
bool do_intersect(Node_index n, const Sphere& sphere) const {
// Create a cubic bounding box from the node
Bbox node_cube = bbox(n);
// Check for intersection between the node and the sphere // Check for intersection between the node and the sphere
return CGAL::do_intersect(node_cube, sphere); return CGAL::do_intersect(node_cube, sphere);
@ -1167,9 +1220,7 @@ private: // functions :
\param output the output iterator to add the found points to (in order of increasing distance) \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 OutputIterator nearest_k_neighbors_in_radius(Sphere& query_sphere, std::size_t k, OutputIterator output) const {
(Sphere& query_sphere,
std::size_t k, OutputIterator output) const {
// Create an empty list of points // Create an empty list of points
std::vector<Point_with_distance> points_list; std::vector<Point_with_distance> points_list;

View File

@ -48,6 +48,7 @@ public:
typedef Orthtree<Traits, PointRange, PointMap> Enclosing; ///< Orthtree type (enclosing class). typedef Orthtree<Traits, PointRange, PointMap> Enclosing; ///< Orthtree type (enclosing class).
typedef typename Enclosing::Dimension Dimension; ///< Dimension type. typedef typename Enclosing::Dimension Dimension; ///< Dimension type.
typedef typename Enclosing::Degree Degree; ///< Degree type. typedef typename Enclosing::Degree Degree; ///< Degree type.
typedef typename Enclosing::Node_index Node_index; ///< Index type.
/*! /*!
\brief Self typedef for convenience. \brief Self typedef for convenience.
@ -106,9 +107,8 @@ private:
std::uint8_t m_depth = 0; std::uint8_t m_depth = 0;
Global_coordinates m_global_coordinates{}; Global_coordinates m_global_coordinates{};
// todo boost::optional<Node_index> m_parent_index{};
boost::optional<std::size_t> m_parent_index{}; boost::optional<Node_index> m_children_index{};
boost::optional<std::size_t> m_children_index{};
// Only the Orthtree class has access to the non-default // Only the Orthtree class has access to the non-default
// constructor, mutators, etc. // constructor, mutators, etc.
@ -138,7 +138,7 @@ public:
\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(std::size_t parent_index, Global_coordinates parent_coordinates, explicit Node(Node_index parent_index, Global_coordinates parent_coordinates,
std::size_t depth, Local_coordinates local_coordinates) : std::size_t depth, Local_coordinates local_coordinates) :
m_parent_index(parent_index), m_depth(depth) { m_parent_index(parent_index), m_depth(depth) {