diff --git a/Orthtree/doc/Orthtree/Orthtree.txt b/Orthtree/doc/Orthtree/Orthtree.txt index 0a957a6fa51..060bda6aaa5 100644 --- a/Orthtree/doc/Orthtree/Orthtree.txt +++ b/Orthtree/doc/Orthtree/Orthtree.txt @@ -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 diff --git a/Orthtree/doc/Orthtree/PackageDescription.txt b/Orthtree/doc/Orthtree/PackageDescription.txt index 22b02350771..cb9864363ef 100644 --- a/Orthtree/doc/Orthtree/PackageDescription.txt +++ b/Orthtree/doc/Orthtree/PackageDescription.txt @@ -48,7 +48,7 @@ \cgalCRPSection{Traits} - `CGAL::Orthtree_traits_2` -- `CGAL::Orthtree_traits_3` +- `CGAL::Orthtree_traits_point_set_3` - `CGAL::Orthtree_traits_d` \cgalCRPSection{Split Predicates} diff --git a/Orthtree/include/CGAL/Orthtree.h b/Orthtree/include/CGAL/Orthtree.h index ac7ee409b9e..34a15ab0fc1 100644 --- a/Orthtree/include/CGAL/Orthtree.h +++ b/Orthtree/include/CGAL/Orthtree.h @@ -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 Node_point_range; + /// @} + /// \name Public Types /// @{ @@ -111,15 +118,36 @@ public: */ typedef std::size_t Node_index; - typedef Properties::Property_container Node_property_container; - /*! * \brief Optional index of a node in the tree. */ typedef boost::optional Maybe_node_index; + // todo: maybe this could be private? + typedef Properties::Property_container 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 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 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 >& m_node_points; + Node_property_container::Array & m_node_points; Node_property_container::Array & m_node_depths; - Node_property_container::Array >& m_node_coordinates; + Node_property_container::Array & m_node_coordinates; Node_property_container::Array & m_node_parents; Node_property_container::Array & 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>("points")), + m_node_points(m_node_properties.add_property("points")), m_node_depths(m_node_properties.add_property("depths", 0)), - m_node_coordinates(m_node_properties.add_property>("coordinates")), + m_node_coordinates(m_node_properties.add_property("coordinates")), m_node_parents(m_node_properties.add_property("parents")), m_node_children(m_node_properties.add_property("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>("points")), + m_node_points(m_node_properties.get_property("points")), m_node_depths(m_node_properties.get_property("depths")), - m_node_coordinates(m_node_properties.get_property>("coordinates")), + m_node_coordinates(m_node_properties.get_property("coordinates")), m_node_parents(m_node_properties.get_property("parents")), m_node_children(m_node_properties.get_property("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>("points")), + m_node_points(m_node_properties.get_property("points")), m_node_depths(m_node_properties.get_property("depths")), - m_node_coordinates(m_node_properties.get_property>("coordinates")), + m_node_coordinates(m_node_properties.get_property("coordinates")), m_node_parents(m_node_properties.get_property("parents")), m_node_children(m_node_properties.get_property("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(static_cast(adjacency))); } @@ -1286,6 +1312,4 @@ public: } // namespace CGAL -#include - #endif // CGAL_ORTHTREE_H diff --git a/Orthtree/include/CGAL/Orthtree/Node.h b/Orthtree/include/CGAL/Orthtree/Node.h deleted file mode 100644 index 2fbe9e56a77..00000000000 --- a/Orthtree/include/CGAL/Orthtree/Node.h +++ /dev/null @@ -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 - -#include - -#include -#include - -#include -#include -#include -#include -#include - -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 -class Orthtree::Node { - -public: - - /// \name Types - /// @{ - - typedef Orthtree 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::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 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 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 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 diff --git a/Orthtree/test/Orthtree/test_node.cpp b/Orthtree/test/Orthtree/test_node.cpp deleted file mode 100644 index 13e3a3f0728..00000000000 --- a/Orthtree/test/Orthtree/test_node.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -#include -#include -#include -#include - -typedef CGAL::Orthtree::Node::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; -}