From b5bf17918190bd55cc45ebef20919672796ce857 Mon Sep 17 00:00:00 2001 From: IasonManolas Date: Tue, 4 Aug 2026 10:30:43 +0300 Subject: [PATCH 01/10] Tetrahedral_remeshing: memoize surface_patch_index over the collapse scan surface_patch_index(v) walks v's whole incident-facet star with no early exit. can_be_collapsed() calls it for both endpoints of every non-boundary edge, and collapse_short_edges()'s initial scan over all finite edges reaches the same vertex once per incident edge, so its star gets walked as many times as it has edges. The scan does not modify the mesh, so the first answer for a vertex stays valid for the rest of it: a cache scoped to the scan replaces the repeated walks with a hash lookup after the first. The cache is opt-in via a pointer defaulting to null, since can_be_collapsed() is also called after individual collapses (when the cache would be stale) to re-evaluate newly-incident edges. Byte-identical: same values, same order, so the same edges enter the bimap in the same sequence. --- .../internal/collapse_short_edges.h | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index 6968dc5e5ca3..87ca280bbf7e 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -1194,11 +1194,34 @@ typename C3t3::Vertex_handle collapse_edge(typename C3t3::Edge& edge, return Vertex_handle(); } +template +using Vertex_patch_cache = std::unordered_map< + typename C3T3::Vertex_handle, + std::optional >; + +// surface_patch_index(v) walks v's whole incident-facet star. The initial +// scan over all finite edges in collapse_short_edges() reaches the same +// vertex once per incident edge, and the scan does not modify the mesh, so +// the first answer stays valid for the rest of it. +template +const std::optional& +cached_surface_patch_index(const typename C3T3::Vertex_handle v, + const C3T3& c3t3, + Vertex_patch_cache& cache) +{ + const auto it = cache.find(v); + if (it != cache.end()) + return it->second; + + return cache.emplace(v, surface_patch_index(v, c3t3)).first->second; +} + template auto can_be_collapsed(const typename C3T3::Edge& e, const C3T3& c3t3, const bool protect_boundaries, - CellSelector cell_selector) + CellSelector cell_selector, + Vertex_patch_cache* patch_cache = nullptr) { struct Collapsible { @@ -1224,8 +1247,12 @@ auto can_be_collapsed(const typename C3T3::Edge& e, if(v0->in_dimension() != 3 && v1->in_dimension() != 3) { - const auto patch_v0 = surface_patch_index(v0, c3t3); - const auto patch_v1 = surface_patch_index(v1, c3t3); + const auto patch_v0 = patch_cache + ? cached_surface_patch_index(v0, c3t3, *patch_cache) + : surface_patch_index(v0, c3t3); + const auto patch_v1 = patch_cache + ? cached_surface_patch_index(v1, c3t3, *patch_cache) + : surface_patch_index(v1, c3t3); if(patch_v0 != std::nullopt && patch_v1 != std::nullopt && patch_v0 != patch_v1) return Collapsible{false, boundary}; @@ -1268,9 +1295,11 @@ void collapse_short_edges(C3T3& c3t3, //collect long edges Boost_bimap short_edges; + Vertex_patch_cache patch_cache; for (const Edge& e : tr.finite_edges()) { - auto [collapsible, boundary] = can_be_collapsed(e, c3t3, protect_boundaries, cell_selector); + auto [collapsible, boundary] + = can_be_collapsed(e, c3t3, protect_boundaries, cell_selector, &patch_cache); if (!collapsible) continue; From f02a55a67f35e90c54520a1d3683caa6dbe00bbe Mon Sep 17 00:00:00 2001 From: IasonManolas Date: Tue, 4 Aug 2026 10:32:31 +0300 Subject: [PATCH 02/10] Tetrahedral_remeshing: settle a collapse's ring test once for all three attempts collapse_edge() calls is_valid_collapse(edge, type, new_pos, c3t3), which walks the star of v0 and/or v1 into a heap vector, runs an orientation predicate per cell, and then runs a ring test over the cells around the edge. On failure with TO_MIDPOINT the whole thing repeats for TO_V0 and again for TO_V1. Further down, the angle and manifold tests build cells_to_insert from those same two stars a fourth time. The ring test depends on neither the collapse type nor the new position, so it decides all three attempts at once: it is hoisted ahead of the orientation cascade, since it is also the cheap one (one cell circulation, no allocation, no orientation predicate). Each star is now collected once, lazily, into a small_vector and handed to every attempt and to cells_to_insert. cells_to_insert is still filled one handle at a time in the original walk order, so its iteration order is unchanged. Byte-identical: same predicates, same order of evaluation, only the redundant walks are removed. --- .../internal/collapse_short_edges.h | 87 ++++++++++++++++--- 1 file changed, 77 insertions(+), 10 deletions(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index 87ca280bbf7e..bf61f58e664e 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -428,6 +428,33 @@ bool is_valid_collapse(const typename C3t3::Edge& edge, return true; } +// The cells of `star` keep a positive orientation once `v_moved` is at +// `new_pos`. Cells that also have `v_other` disappear with the collapse. +template +bool collapse_keeps_orientations(const CellRange& star, + const typename C3t3::Vertex_handle v_moved, + const typename C3t3::Vertex_handle v_other, + const typename C3t3::Triangulation::Point& new_pos) +{ + typedef typename C3t3::Triangulation::Point Point; + + for (const auto& ch : star) + { + if (ch->has_vertex(v_other)) + continue; + + std::array pts = { ch->vertex(0)->point(), + ch->vertex(1)->point(), + ch->vertex(2)->point(), + ch->vertex(3)->point() }; + pts[ch->index(v_moved)] = new_pos; + if (CGAL::orientation(point(pts[0]), point(pts[1]), point(pts[2]), point(pts[3])) + != CGAL::POSITIVE) + return false; + } + return true; +} + template bool is_valid_collapse(const typename C3t3::Edge& edge, const Collapse_type& collapse_type, @@ -1122,17 +1149,60 @@ typename C3t3::Vertex_handle collapse_edge(typename C3t3::Edge& edge, new_pos = Point(CGAL::midpoint(point(v0->point()), point(v1->point()))); } - if (!is_valid_collapse(edge, collapse_type, new_pos, c3t3)) + // The ring test depends on neither the collapse type nor the new position, + // so it settles all three attempts below at once - and it is the cheap one: + // one cell circulation, against a star walk plus an orientation predicate + // per cell of the star. + if (!is_valid_collapse(edge, c3t3)) + return Vertex_handle(); + + // Each attempt below walks the star of v0 and/or of v1, and so do the angle + // and manifold tests further down. The mesh is not touched in between, so + // each star is walked once here and handed to all of them. + boost::container::small_vector star_v0, star_v1; + bool has_star_v0 = false; + bool has_star_v1 = false; + const auto star_of_v0 = [&]() -> const boost::container::small_vector& + { + if (!has_star_v0) + { + c3t3.triangulation().finite_incident_cells(v0, std::back_inserter(star_v0)); + has_star_v0 = true; + } + return star_v0; + }; + const auto star_of_v1 = [&]() -> const boost::container::small_vector& + { + if (!has_star_v1) + { + c3t3.triangulation().finite_incident_cells(v1, std::back_inserter(star_v1)); + has_star_v1 = true; + } + return star_v1; + }; + + const auto orientations_ok = [&](const Collapse_type ct, const Point& pos) + { + if ((ct == TO_V1 || ct == TO_MIDPOINT) + && !collapse_keeps_orientations(star_of_v0(), v0, v1, pos)) + return false; + if ((ct == TO_V0 || ct == TO_MIDPOINT) + && !collapse_keeps_orientations(star_of_v1(), v1, v0, pos)) + return false; + return true; + }; + + if (!orientations_ok(collapse_type, new_pos)) { if (collapse_type == TO_MIDPOINT) { // with TO_MIDPOINT, we are authorized to test TO_V0 and TO_V1 - if (is_valid_collapse(edge, TO_V0, v0->point(), c3t3)) + if (orientations_ok(TO_V0, v0->point())) { collapse_type = TO_V0; new_pos = v0->point(); } - else if (is_valid_collapse(edge, TO_V1, v1->point(), c3t3)) + else if (orientations_ok(TO_V1, v1->point())) { collapse_type = TO_V1; new_pos = v1->point(); @@ -1163,14 +1233,11 @@ typename C3t3::Vertex_handle collapse_edge(typename C3t3::Edge& edge, edge.first->vertex(edge.second), edge.first->vertex(edge.third))); - Vertex_handle v0_init = edge.first->vertex(edge.second); - Vertex_handle v1_init = edge.first->vertex(edge.third); - std::unordered_set cells_to_insert; - c3t3.triangulation().finite_incident_cells(v0_init, - std::inserter(cells_to_insert, cells_to_insert.end())); - c3t3.triangulation().finite_incident_cells(v1_init, - std::inserter(cells_to_insert, cells_to_insert.end())); + for (const Cell_handle ch : star_of_v0()) + cells_to_insert.insert(ch); + for (const Cell_handle ch : star_of_v1()) + cells_to_insert.insert(ch); if(!is_cells_set_manifold(c3t3, cells_to_insert)) return Vertex_handle(); From d6247353ce9bf4758a3d9fe35730fbb4797f2834 Mon Sep 17 00:00:00 2001 From: IasonManolas Date: Tue, 4 Aug 2026 10:43:13 +0300 Subject: [PATCH 03/10] Tetrahedral_remeshing: read incident_subdomains straight off the star walk incident_subdomains(v) collected the whole incident-cell star into a heap vector and then read nothing from it but subdomain_index(). Emitting straight to the output iterator as the star is walked removes one heap allocation per call on the hottest star-walk site in the profile (nb_incident_subdomains <- topology_test <- collapse_edge). Identical emission order, so byte-identical. --- .../internal/tetrahedral_remeshing_helpers.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h index 621f2dc2c5a3..60de516412fb 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -892,11 +893,14 @@ OutputIterator incident_subdomains(const typename C3t3::Vertex_handle v, OutputIterator oit) { typedef typename C3t3::Triangulation::Cell_handle Cell_handle; - std::vector cells; - c3t3.triangulation().incident_cells(v, std::back_inserter(cells)); - for (std::size_t i = 0; i < cells.size(); ++i) - *oit++ = cells[i]->subdomain_index(); + // only the subdomain index of each cell of the star is wanted, so the star + // is read as it is walked rather than collected first + c3t3.triangulation().incident_cells(v, + boost::make_function_output_iterator([&](const Cell_handle c) + { + *oit++ = c->subdomain_index(); + })); return oit; } From aa1a105e2d4607614c1a7d5669af359aca324dd2 Mon Sep 17 00:00:00 2001 From: IasonManolas Date: Tue, 4 Aug 2026 10:56:01 +0300 Subject: [PATCH 04/10] Tetrahedral_remeshing: topology_test: stop counting all subdomains around a vertex nb_incident_subdomains(v, c3t3) > 1 asks for a count when it only needs "is there a second index". The count walks every cell around v to build a set of distinct subdomain indices; the question only needs the walk to reach a second index, which on a vertex lying on a surface happens after a handful of cells rather than the whole star. has_several_incident_subdomains() reuses the TDS's own conflict-mark traversal - the same one TDS_3::incident_cells_3() performs - and stops as soon as a second index appears. Same boolean, so byte-identical by construction. The marks are shared state, so the function must not be called from inside another marking traversal; the collapse guard chain that calls it is not. --- .../internal/tetrahedral_remeshing_helpers.h | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h index 60de516412fb..999174b34e72 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h @@ -976,6 +976,63 @@ std::size_t nb_incident_subdomains(const typename C3t3::Vertex_handle v, return indices.size(); } +// `nb_incident_subdomains(v, c3t3) > 1`, without counting the whole star. The +// traversal is the one `TDS_3::incident_cells_3()` performs - from v's cell, +// across the facets that contain v, marking cells as it goes - so it sees the +// same cells in the same order, and stops as soon as a second index appears. +// The marks are the TDS's own conflict flags and are cleared before +// returning, so this must not be called from inside another marking +// traversal; the collapse guard chain that calls it is not. +template +bool has_several_incident_subdomains(const typename C3t3::Vertex_handle v, + const C3t3& c3t3) +{ + typedef typename C3t3::Triangulation::Cell_handle Cell_handle; + CGAL_USE(c3t3); + + const Cell_handle start = v->cell(); + const auto si0 = start->subdomain_index(); + + boost::container::small_vector marked; + boost::container::small_vector to_visit; + + start->tds_data().mark_in_conflict(); + marked.push_back(start); + to_visit.push_back(start); + + bool several = false; + while (!to_visit.empty()) + { + const Cell_handle c = to_visit.back(); + to_visit.pop_back(); + + if (c->subdomain_index() != si0) + { + several = true; + break; + } + + for (int i = 0; i < 4; ++i) + { + if (c->vertex(i) == v) + continue; + + const Cell_handle n = c->neighbor(i); + if (!n->tds_data().is_clear()) + continue; + + n->tds_data().mark_in_conflict(); + marked.push_back(n); + to_visit.push_back(n); + } + } + + for (const Cell_handle c : marked) + c->tds_data().clear(); + + return several; +} + template std::size_t nb_incident_subdomains(const typename C3t3::Edge& e, const C3t3& c3t3) @@ -1312,7 +1369,7 @@ bool topology_test(const typename C3t3::Edge& edge, for (int i = 1; i < 4; i++) { Vertex_handle vi = f.first->vertex((f.second + i) % 4); - if (vi != v0 && vi != v1 && nb_incident_subdomains(vi, c3t3) > 1) + if (vi != v0 && vi != v1 && has_several_incident_subdomains(vi, c3t3)) { if (is_edge_in_complex(v0, vi, c3t3) && is_edge_in_complex(v1, vi, c3t3)) From 6daeb1fa85134e52e4a7956a5cacdd1f01f1ec39 Mon Sep 17 00:00:00 2001 From: Iasonas Manolas Date: Thu, 6 Aug 2026 16:24:06 +0300 Subject: [PATCH 05/10] Update Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h using Geom_traits::Point_3 instead of Point Co-authored-by: Jane Tournois --- .../CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index bf61f58e664e..742c0d73c05b 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -434,7 +434,7 @@ template bool collapse_keeps_orientations(const CellRange& star, const typename C3t3::Vertex_handle v_moved, const typename C3t3::Vertex_handle v_other, - const typename C3t3::Triangulation::Point& new_pos) + const typename C3t3::Triangulation::Geom_traits::Point_3& new_pos) { typedef typename C3t3::Triangulation::Point Point; From c984bcb10b6823a718c5286484f0cf2873bc6282 Mon Sep 17 00:00:00 2001 From: Iasonas Manolas Date: Thu, 6 Aug 2026 16:24:48 +0300 Subject: [PATCH 06/10] Update Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h removed redundant point() Co-authored-by: Jane Tournois --- .../CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index 742c0d73c05b..5554f4c3e733 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -448,7 +448,7 @@ bool collapse_keeps_orientations(const CellRange& star, ch->vertex(2)->point(), ch->vertex(3)->point() }; pts[ch->index(v_moved)] = new_pos; - if (CGAL::orientation(point(pts[0]), point(pts[1]), point(pts[2]), point(pts[3])) + if (CGAL::orientation(pts[0], pts[1], pts[2], pts[3])) != CGAL::POSITIVE) return false; } From 1484fba2d5013f7bce99dfc0b00755eb3064cd19 Mon Sep 17 00:00:00 2001 From: Iasonas Manolas Date: Thu, 6 Aug 2026 16:38:14 +0300 Subject: [PATCH 07/10] Update Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h Co-authored-by: Jane Tournois --- .../CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index 5554f4c3e733..5cb782525a4c 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -436,7 +436,7 @@ bool collapse_keeps_orientations(const CellRange& star, const typename C3t3::Vertex_handle v_other, const typename C3t3::Triangulation::Geom_traits::Point_3& new_pos) { - typedef typename C3t3::Triangulation::Point Point; + typedef typename C3t3::Triangulation::Geom_traits::Point_3 Point; for (const auto& ch : star) { From 2eaad9722abadb7e42ff9d97bcbf5c731df5334b Mon Sep 17 00:00:00 2001 From: Iasonas Manolas Date: Thu, 6 Aug 2026 16:38:26 +0300 Subject: [PATCH 08/10] Update Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h Co-authored-by: Jane Tournois --- .../Tetrahedral_remeshing/internal/collapse_short_edges.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index 5cb782525a4c..3baccd991692 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -443,10 +443,10 @@ bool collapse_keeps_orientations(const CellRange& star, if (ch->has_vertex(v_other)) continue; - std::array pts = { ch->vertex(0)->point(), - ch->vertex(1)->point(), - ch->vertex(2)->point(), - ch->vertex(3)->point() }; + std::array pts = { point(ch->vertex(0)->point()), + point(ch->vertex(1)->point()), + point(ch->vertex(2)->point()), + point(ch->vertex(3)->point()) }; pts[ch->index(v_moved)] = new_pos; if (CGAL::orientation(pts[0], pts[1], pts[2], pts[3])) != CGAL::POSITIVE) From 47fb237b36bbdec3673d0b5a194a94f5c6a9117b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 7 Aug 2026 10:17:19 +0200 Subject: [PATCH 09/10] fix compilation of examples --- .../Tetrahedral_remeshing/internal/collapse_short_edges.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index 3baccd991692..955c4dfe1190 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -448,8 +448,7 @@ bool collapse_keeps_orientations(const CellRange& star, point(ch->vertex(2)->point()), point(ch->vertex(3)->point()) }; pts[ch->index(v_moved)] = new_pos; - if (CGAL::orientation(pts[0], pts[1], pts[2], pts[3])) - != CGAL::POSITIVE) + if (CGAL::orientation(pts[0], pts[1], pts[2], pts[3]) != CGAL::POSITIVE) return false; } return true; @@ -1184,10 +1183,10 @@ typename C3t3::Vertex_handle collapse_edge(typename C3t3::Edge& edge, const auto orientations_ok = [&](const Collapse_type ct, const Point& pos) { if ((ct == TO_V1 || ct == TO_MIDPOINT) - && !collapse_keeps_orientations(star_of_v0(), v0, v1, pos)) + && !collapse_keeps_orientations(star_of_v0(), v0, v1, point(pos))) return false; if ((ct == TO_V0 || ct == TO_MIDPOINT) - && !collapse_keeps_orientations(star_of_v1(), v1, v0, pos)) + && !collapse_keeps_orientations(star_of_v1(), v1, v0, point(pos))) return false; return true; }; From e450540232ea180cbd2790b72cbc829a8465fc44 Mon Sep 17 00:00:00 2001 From: IasonManolas Date: Wed, 12 Aug 2026 13:25:59 +0300 Subject: [PATCH 10/10] topology_test: move the short-circuiting subdomain test to #9588 has_several_incident_subdomains() has exactly one caller, the boundary-apex guard in topology_test(), and #9588 rewrites that same guard so its two complex-membership lookups run before the star walk. Holding the helper here made the two branches conflict on that one line for no reason: it belongs with the reordering that decides when it runs. #9588 now introduces it and uses it as the last conjunct, which is faster than either branch alone. --- .../internal/tetrahedral_remeshing_helpers.h | 59 +------------------ 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h index b5a9f2a363e4..5e5e1601f6e0 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h @@ -979,63 +979,6 @@ std::size_t nb_incident_subdomains(const typename C3t3::Vertex_handle v, return indices.size(); } -// `nb_incident_subdomains(v, c3t3) > 1`, without counting the whole star. The -// traversal is the one `TDS_3::incident_cells_3()` performs - from v's cell, -// across the facets that contain v, marking cells as it goes - so it sees the -// same cells in the same order, and stops as soon as a second index appears. -// The marks are the TDS's own conflict flags and are cleared before -// returning, so this must not be called from inside another marking -// traversal; the collapse guard chain that calls it is not. -template -bool has_several_incident_subdomains(const typename C3t3::Vertex_handle v, - const C3t3& c3t3) -{ - typedef typename C3t3::Triangulation::Cell_handle Cell_handle; - CGAL_USE(c3t3); - - const Cell_handle start = v->cell(); - const auto si0 = start->subdomain_index(); - - boost::container::small_vector marked; - boost::container::small_vector to_visit; - - start->tds_data().mark_in_conflict(); - marked.push_back(start); - to_visit.push_back(start); - - bool several = false; - while (!to_visit.empty()) - { - const Cell_handle c = to_visit.back(); - to_visit.pop_back(); - - if (c->subdomain_index() != si0) - { - several = true; - break; - } - - for (int i = 0; i < 4; ++i) - { - if (c->vertex(i) == v) - continue; - - const Cell_handle n = c->neighbor(i); - if (!n->tds_data().is_clear()) - continue; - - n->tds_data().mark_in_conflict(); - marked.push_back(n); - to_visit.push_back(n); - } - } - - for (const Cell_handle c : marked) - c->tds_data().clear(); - - return several; -} - template std::size_t nb_incident_subdomains(const typename C3t3::Edge& e, const C3t3& c3t3) @@ -1372,7 +1315,7 @@ bool topology_test(const typename C3t3::Edge& edge, for (int i = 1; i < 4; i++) { Vertex_handle vi = f.first->vertex((f.second + i) % 4); - if (vi != v0 && vi != v1 && has_several_incident_subdomains(vi, c3t3)) + if (vi != v0 && vi != v1 && nb_incident_subdomains(vi, c3t3) > 1) { if (is_edge_in_complex(v0, vi, c3t3) && is_edge_in_complex(v1, vi, c3t3))