mirror of https://github.com/CGAL/cgal
Delete independent `Node` type, move relevant typedefs to Orthtree.h
This commit is contained in:
parent
01aad4af7a
commit
c41faf1274
|
|
@ -73,7 +73,7 @@ split.
|
|||
|
||||
\subsection Section_Orthtree_Point_Vector Building an Octree
|
||||
|
||||
The `Orthtree` class may be templated with `Orthtree_traits_3` and thus
|
||||
The `Orthtree` class may be templated with `Orthtree_traits_point_set_3` and thus
|
||||
behave as an %octree. For convenience, the alias `Octree` is provided.
|
||||
|
||||
The following example shows how to create an %octree from a vector of
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
\cgalCRPSection{Traits}
|
||||
- `CGAL::Orthtree_traits_2<GeomTraits>`
|
||||
- `CGAL::Orthtree_traits_3<GeomTraits>`
|
||||
- `CGAL::Orthtree_traits_point_set_3<GeomTraits>`
|
||||
- `CGAL::Orthtree_traits_d<GeomTraits, Dimension>`
|
||||
|
||||
\cgalCRPSection{Split Predicates}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ public:
|
|||
typedef typename Traits::Point_d Point; ///< Point type.
|
||||
typedef typename Traits::Bbox_d Bbox; ///< Bounding box type.
|
||||
typedef typename Traits::Sphere_d Sphere; ///< Sphere type.
|
||||
typedef typename Traits::Adjacency Adjacency; ///< Adjacency type.
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
typedef typename Traits::Array Array; ///< Array type.
|
||||
|
|
@ -93,6 +94,12 @@ public:
|
|||
/// \endcond
|
||||
/// @}
|
||||
|
||||
/// \name Types specific to Point_set_3
|
||||
/// todo: should be moved to Traits
|
||||
/// @{
|
||||
typedef boost::iterator_range<typename PointRange::iterator> Node_point_range;
|
||||
/// @}
|
||||
|
||||
/// \name Public Types
|
||||
/// @{
|
||||
|
||||
|
|
@ -111,15 +118,36 @@ public:
|
|||
*/
|
||||
typedef std::size_t Node_index;
|
||||
|
||||
typedef Properties::Property_container<Node_index> Node_property_container;
|
||||
|
||||
/*!
|
||||
* \brief Optional index of a node in the tree.
|
||||
*/
|
||||
typedef boost::optional<Node_index> Maybe_node_index;
|
||||
|
||||
// todo: maybe this could be private?
|
||||
typedef Properties::Property_container<Node_index> Node_property_container;
|
||||
|
||||
/*!
|
||||
\brief Set of bits representing this node's relationship to its parent.
|
||||
|
||||
Equivalent to an array of Booleans, where index[0] is whether `x`
|
||||
is greater, index[1] is whether `y` is greater, index[2] is whether
|
||||
`z` is greater, and so on for higher dimensions if needed.
|
||||
Used to represent a node's relationship to the center of its parent.
|
||||
*/
|
||||
typedef std::bitset<Dimension::value> Local_coordinates;
|
||||
|
||||
/*!
|
||||
\brief Coordinates representing this node's relationship
|
||||
with the rest of the tree.
|
||||
|
||||
Each value `(x, y, z, ...)` of global coordinates is calculated by doubling
|
||||
the parent's global coordinates and adding the local coordinates.
|
||||
*/
|
||||
typedef std::array<std::uint32_t, Dimension::value> Global_coordinates;
|
||||
|
||||
/*!
|
||||
* \brief The Sub-tree / Orthant type.
|
||||
* todo: this should be removed
|
||||
*/
|
||||
class Node;
|
||||
|
||||
|
|
@ -163,9 +191,9 @@ private: // data members :
|
|||
PointMap m_point_map; /* property map: `value_type of InputIterator` -> `Point` (Position) */
|
||||
|
||||
Node_property_container m_node_properties;
|
||||
Node_property_container::Array <boost::iterator_range<typename PointRange::iterator>>& m_node_points;
|
||||
Node_property_container::Array <Node_point_range>& m_node_points;
|
||||
Node_property_container::Array <std::uint8_t>& m_node_depths;
|
||||
Node_property_container::Array <std::array<std::uint32_t, Dimension::value>>& m_node_coordinates;
|
||||
Node_property_container::Array <Global_coordinates>& m_node_coordinates;
|
||||
Node_property_container::Array <Maybe_node_index>& m_node_parents;
|
||||
Node_property_container::Array <Maybe_node_index>& m_node_children;
|
||||
|
||||
|
|
@ -212,9 +240,9 @@ public:
|
|||
const FT enlarge_ratio = 1.2,
|
||||
Traits traits = Traits()) :
|
||||
m_traits(traits), m_range(point_range), m_point_map(point_map),
|
||||
m_node_points(m_node_properties.add_property<boost::iterator_range<typename PointRange::iterator>>("points")),
|
||||
m_node_points(m_node_properties.add_property<Node_point_range>("points")),
|
||||
m_node_depths(m_node_properties.add_property<std::uint8_t>("depths", 0)),
|
||||
m_node_coordinates(m_node_properties.add_property<std::array<std::uint32_t, Dimension::value>>("coordinates")),
|
||||
m_node_coordinates(m_node_properties.add_property<Global_coordinates>("coordinates")),
|
||||
m_node_parents(m_node_properties.add_property<Maybe_node_index>("parents")),
|
||||
m_node_children(m_node_properties.add_property<Maybe_node_index>("children")) {
|
||||
|
||||
|
|
@ -275,9 +303,9 @@ public:
|
|||
m_traits(other.m_traits), m_range(other.m_range), m_point_map(other.m_point_map),
|
||||
m_bbox_min(other.m_bbox_min), m_side_per_depth(other.m_side_per_depth),
|
||||
m_node_properties(other.m_node_properties),
|
||||
m_node_points(m_node_properties.get_property<boost::iterator_range<typename PointRange::iterator>>("points")),
|
||||
m_node_points(m_node_properties.get_property<Node_point_range>("points")),
|
||||
m_node_depths(m_node_properties.get_property<std::uint8_t>("depths")),
|
||||
m_node_coordinates(m_node_properties.get_property<std::array<std::uint32_t, Dimension::value>>("coordinates")),
|
||||
m_node_coordinates(m_node_properties.get_property<Global_coordinates>("coordinates")),
|
||||
m_node_parents(m_node_properties.get_property<Maybe_node_index>("parents")),
|
||||
m_node_children(m_node_properties.get_property<Maybe_node_index>("children")) {}
|
||||
|
||||
|
|
@ -286,9 +314,9 @@ public:
|
|||
m_traits(other.m_traits), m_range(other.m_range), m_point_map(other.m_point_map),
|
||||
m_bbox_min(other.m_bbox_min), m_side_per_depth(other.m_side_per_depth),
|
||||
m_node_properties(std::move(other.m_node_properties)),
|
||||
m_node_points(m_node_properties.get_property<boost::iterator_range<typename PointRange::iterator>>("points")),
|
||||
m_node_points(m_node_properties.get_property<Node_point_range>("points")),
|
||||
m_node_depths(m_node_properties.get_property<std::uint8_t>("depths")),
|
||||
m_node_coordinates(m_node_properties.get_property<std::array<std::uint32_t, Dimension::value>>("coordinates")),
|
||||
m_node_coordinates(m_node_properties.get_property<Global_coordinates>("coordinates")),
|
||||
m_node_parents(m_node_properties.get_property<Maybe_node_index>("parents")),
|
||||
m_node_children(m_node_properties.get_property<Maybe_node_index>("children")) {
|
||||
|
||||
|
|
@ -312,10 +340,9 @@ public:
|
|||
/*!
|
||||
\brief recursively subdivides the orthtree until it meets the given criteria.
|
||||
|
||||
todo: split predicate now works with node indices!
|
||||
The split predicate is a `std::function` that takes a `Node` and
|
||||
returns a Boolean value (where `true` implies that a `Node` needs to
|
||||
be split, `false` that the `Node` should be a leaf).
|
||||
The split predicate is an `std::function` that takes a `Node_index` and an Orthtree reference, and
|
||||
returns a Boolean value (where `true` implies that the corresponding node needs to
|
||||
be split, `false` that the node should be a leaf).
|
||||
|
||||
This function may be called several times with different
|
||||
predicates: in that case, nodes already split are left unaltered,
|
||||
|
|
@ -600,7 +627,7 @@ public:
|
|||
Point center = barycenter(node_for_point);
|
||||
|
||||
// Find the index of the correct sub-node
|
||||
typename Node::Local_coordinates local_coords;
|
||||
Local_coordinates local_coords;
|
||||
std::size_t dimension = 0;
|
||||
for (const auto& r: cartesian_range(center, point))
|
||||
local_coords[dimension++] = (get < 0 > (r) < get < 1 > (r));
|
||||
|
|
@ -657,7 +684,7 @@ public:
|
|||
This function finds all the intersecting nodes and returns them as const pointers.
|
||||
|
||||
\tparam Query the primitive class (e.g. sphere, ray)
|
||||
\tparam OutputIterator a model of `OutputIterator` that accepts `Node` objects
|
||||
\tparam OutputIterator a model of `OutputIterator` that accepts `Node_index` types
|
||||
\param query the intersecting primitive.
|
||||
\param output output iterator.
|
||||
*/
|
||||
|
|
@ -676,7 +703,6 @@ public:
|
|||
|
||||
Trees may be considered equivalent even if they contain different points.
|
||||
Equivalent trees must have the same bounding box and the same node structure.
|
||||
Node structure is evaluated by comparing the root nodes using the node equality operator.
|
||||
*/
|
||||
bool operator==(const Self& rhs) const {
|
||||
|
||||
|
|
@ -716,20 +742,20 @@ public:
|
|||
return m_node_depths[n];
|
||||
}
|
||||
|
||||
typename Node::Point_range& points(Node_index n) {
|
||||
Node_point_range& points(Node_index n) {
|
||||
return m_node_points[n];
|
||||
}
|
||||
|
||||
const typename Node::Point_range& points(Node_index n) const {
|
||||
const Node_point_range& points(Node_index n) const {
|
||||
return m_node_points[n];
|
||||
}
|
||||
|
||||
typename Node::Global_coordinates global_coordinates(Node_index n) const {
|
||||
Global_coordinates global_coordinates(Node_index n) const {
|
||||
return m_node_coordinates[n];
|
||||
}
|
||||
|
||||
typename Node::Local_coordinates local_coordinates(Node_index n) const {
|
||||
typename Node::Local_coordinates result;
|
||||
Local_coordinates local_coordinates(Node_index n) const {
|
||||
Local_coordinates result;
|
||||
for (std::size_t i = 0; i < Dimension::value; ++i)
|
||||
result[i] = global_coordinates(n)[i] & 1;
|
||||
return result;
|
||||
|
|
@ -770,7 +796,7 @@ public:
|
|||
std::size_t local_coords = local_coordinates(n).to_ulong(); // todo: add local_coordinates(n) helper
|
||||
|
||||
// The last child has no more siblings
|
||||
if (int(local_coords) == Node::Degree::value - 1)
|
||||
if (int(local_coords) == Degree::value - 1)
|
||||
return {};
|
||||
|
||||
// The next sibling is the child of the parent with the following local coordinates
|
||||
|
|
@ -815,7 +841,7 @@ public:
|
|||
return node;
|
||||
|
||||
if (!is_leaf(node))
|
||||
for (int i = 0; i < Node::Degree::value; ++i)
|
||||
for (int i = 0; i < Degree::value; ++i)
|
||||
todo.push(child(node, i));
|
||||
}
|
||||
|
||||
|
|
@ -837,7 +863,7 @@ public:
|
|||
CGAL_precondition (is_leaf(n));
|
||||
|
||||
// Split the node to create children
|
||||
using Local_coordinates = typename Node::Local_coordinates;
|
||||
using Local_coordinates = Local_coordinates;
|
||||
m_node_children[n] = m_node_properties.emplace_group(Degree::value);
|
||||
for (std::size_t i = 0; i < Degree::value; i++) {
|
||||
|
||||
|
|
@ -966,7 +992,7 @@ public:
|
|||
|
||||
\return the index of the adjacent node if it exists, nothing otherwise.
|
||||
*/
|
||||
Maybe_node_index adjacent_node(Node_index n, typename Node::Local_coordinates direction) const {
|
||||
Maybe_node_index adjacent_node(Node_index n, Local_coordinates direction) const {
|
||||
|
||||
// Direction: LEFT RIGHT DOWN UP BACK FRONT
|
||||
// direction: 000 001 010 011 100 101
|
||||
|
|
@ -1012,7 +1038,7 @@ public:
|
|||
/*!
|
||||
\brief equivalent to `adjacent_node()`, with an adjacency direction rather than a bitset.
|
||||
*/
|
||||
Maybe_node_index adjacent_node(Node_index n, typename Node::Adjacency adjacency) const {
|
||||
Maybe_node_index adjacent_node(Node_index n, Adjacency adjacency) const {
|
||||
return adjacent_node(n, std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
||||
}
|
||||
|
||||
|
|
@ -1286,6 +1312,4 @@ public:
|
|||
|
||||
} // namespace CGAL
|
||||
|
||||
#include <CGAL/Orthtree/Node.h>
|
||||
|
||||
#endif // CGAL_ORTHTREE_H
|
||||
|
|
|
|||
|
|
@ -1,238 +0,0 @@
|
|||
// Copyright (c) 2007-2020 INRIA (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
// Author(s) : Jackson Campolattaro, Cédric Portaneri, Tong Zhao
|
||||
|
||||
#ifndef CGAL_ORTHTREE_NODE_H
|
||||
#define CGAL_ORTHTREE_NODE_H
|
||||
|
||||
#include <CGAL/license/Orthtree.h>
|
||||
|
||||
#include <CGAL/Orthtree.h>
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/core/span.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
|
||||
\brief represents a single node of the tree. Alternatively referred
|
||||
to as a cell, orthant, or sub-tree.
|
||||
|
||||
A `Node` is a lightweight object and thus generally passed by
|
||||
copy. It is also a model of `ConstRange` with value type `Traits::Point_d`.
|
||||
|
||||
\cgalModels `ConstRange`
|
||||
*/
|
||||
template <typename Traits, typename PointRange, typename PointMap>
|
||||
class Orthtree<Traits, PointRange, PointMap>::Node {
|
||||
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
typedef Orthtree<Traits, PointRange, PointMap> Enclosing; ///< Orthtree type (enclosing class).
|
||||
typedef typename Enclosing::Dimension Dimension; ///< Dimension type.
|
||||
typedef typename Enclosing::Degree Degree; ///< Degree type.
|
||||
typedef typename Enclosing::Node_index Node_index; ///< Index type.
|
||||
typedef typename Enclosing::Maybe_node_index Maybe_node_index; ///< Index type.
|
||||
|
||||
/*!
|
||||
\brief Self typedef for convenience.
|
||||
*/
|
||||
typedef typename Orthtree<Traits, PointRange, PointMap>::Node Self;
|
||||
|
||||
/*!
|
||||
\brief Set of bits representing this node's relationship to its parent.
|
||||
|
||||
Equivalent to an array of Booleans, where index[0] is whether `x`
|
||||
is greater, index[1] is whether `y` is greater, index[2] is whether
|
||||
`z` is greater, and so on for higher dimensions if needed.
|
||||
Used to represent a node's relationship to the center of its parent.
|
||||
*/
|
||||
typedef std::bitset<Dimension::value> Local_coordinates;
|
||||
|
||||
/*!
|
||||
\brief Coordinates representing this node's relationship
|
||||
with the rest of the tree.
|
||||
|
||||
Each value `(x, y, z, ...)` of global coordinates is calculated by doubling
|
||||
the parent's global coordinates and adding the local coordinates.
|
||||
*/
|
||||
typedef std::array<std::uint32_t, Dimension::value> Global_coordinates;
|
||||
|
||||
|
||||
typedef typename PointRange::const_iterator const_iterator; ///< constant iterator type.
|
||||
|
||||
/*!
|
||||
\brief Adjacency directions.
|
||||
*/
|
||||
typedef typename Traits::Adjacency Adjacency;
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
/*!
|
||||
\brief point range type.
|
||||
*/
|
||||
typedef typename PointRange::iterator iterator; ///< constant iterator type.
|
||||
typedef boost::iterator_range<iterator> Point_range;
|
||||
/// \endcond
|
||||
|
||||
Point_range m_points;
|
||||
std::uint8_t m_depth = 0;
|
||||
Global_coordinates m_global_coordinates{};
|
||||
|
||||
Maybe_node_index m_parent_index{};
|
||||
Maybe_node_index m_children_index{};
|
||||
|
||||
// Only the Orthtree class has access to the non-default
|
||||
// constructor, mutators, etc.
|
||||
friend Enclosing;
|
||||
|
||||
public:
|
||||
|
||||
/// \name Construction
|
||||
/// @{
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
Node() = default; // constructs a root node
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
\brief creates a new node, optionally as the child of a parent
|
||||
|
||||
If no parent is provided, the node created is assumed to be the
|
||||
root of a tree. This means that `parent.is_null()` returns
|
||||
`true`, and the depth is zero. If a parent is provided, the node
|
||||
becomes the child of that parent. In that case, an index should
|
||||
be passed, telling this node its relationship to its parent.
|
||||
Depth and global coordinates are automatically determined in the
|
||||
constructor, and should generally be considered immutable after
|
||||
construction.
|
||||
|
||||
\param parent the node containing this one
|
||||
\param index this node's relationship to its parent
|
||||
*/
|
||||
explicit Node(Node_index parent_index, Global_coordinates parent_coordinates,
|
||||
std::size_t depth, Local_coordinates local_coordinates) :
|
||||
m_parent_index(parent_index), m_depth(depth) {
|
||||
|
||||
for (int i = 0; i < Dimension::value; i++)
|
||||
m_global_coordinates[i] = (2 * parent_coordinates[i]) + local_coordinates[i];
|
||||
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
public:
|
||||
|
||||
/// \name Member Access
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
* \brief Access to the content held by this node
|
||||
* \return a reference to the collection of point indices
|
||||
*/
|
||||
Point_range& points() { return m_points; }
|
||||
|
||||
const Point_range& points() const { return m_points; }
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Type & Location
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
\brief returns `true` if the node has no parent, `false` otherwise.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
bool is_root() const {
|
||||
return !m_parent_index.has_value();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns `true` if the node has no children, `false` otherwise.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
bool is_leaf() const {
|
||||
return !m_children_index.has_value();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns this node's depth.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
std::uint8_t depth() const {
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns this node's local coordinates (in relation to its parent).
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
Local_coordinates local_coordinates() const {
|
||||
|
||||
Local_coordinates result;
|
||||
|
||||
for (std::size_t i = 0; i < Dimension::value; ++i)
|
||||
result[i] = global_coordinates()[i] & 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns this node's global coordinates.
|
||||
\pre `!is_null()`
|
||||
*/
|
||||
Global_coordinates global_coordinates() const {
|
||||
return m_global_coordinates;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Point Range
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
\brief returns the number of points of this node.
|
||||
*/
|
||||
std::size_t size() const {
|
||||
return std::size_t(std::distance(m_points.begin(), m_points.end()));
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
/// \name Operators
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
* \brief compares the topology of this node to another node.
|
||||
*
|
||||
* \param rhs node to compare with
|
||||
* \return whether the nodes have different topology.
|
||||
*/
|
||||
bool operator==(const Self& rhs) const = default; // todo: this doesn't work in C++17
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //CGAL_ORTHTREE_NODE_H
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
|
||||
#include <CGAL/Orthtree/Node.h>
|
||||
#include <CGAL/Octree/IO.h>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
typedef CGAL::Orthtree::Node<std::vector<int>::iterator> Node;
|
||||
|
||||
int main(void) {
|
||||
|
||||
// Build a new node
|
||||
Node n = Node();
|
||||
|
||||
// Check that its values are correct
|
||||
assert(n.is_root());
|
||||
assert(n.is_leaf());
|
||||
assert(!n.parent());
|
||||
assert(n.depth() == 0);
|
||||
assert(n.location()[0] == 0 && n.location()[1] == 0 && n.location()[2] == 0);
|
||||
|
||||
// Split the node
|
||||
n.split();
|
||||
|
||||
// Check that it's children's values are also correct
|
||||
for (std::size_t i = 0; i < 8; ++i) {
|
||||
|
||||
assert(!n[i].is_root());
|
||||
assert(n[i].is_leaf());
|
||||
assert(*n[i].parent() == n);
|
||||
assert(n[i].depth() == 1);
|
||||
}
|
||||
|
||||
// Check that the parent has updated
|
||||
assert(n.is_root());
|
||||
assert(!n.is_leaf());
|
||||
|
||||
// Split one of the children
|
||||
n[1].split();
|
||||
|
||||
// Check each of that child's children
|
||||
for (std::size_t i = 0; i < 8; ++i) {
|
||||
|
||||
assert(!n[1][i].is_root());
|
||||
assert(n[1][i].is_leaf());
|
||||
assert(*n[1][i].parent() == n[1]);
|
||||
assert(*n[1][i].parent()->parent() == n);
|
||||
assert(n[1][i].depth() == 2);
|
||||
}
|
||||
|
||||
// Check that the child's values have updated
|
||||
assert(!n[1].is_root());
|
||||
assert(!n[1].is_leaf());
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue