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.
\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 cubic_nodes Boolean to enforce cubic nodes
*/

View File

@ -125,7 +125,7 @@ public:
/// @{
#ifndef DOXYGEN_RUNNING
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
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.
@ -385,7 +385,8 @@ public:
\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.
*/
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));
}
@ -681,10 +682,10 @@ public:
\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,
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)());
CGAL_precondition(k > 0);
@ -704,8 +705,8 @@ public:
\warning Nearest neighbor searches requires `GeomTraits` to be a model of `CollectionPartitioningOrthtreeTraits`.
*/
template<typename OutputIterator>
auto neighbors_within_radius(const Sphere& query, OutputIterator output) const -> std::enable_if_t<supports_neighbor_search, OutputIterator> {
template<typename OutputIterator, typename Orthtree = Self>
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);
}
@ -726,12 +727,12 @@ public:
\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(
const Sphere& query,
std::size_t k,
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);
Sphere query_sphere = query;
@ -1298,13 +1299,13 @@ private: // functions :
return output;
}
template <typename Result>
template <typename Result, typename Orthtree = Self>
auto nearest_k_neighbors_recursive(
Sphere& search_bounds,
Node_index node,
std::vector<Result>& results,
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
if (is_leaf(node)) {

View File

@ -85,7 +85,7 @@ public:
\ingroup PkgOrthtreeSplitPredicates
\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
limit.

View File

@ -89,11 +89,16 @@ struct Orthtree_traits_base {
using Adjacency = int;
/// @}
auto construct_point_d_object() const {
return [](auto... Args) -> Point_d {
std::initializer_list<FT> args_list{Args...};
struct Construct_point_d {
template <typename ...Args, typename T = std::common_type_t<Args...>>
Point_d operator()(Args ...args) {
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
};
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 {x, y};
};
@ -153,7 +160,9 @@ struct Orthtree_traits_base<GeomTraits, 3> {
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 {x, y, z};
};

View File

@ -96,11 +96,15 @@ public:
using Node_index = typename Base::Node_index;
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(
PointRange& points,
PointMap point_map = PointMap()
) : m_points(points), m_point_map(point_map) {}
using Construct_root_node_bbox = typename Self::Bbox_d(*)();
auto construct_root_node_bbox_object() const {
return [&]() -> typename Self::Bbox_d {
@ -152,41 +156,65 @@ public:
};
}
auto construct_root_node_contents_object() const {
return [&]() -> typename Self::Node_data {
struct Construct_root_node_contents {
PointRange& m_points;
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 {
return [&](Node_index n, Tree& tree, const typename Self::Point_d& center) {
struct Distribute_node_contents {
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));
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 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 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 sphere.squared_radius();
};
}
auto squared_distance_of_element_object() const {
return [&](const Node_data_element& index, const typename Self::Point_d& point) -> typename Self::FT {
struct Squared_distance_of_element {
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);
};
};
Squared_distance_of_element squared_distance_of_element_object() const {
return Squared_distance_of_element(m_point_map);
}
PointRange& m_points;