Orthtree: Doc and traits bugfixes (#8678)

## Summary of Changes

Octree doc states requirement of RandomAccessIterator for point range
added missing _object types for functors in traits

## Release Management

* Affected package(s): Orthtree
This commit is contained in:
Sebastien Loriot 2025-01-09 19:14:51 +01:00 committed by GitHub
commit 17e6644f9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 69 additions and 31 deletions

View File

@ -25,7 +25,7 @@ namespace CGAL {
\brief Alias that specializes the `Orthtree` class to a 3D octree storing 3D points. \brief Alias that specializes the `Orthtree` class to a 3D octree storing 3D points.
\tparam GeomTraits a model of `Kernel` \tparam GeomTraits a model of `Kernel`
\tparam PointRange a model of `Range` whose value type is the key type of `PointMap` \tparam PointRange a model of `Range` whose value type is the key type of `PointMap` and whose iterator type is a model of `RandomAccessIterator`
\tparam PointMap a model of `ReadablePropertyMap` whose value type is `GeomTraits::Point_3` \tparam PointMap a model of `ReadablePropertyMap` whose value type is `GeomTraits::Point_3`
\tparam cubic_nodes Boolean to enforce cubic nodes \tparam cubic_nodes Boolean to enforce cubic nodes
*/ */

View File

@ -125,7 +125,7 @@ public:
/// @{ /// @{
#ifndef DOXYGEN_RUNNING #ifndef DOXYGEN_RUNNING
static inline constexpr bool has_data = Orthtree_impl::has_Node_data<GeomTraits>::value; static inline constexpr bool has_data = Orthtree_impl::has_Node_data<GeomTraits>::value;
static inline constexpr bool supports_neighbor_search = true;// Orthtree_impl::has_Squared_distance_of_element<GeomTraits>::value; static inline constexpr bool supports_neighbor_search = Orthtree_impl::has_Squared_distance_of_element<GeomTraits>::value;
#else #else
static inline constexpr bool has_data = bool_value; ///< `true` if `GeomTraits` is a model of `OrthtreeTraitsWithData` and `false` otherwise. static inline constexpr bool has_data = bool_value; ///< `true` if `GeomTraits` is a model of `OrthtreeTraitsWithData` and `false` otherwise.
static inline constexpr bool supports_neighbor_search = bool_value; ///< `true` if `GeomTraits` is a model of `CollectionPartitioningOrthtreeTraits` and `false` otherwise. static inline constexpr bool supports_neighbor_search = bool_value; ///< `true` if `GeomTraits` is a model of `CollectionPartitioningOrthtreeTraits` and `false` otherwise.
@ -385,7 +385,8 @@ public:
\param max_depth deepest a tree is allowed to be (nodes at this depth will not be split). \param max_depth deepest a tree is allowed to be (nodes at this depth will not be split).
\param bucket_size maximum number of items a node is allowed to contain. \param bucket_size maximum number of items a node is allowed to contain.
*/ */
void refine(size_t max_depth = 10, size_t bucket_size = 20) { template<typename Orthtree = Self>
auto refine(size_t max_depth = 10, size_t bucket_size = 20) -> std::enable_if_t<Orthtree::has_data, void> {
refine(Orthtrees::Maximum_depth_and_maximum_contained_elements(max_depth, bucket_size)); refine(Orthtrees::Maximum_depth_and_maximum_contained_elements(max_depth, bucket_size));
} }
@ -681,10 +682,10 @@ public:
\warning Nearest neighbor searches requires `GeomTraits` to be a model of `CollectionPartitioningOrthtreeTraits`. \warning Nearest neighbor searches requires `GeomTraits` to be a model of `CollectionPartitioningOrthtreeTraits`.
*/ */
template<typename OutputIterator> template<typename OutputIterator, typename Orthtree = Self>
auto nearest_k_neighbors(const Point& query, auto nearest_k_neighbors(const Point& query,
std::size_t k, std::size_t k,
OutputIterator output) const -> std::enable_if_t<supports_neighbor_search, OutputIterator> { OutputIterator output) const -> std::enable_if_t<Orthtree::supports_neighbor_search, OutputIterator> {
Sphere query_sphere(query, (std::numeric_limits<FT>::max)()); Sphere query_sphere(query, (std::numeric_limits<FT>::max)());
CGAL_precondition(k > 0); CGAL_precondition(k > 0);
@ -704,8 +705,8 @@ public:
\warning Nearest neighbor searches requires `GeomTraits` to be a model of `CollectionPartitioningOrthtreeTraits`. \warning Nearest neighbor searches requires `GeomTraits` to be a model of `CollectionPartitioningOrthtreeTraits`.
*/ */
template<typename OutputIterator> template<typename OutputIterator, typename Orthtree = Self>
auto neighbors_within_radius(const Sphere& query, OutputIterator output) const -> std::enable_if_t<supports_neighbor_search, OutputIterator> { auto neighbors_within_radius(const Sphere& query, OutputIterator output) const -> std::enable_if_t<Orthtree::supports_neighbor_search, OutputIterator> {
return nearest_k_neighbors_within_radius(query, (std::numeric_limits<std::size_t>::max)(), output); return nearest_k_neighbors_within_radius(query, (std::numeric_limits<std::size_t>::max)(), output);
} }
@ -726,12 +727,12 @@ public:
\warning Nearest neighbor searches requires `GeomTraits` to be a model of `CollectionPartitioningOrthtreeTraits`. \warning Nearest neighbor searches requires `GeomTraits` to be a model of `CollectionPartitioningOrthtreeTraits`.
*/ */
template <typename OutputIterator> template <typename OutputIterator, typename Orthtree = Self>
auto nearest_k_neighbors_within_radius( auto nearest_k_neighbors_within_radius(
const Sphere& query, const Sphere& query,
std::size_t k, std::size_t k,
OutputIterator output OutputIterator output
) const -> std::enable_if_t<supports_neighbor_search, OutputIterator> { ) const -> std::enable_if_t<Orthtree::supports_neighbor_search, OutputIterator> {
CGAL_precondition(k > 0); CGAL_precondition(k > 0);
Sphere query_sphere = query; Sphere query_sphere = query;
@ -1298,13 +1299,13 @@ private: // functions :
return output; return output;
} }
template <typename Result> template <typename Result, typename Orthtree = Self>
auto nearest_k_neighbors_recursive( auto nearest_k_neighbors_recursive(
Sphere& search_bounds, Sphere& search_bounds,
Node_index node, Node_index node,
std::vector<Result>& results, std::vector<Result>& results,
std::size_t k, std::size_t k,
FT epsilon = 0) const -> std::enable_if_t<supports_neighbor_search> { FT epsilon = 0) const -> std::enable_if_t<Orthtree::supports_neighbor_search> {
// Check whether the node has children // Check whether the node has children
if (is_leaf(node)) { if (is_leaf(node)) {

View File

@ -85,7 +85,7 @@ public:
\ingroup PkgOrthtreeSplitPredicates \ingroup PkgOrthtreeSplitPredicates
\brief A class used to choose when a node should be split depending on the depth and the number of contained elements. \brief A class used to choose when a node should be split depending on the depth and the number of contained elements.
This predicate makes a note split if it contains more than a This predicate makes a node split if it contains more than a
certain number of items and if its depth is lower than a certain certain number of items and if its depth is lower than a certain
limit. limit.

View File

@ -89,11 +89,16 @@ struct Orthtree_traits_base {
using Adjacency = int; using Adjacency = int;
/// @} /// @}
auto construct_point_d_object() const { struct Construct_point_d {
return [](auto... Args) -> Point_d { template <typename ...Args, typename T = std::common_type_t<Args...>>
std::initializer_list<FT> args_list{Args...}; Point_d operator()(Args ...args) {
return Point_d{static_cast<int>(args_list.size()), args_list.begin(), args_list.end()}; std::initializer_list<T> args_list{ args... };
}; return Point_d{ static_cast<int>(args_list.size()), args_list.begin(), args_list.end() };
}
};
Construct_point_d construct_point_d_object() const {
return Construct_point_d();
} }
}; };
@ -115,7 +120,9 @@ struct Orthtree_traits_base<GeomTraits, 2> {
UP UP
}; };
auto construct_point_d_object() const { using Construct_point_d = Point_d(*)(const FT&, const FT&);
Construct_point_d construct_point_d_object() const {
return [](const FT& x, const FT& y) -> Point_d { return [](const FT& x, const FT& y) -> Point_d {
return {x, y}; return {x, y};
}; };
@ -153,7 +160,9 @@ struct Orthtree_traits_base<GeomTraits, 3> {
RIGHT_TOP_FRONT RIGHT_TOP_FRONT
}; };
auto construct_point_d_object() const { using Construct_point_d = Point_d(*)(const FT&, const FT&, const FT&);
Construct_point_d construct_point_d_object() const {
return [](const FT& x, const FT& y, const FT& z) -> Point_d { return [](const FT& x, const FT& y, const FT& z) -> Point_d {
return {x, y, z}; return {x, y, z};
}; };

View File

@ -96,11 +96,15 @@ public:
using Node_index = typename Base::Node_index; using Node_index = typename Base::Node_index;
using Node_data_element = typename std::iterator_traits<typename PointRange::iterator>::value_type; using Node_data_element = typename std::iterator_traits<typename PointRange::iterator>::value_type;
static_assert(std::is_same_v<typename std::iterator_traits<typename PointRange::iterator>::iterator_category, std::random_access_iterator_tag>);
Orthtree_traits_point( Orthtree_traits_point(
PointRange& points, PointRange& points,
PointMap point_map = PointMap() PointMap point_map = PointMap()
) : m_points(points), m_point_map(point_map) {} ) : m_points(points), m_point_map(point_map) {}
using Construct_root_node_bbox = typename Self::Bbox_d(*)();
auto construct_root_node_bbox_object() const { auto construct_root_node_bbox_object() const {
return [&]() -> typename Self::Bbox_d { return [&]() -> typename Self::Bbox_d {
@ -152,41 +156,65 @@ public:
}; };
} }
auto construct_root_node_contents_object() const { struct Construct_root_node_contents {
return [&]() -> typename Self::Node_data { PointRange& m_points;
return {m_points.begin(), m_points.end()}; Construct_root_node_contents(PointRange& points) : m_points(points) {}
}; typename Self::Node_data operator()() {
return { m_points.begin(), m_points.end() };
}
};
Construct_root_node_contents construct_root_node_contents_object() const {
return Construct_root_node_contents(m_points);
} }
auto distribute_node_contents_object() const { struct Distribute_node_contents {
return [&](Node_index n, Tree& tree, const typename Self::Point_d& center) { const PointMap m_point_map;
Distribute_node_contents(const PointMap& point_map) : m_point_map(point_map) {}
void operator()(Node_index n, Tree& tree, const typename Self::Point_d& center) {
CGAL_precondition(!tree.is_leaf(n)); CGAL_precondition(!tree.is_leaf(n));
reassign_points(tree, m_point_map, n, center, tree.data(n)); reassign_points(tree, m_point_map, n, center, tree.data(n));
}; };
};
Distribute_node_contents distribute_node_contents_object() const {
return Distribute_node_contents(m_point_map);
} }
auto construct_sphere_d_object() const { using Construct_sphere_d = typename Self::Sphere_d(*)(const typename Self::Point_d&, const typename Self::FT&);
Construct_sphere_d construct_sphere_d_object() const {
return [](const typename Self::Point_d& center, const typename Self::FT& squared_radius) -> typename Self::Sphere_d { return [](const typename Self::Point_d& center, const typename Self::FT& squared_radius) -> typename Self::Sphere_d {
return typename Self::Sphere_d(center, squared_radius); return typename Self::Sphere_d(center, squared_radius);
}; };
} }
auto construct_center_d_object() const { using Construct_center_d = typename Self::Point_d(*)(const typename Self::Sphere_d&);
Construct_center_d construct_center_d_object() const {
return [](const typename Self::Sphere_d& sphere) -> typename Self::Point_d { return [](const typename Self::Sphere_d& sphere) -> typename Self::Point_d {
return sphere.center(); return sphere.center();
}; };
} }
auto compute_squared_radius_d_object() const { using Compute_squared_radius_d = typename Self::FT(*)(const typename Self::Sphere_d&);
Compute_squared_radius_d compute_squared_radius_d_object() const {
return [](const typename Self::Sphere_d& sphere) -> typename Self::FT { return [](const typename Self::Sphere_d& sphere) -> typename Self::FT {
return sphere.squared_radius(); return sphere.squared_radius();
}; };
} }
auto squared_distance_of_element_object() const { struct Squared_distance_of_element {
return [&](const Node_data_element& index, const typename Self::Point_d& point) -> typename Self::FT { const PointMap m_point_map;
Squared_distance_of_element(const PointMap& point_map) : m_point_map(point_map) {}
typename Self::FT operator()(const Node_data_element& index, const typename Self::Point_d& point) {
return CGAL::squared_distance(get(m_point_map, index), point); return CGAL::squared_distance(get(m_point_map, index), point);
}; };
};
Squared_distance_of_element squared_distance_of_element_object() const {
return Squared_distance_of_element(m_point_map);
} }
PointRange& m_points; PointRange& m_points;