From 4228eef10af539751ab0b7f698f63a7e42864512 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Tue, 21 Jan 2025 11:51:03 +0100 Subject: [PATCH 01/13] stop splitting nodes if the contained points are only duplicates --- Spatial_searching/include/CGAL/Kd_tree.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Spatial_searching/include/CGAL/Kd_tree.h b/Spatial_searching/include/CGAL/Kd_tree.h index 350b9f533d8e..2d47eab2d12e 100644 --- a/Spatial_searching/include/CGAL/Kd_tree.h +++ b/Spatial_searching/include/CGAL/Kd_tree.h @@ -196,7 +196,7 @@ class Kd_tree { if (try_parallel_internal_node_creation (nh, c, c_low, tag)) return; - if (c_low.size() > split.bucket_size()) + if (c_low.size() > split.bucket_size() && c_low.max_tight_spread() > 0) { nh->lower_ch = new_internal_node(); create_internal_node (nh->lower_ch, c_low, tag); @@ -204,7 +204,7 @@ class Kd_tree { else nh->lower_ch = create_leaf_node(c_low); - if (c.size() > split.bucket_size()) + if (c.size() > split.bucket_size() && c.max_tight_spread() > 0) { nh->upper_ch = new_internal_node(); create_internal_node (nh->upper_ch, c, tag); @@ -341,7 +341,7 @@ class Kd_tree { Point_container c(dim_, data.begin(), data.end(),traits_); bbox = new Kd_tree_rectangle(c.bounding_box()); - if (c.size() <= split.bucket_size()){ + if (c.size() <= split.bucket_size() || c.max_tight_spread() == 0){ tree_root = create_leaf_node(c); }else { tree_root = new_internal_node(); From 5b28489b16c4312ad781f50b495dfbea50399fb2 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 23 Jan 2025 11:00:44 +0100 Subject: [PATCH 02/13] fixed test_pmp_distance --- .../test/Polygon_mesh_processing/test_pmp_distance.cpp | 1 + Spatial_searching/include/CGAL/Kd_tree.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp index 5ecd9b9530b4..1236f1b8d094 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp @@ -22,6 +22,7 @@ struct Custom_traits_Hausdorff FT operator+(FT)const{return FT();} FT operator*(FT)const{return FT();} bool operator<=(FT)const{return false;} + bool operator==(FT)const{return false;} bool operator>=(FT)const{return false;} bool operator!=(FT)const{return false;} bool operator<(FT)const{return false;} diff --git a/Spatial_searching/include/CGAL/Kd_tree.h b/Spatial_searching/include/CGAL/Kd_tree.h index 2d47eab2d12e..a1d1e670d2b0 100644 --- a/Spatial_searching/include/CGAL/Kd_tree.h +++ b/Spatial_searching/include/CGAL/Kd_tree.h @@ -196,7 +196,7 @@ class Kd_tree { if (try_parallel_internal_node_creation (nh, c, c_low, tag)) return; - if (c_low.size() > split.bucket_size() && c_low.max_tight_spread() > 0) + if (c_low.size() > split.bucket_size() && !CGAL::is_zero(c_low.max_tight_spread())) { nh->lower_ch = new_internal_node(); create_internal_node (nh->lower_ch, c_low, tag); @@ -204,7 +204,7 @@ class Kd_tree { else nh->lower_ch = create_leaf_node(c_low); - if (c.size() > split.bucket_size() && c.max_tight_spread() > 0) + if (c.size() > split.bucket_size() && !CGAL::is_zero(c.max_tight_spread())) { nh->upper_ch = new_internal_node(); create_internal_node (nh->upper_ch, c, tag); @@ -341,7 +341,7 @@ class Kd_tree { Point_container c(dim_, data.begin(), data.end(),traits_); bbox = new Kd_tree_rectangle(c.bounding_box()); - if (c.size() <= split.bucket_size() || c.max_tight_spread() == 0){ + if (c.size() <= split.bucket_size() || CGAL::is_zero(c.max_tight_spread())){ tree_root = create_leaf_node(c); }else { tree_root = new_internal_node(); From 48569ff99c49105f9f74a39c6de23058cfd41a72 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 30 Jan 2025 16:55:51 +0100 Subject: [PATCH 03/13] prevent linearity in median splitters due to duplicated points --- .../include/CGAL/Point_container.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Spatial_searching/include/CGAL/Point_container.h b/Spatial_searching/include/CGAL/Point_container.h index eb96024348e2..c2218eab6b89 100644 --- a/Spatial_searching/include/CGAL/Point_container.h +++ b/Spatial_searching/include/CGAL/Point_container.h @@ -419,6 +419,24 @@ class Point_container { typename Traits::Cartesian_const_iterator_d mpit = construct_it((*(*mid))); FT val1 = *(mpit+split_coord); + + // Avoid using the low coord value as it results in an empty split + if (val1 == tbox.min_coord(split_coord)) { + iterator it = std::min_element(mid, end(), [=](const Point_d* a, const Point_d* b) -> bool { + FT a_c = *(construct_it(*a) + split_coord); + FT b_c = *(construct_it(*b) + split_coord); + + if (a_c == val1) + return false; + + if (b_c == val1) + return true; + + return a_c < b_c; + }); + return *(construct_it(**it) + split_coord); + } + mid++; mpit = construct_it((*(*mid))); FT val2 = *(mpit+split_coord); From 408730b30a6c1f76158e4acd796ea8fe03c98af7 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Wed, 5 Feb 2025 13:29:02 +0100 Subject: [PATCH 04/13] Median_of_rectangle: prevent using largest span of bbox as split axis when actual spread is 0 --- Spatial_searching/include/CGAL/Splitters.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Spatial_searching/include/CGAL/Splitters.h b/Spatial_searching/include/CGAL/Splitters.h index 057c27aae43d..437d0f6b09d9 100644 --- a/Spatial_searching/include/CGAL/Splitters.h +++ b/Spatial_searching/include/CGAL/Splitters.h @@ -236,7 +236,9 @@ namespace CGAL { void operator() (Separator& sep, Container& c0, Container& c1) const { - sep = Separator(c0.max_span_coord(),FT(0)); + if (!CGAL::is_zero(c0.max_spread())) + sep = Separator(c0.max_span_coord(),FT(0)); + else sep = Separator(c0.max_tight_span_coord(), FT(0)); sep.set_cutting_value(c0.median(sep.cutting_dimension())); c0.split(c1,sep,true); } From 61ab2d3bfd47bf4dc37c8e3021adc821cab20b24 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Wed, 5 Feb 2025 13:47:31 +0100 Subject: [PATCH 05/13] bugfix --- Spatial_searching/include/CGAL/Point_container.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Spatial_searching/include/CGAL/Point_container.h b/Spatial_searching/include/CGAL/Point_container.h index c2218eab6b89..2fc15680bc3a 100644 --- a/Spatial_searching/include/CGAL/Point_container.h +++ b/Spatial_searching/include/CGAL/Point_container.h @@ -438,6 +438,9 @@ class Point_container { } mid++; + if (mid == end()) + return val1; + mpit = construct_it((*(*mid))); FT val2 = *(mpit+split_coord); return (val1+val2)/FT(2); From 9f049bd4256a2d70c02e8d4712aa9c6c1a47f042 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Wed, 5 Feb 2025 14:40:43 +0100 Subject: [PATCH 06/13] added missing header --- Spatial_searching/include/CGAL/Splitters.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Spatial_searching/include/CGAL/Splitters.h b/Spatial_searching/include/CGAL/Splitters.h index 437d0f6b09d9..42a5a9eead8f 100644 --- a/Spatial_searching/include/CGAL/Splitters.h +++ b/Spatial_searching/include/CGAL/Splitters.h @@ -19,6 +19,7 @@ #include +#include #include #include From 531e612e5fff1aa442c7fbea8ac90c9d54e3d0f3 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 6 Feb 2025 10:34:41 +0100 Subject: [PATCH 07/13] fix warnings --- Spatial_searching/include/CGAL/Kd_tree_rectangle.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Spatial_searching/include/CGAL/Kd_tree_rectangle.h b/Spatial_searching/include/CGAL/Kd_tree_rectangle.h index ef2f13476d93..ba111699f079 100644 --- a/Spatial_searching/include/CGAL/Kd_tree_rectangle.h +++ b/Spatial_searching/include/CGAL/Kd_tree_rectangle.h @@ -111,11 +111,7 @@ namespace CGAL { explicit Kd_tree_rectangle(const Kd_tree_rectangle& r) - : max_span_coord_(r.max_span_coord_) - { - lower_ = r.lower_; - upper_ = r.upper_; - } + : lower_(r.lower_), upper_(r.upper_), max_span_coord_(r.max_span_coord_) {} template void update_from_point_pointers(PointPointerIter begin, From 88163cc512defc18d0be1ac221fca8fcd289deda Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 6 Feb 2025 13:03:41 +0100 Subject: [PATCH 08/13] typo fix --- Spatial_searching/doc/Spatial_searching/CGAL/Kd_tree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_searching/doc/Spatial_searching/CGAL/Kd_tree.h b/Spatial_searching/doc/Spatial_searching/CGAL/Kd_tree.h index b36cc8fb9733..c83d721efa8a 100644 --- a/Spatial_searching/doc/Spatial_searching/CGAL/Kd_tree.h +++ b/Spatial_searching/doc/Spatial_searching/CGAL/Kd_tree.h @@ -20,7 +20,7 @@ lot of cache misses, leading to non-optimal performance. This is the case for example when indices are stored inside the tree, or to a lesser extent when the points coordinates are stored in a dynamically allocated array (e.g., `Epick_d` with dynamic -dimension) — we says "to a lesser extent" because the points +dimension) — we say "to a lesser extent" because the points are re-created by the kd-tree in a cache-friendly order after its construction, so the coordinates are more likely to be stored in a near-optimal order on the heap. When `EnablePointsCache` is set to `Tag_true`, the points From 636721e7f5cde9c4e04d6890b17fe5ab6e1df127 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 6 Feb 2025 13:09:58 +0100 Subject: [PATCH 09/13] doc typo fix --- Spatial_searching/doc/Spatial_searching/Spatial_searching.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt b/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt index afa3a3eb0ca8..f4e3d7832a50 100644 --- a/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt +++ b/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt @@ -127,7 +127,7 @@ which is the case for point queries. The following two classes implement the standard search strategy for orthogonal distances like the weighted Minkowski distance. The second one is a specialization for incremental neighbor -searching and distance browsing. Both require extendes nodes. +searching and distance browsing. Both require extended nodes. `Orthogonal_k_neighbor_search` From fc08cf5fb253d5b87f9a37aaa4f09756c75e38e7 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Mon, 10 Feb 2025 14:54:03 +0100 Subject: [PATCH 10/13] switching to number_utils.h instead of basic.h --- Spatial_searching/include/CGAL/Splitters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_searching/include/CGAL/Splitters.h b/Spatial_searching/include/CGAL/Splitters.h index 42a5a9eead8f..659c0954a6af 100644 --- a/Spatial_searching/include/CGAL/Splitters.h +++ b/Spatial_searching/include/CGAL/Splitters.h @@ -19,7 +19,7 @@ #include -#include +#include #include #include From 934054c9ba68c0b96ec79d6861a15dbcfa5504b0 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Mon, 10 Feb 2025 17:15:56 +0100 Subject: [PATCH 11/13] documenting that Median_of_rectangle splitter is robust bugfix --- Spatial_searching/include/CGAL/Splitters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_searching/include/CGAL/Splitters.h b/Spatial_searching/include/CGAL/Splitters.h index 659c0954a6af..387144bcf8a3 100644 --- a/Spatial_searching/include/CGAL/Splitters.h +++ b/Spatial_searching/include/CGAL/Splitters.h @@ -237,7 +237,7 @@ namespace CGAL { void operator() (Separator& sep, Container& c0, Container& c1) const { - if (!CGAL::is_zero(c0.max_spread())) + if (!CGAL::is_zero(c0.tight_bounding_box().max_coord(c0.max_span_coord()) - c0.tight_bounding_box().min_coord(c0.max_span_coord()))) sep = Separator(c0.max_span_coord(),FT(0)); else sep = Separator(c0.max_tight_span_coord(), FT(0)); sep.set_cutting_value(c0.median(sep.cutting_dimension())); From 295f6488beb573341bb02c97d6849af7e40ffd4e Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Mon, 10 Feb 2025 17:15:56 +0100 Subject: [PATCH 12/13] documenting that Median_of_rectangle splitter is robust bugfix --- .../doc/Spatial_searching/Spatial_searching.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt b/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt index f4e3d7832a50..9ccd82722ed4 100644 --- a/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt +++ b/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt @@ -175,9 +175,13 @@ because in general the query time will be less than using the default value. Instead of using the default splitting rule `Sliding_midpoint` described below, a user may, depending upon the data, select one from the following splitting rules, -which determine how a separating hyperplane is computed. Every splitter has +which determine how a separating hyperplane is computed. Some splitter have degenerated worst cases, which may lead to a linear tree and a stack overflow. Switching the splitting rule to one of a different kind will solve the problem. +The `Median_of_rectangle` and `Median_of_max_spread` are robust sliders that will +neither lead to a linear tree nor to a stack overflow. The `Median_of_rectangle` +splitter will detect if the data in a node is degenerated and applies the +`Median_of_max_spread` rule for that node to avoid a linear tree.
From fc254c3c03ffe39e9deaa66a14e0ff261a7d17cd Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Mon, 24 Feb 2025 14:47:09 +0100 Subject: [PATCH 13/13] fix warning --- Spatial_searching/include/CGAL/Point_container.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Spatial_searching/include/CGAL/Point_container.h b/Spatial_searching/include/CGAL/Point_container.h index 2fc15680bc3a..07ad4053079c 100644 --- a/Spatial_searching/include/CGAL/Point_container.h +++ b/Spatial_searching/include/CGAL/Point_container.h @@ -232,8 +232,9 @@ class Point_container { // building the container from a sequence of Point_d* Point_container(const int d, iterator begin, iterator end,const Traits& traits_) : - traits(traits_),m_b(begin), m_e(end), bbox(d, begin, end,traits.construct_cartesian_const_iterator_d_object()), tbox(bbox) + traits(traits_),m_b(begin), m_e(end), bbox(d, begin, end,traits.construct_cartesian_const_iterator_d_object()), tbox() { + tbox = bbox; built_coord = max_span_coord(); }