From 8076e20b71bc83407ec94d6e399d6e41f163c8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 1 Aug 2023 13:07:55 +0200 Subject: [PATCH 001/133] Add debug code --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 14 ++++++++------ .../test_AW3_cavity_initializations.cpp | 1 + .../test/Alpha_wrap_3/test_AW3_manifoldness.cpp | 1 + .../test/Alpha_wrap_3/test_AW3_multiple_calls.cpp | 1 + .../test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index e88e00fafe0c..1e9674276fa8 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1362,7 +1362,12 @@ class Alpha_wrap_3 for(Vertex_handle v : m_dt.finite_vertex_handles()) { if(is_non_manifold(v)) + { +#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS_PP + std::cout << v->point() << " is non-manifold" << std::endl; +#endif non_manifold_vertices.push(v); + } } // Some lambdas for the comparer @@ -1412,23 +1417,19 @@ class Alpha_wrap_3 squared_distance(m_dt.point(c, 2), m_dt.point(c, 3)) }); }; -#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS +#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS_PP std::cout << non_manifold_vertices.size() << " initial NMV" << std::endl; #endif while(!non_manifold_vertices.empty()) { -#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS +#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS_PP std::cout << non_manifold_vertices.size() << " NMV in queue" << std::endl; #endif Vertex_handle v = non_manifold_vertices.top(); non_manifold_vertices.pop(); -#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS - std::cout << "ยท"; -#endif - if(!is_non_manifold(v)) continue; @@ -1503,6 +1504,7 @@ class Alpha_wrap_3 void check_queue_sanity() { std::cout << "Check queue sanity..." << std::endl; + std::vector queue_gates; Gate previous_top_gate = m_queue.top(); while(!m_queue.empty()) diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp index d7567bab205b..c6591e000df1 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp @@ -1,5 +1,6 @@ #define CGAL_AW3_TIMER #define CGAL_AW3_DEBUG +#define CGAL_AW3_DEBUG_MANIFOLDNESS // #define CGAL_AW3_DEBUG_INITIALIZATION #include diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp index 928cade64959..8ac2e422d878 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp @@ -1,5 +1,6 @@ #define CGAL_AW3_TIMER #define CGAL_AW3_DEBUG +#define CGAL_AW3_DEBUG_MANIFOLDNESS //#define CGAL_AW3_DEBUG_STEINER_COMPUTATION //#define CGAL_AW3_DEBUG_INITIALIZATION //#define CGAL_AW3_DEBUG_QUEUE diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp index e2abc6f1f12f..eda64a8376a4 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp @@ -1,5 +1,6 @@ #define CGAL_AW3_TIMER #define CGAL_AW3_DEBUG +#define CGAL_AW3_DEBUG_MANIFOLDNESS #include diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp index 5091934b62f0..302494d8c304 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp @@ -1,6 +1,6 @@ #define CGAL_AW3_TIMER //#define CGAL_AW3_DEBUG -//#define CGAL_AW3_DEBUG_MANIFOLDNESS +#define CGAL_AW3_DEBUG_MANIFOLDNESS //#define CGAL_AW3_DEBUG_STEINER_COMPUTATION //#define CGAL_AW3_DEBUG_INITIALIZATION //#define CGAL_AW3_DEBUG_QUEUE From c7b9317a96117f874aa88b6ca9cd6b376f4d10cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 1 Aug 2023 13:16:18 +0200 Subject: [PATCH 002/133] Simplify choice of cells to un-carve while enforcing manifoldness This combinatorial choice seemed like a good idea, but it can have nasty cascading effects, adding very large tetrahedra. See this issue: https://github.com/CGAL/cgal/issues/7625 In the end, the only thing we care about is small volumes being added. I keep the artificial vertex for now, but I am not fully convinced these should be actually kept too. --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 1e9674276fa8..1b0a6968c092 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1445,11 +1445,6 @@ class Alpha_wrap_3 if(has_artificial_vertex(r)) return true; - const int l_bf_count = count_boundary_facets(l, v); - const int r_bf_count = count_boundary_facets(r, v); - if(l_bf_count != r_bf_count) - return l_bf_count > r_bf_count; - return sq_longest_edge(l) < sq_longest_edge(r); }; From b4e207ab00237bffbd221bc7f4bd4b0bb2e69c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 2 Aug 2023 10:00:34 +0200 Subject: [PATCH 003/133] Add some comments on AW3 manifoldness heuristics criteria --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 1b0a6968c092..a21925cdc6d8 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1380,25 +1380,27 @@ class Alpha_wrap_3 return false; }; - auto is_on_boundary = [](Cell_handle c, int i) -> bool - { - return (c->info().is_outside != c->neighbor(i)->info().is_outside); - }; - - auto count_boundary_facets = [&](Cell_handle c, Vertex_handle v) -> int - { - const int v_index_in_c = c->index(v); - int boundary_facets = 0; - for(int i=0; i<3; ++i) // also take into account the opposite facet? - { - if(i == v_index_in_c) - continue; - - boundary_facets += is_on_boundary(c, i); - } - - return boundary_facets; - }; + // This seemed like a good idea, but in the end it can have strong cascading issues, + // whereas some cells with much lower volume would have solved the non-manifoldness. +// auto is_on_boundary = [](Cell_handle c, int i) -> bool +// { +// return (c->info().is_outside != c->neighbor(i)->info().is_outside); +// }; +// +// auto count_boundary_facets = [&](Cell_handle c, Vertex_handle v) -> int +// { +// const int v_index_in_c = c->index(v); +// int boundary_facets = 0; +// for(int i=0; i<3; ++i) // also take into account the opposite facet? +// { +// if(i == v_index_in_c) +// continue; +// +// boundary_facets += is_on_boundary(c, i); +// } +// +// return boundary_facets; +// }; // longest edge works better // auto sq_circumradius = [&](Cell_handle c) -> FT @@ -1407,6 +1409,9 @@ class Alpha_wrap_3 // return geom_traits().compute_squared_distance_3_object()(m_dt.point(c, 0), cc); // }; + // the reasonning behind using longest edge rather than volume is that we want to avoid + // spikes (which would have a small volume), and can often happen since we do not spend + // any care on the quality of tetrahedra. auto sq_longest_edge = [&](Cell_handle c) -> FT { return (std::max)({ squared_distance(m_dt.point(c, 0), m_dt.point(c, 1)), From 330ff2e65776a9be1f7ca757a813e5055e0a1994 Mon Sep 17 00:00:00 2001 From: Mael Date: Wed, 2 Aug 2023 10:23:12 +0200 Subject: [PATCH 004/133] Fix spelling Thanks @albert-github! --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index a21925cdc6d8..6d544be058d6 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1409,7 +1409,7 @@ class Alpha_wrap_3 // return geom_traits().compute_squared_distance_3_object()(m_dt.point(c, 0), cc); // }; - // the reasonning behind using longest edge rather than volume is that we want to avoid + // the reasoning behind using longest edge rather than volume is that we want to avoid // spikes (which would have a small volume), and can often happen since we do not spend // any care on the quality of tetrahedra. auto sq_longest_edge = [&](Cell_handle c) -> FT From 88bcd4096625b172d1091e33cfb37118513e50a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 20 Sep 2023 12:48:42 +0200 Subject: [PATCH 005/133] Enable changing the oracle in the AW3 builder --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index f12ad06804b1..86010b27dfcf 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -173,7 +173,7 @@ class Alpha_wrap_3 using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; protected: - const Oracle m_oracle; + Oracle m_oracle; SC_Iso_cuboid_3 m_bbox; FT m_alpha, m_sq_alpha; @@ -183,10 +183,12 @@ class Alpha_wrap_3 Alpha_PQ m_queue; public: - // Main constructor + Alpha_wrap_3() + : m_queue(4096) + { } + Alpha_wrap_3(const Oracle& oracle) - : - m_oracle(oracle), + : m_oracle(oracle), m_dt(Geom_traits(oracle.geom_traits())), // used to set up the initial MPQ, use some arbitrary not-too-small value m_queue(4096) @@ -198,6 +200,8 @@ class Alpha_wrap_3 public: const Geom_traits& geom_traits() const { return m_dt.geom_traits(); } + Oracle& oracle() { return m_oracle; } + const Oracle& oracle() const { return m_oracle; } Dt& triangulation() { return m_dt; } const Dt& triangulation() const { return m_dt; } const Alpha_PQ& queue() const { return m_queue; } From 4512b0e6f44ec1ac42ae0854bba2abb12588b7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 20 Sep 2023 12:52:20 +0200 Subject: [PATCH 006/133] Rewrite the extraction of possibly non-manifold wraps --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 295 ++++++++++++------ 1 file changed, 193 insertions(+), 102 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 86010b27dfcf..6e8e323e85a9 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -648,165 +648,256 @@ class Alpha_wrap_3 return true; } -public: - // Manifoldness is tolerated while debugging and extracting at intermediate states - // Not the preferred way because it uses 3*nv storage - template - void extract_possibly_non_manifold_surface(OutputMesh& output_mesh, - OVPM ovpm) const +private: + void extract_boundary(std::vector& points, + std::vector >& faces) const { - namespace PMP = Polygon_mesh_processing; - -#ifdef CGAL_AW3_DEBUG - std::cout << "> Extract possibly non-manifold wrap... ()" << std::endl; -#endif - - clear(output_mesh); - - CGAL_assertion_code(for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit)) - CGAL_assertion(cit->tds_data().is_clear()); + std::unordered_map vertex_to_id; - for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit) + for(auto fit=m_dt.all_facets_begin(), fend=m_dt.all_facets_end(); fit!=fend; ++fit) { - Cell_handle seed = cit; - if(seed->info().is_outside || seed->tds_data().processed()) + Facet f = *fit; + if(!f.first->info().is_outside) + f = m_dt.mirror_facet(f); + + const Cell_handle ch = f.first; + const int s = f.second; + const Cell_handle nh = ch->neighbor(s); + if(ch->info().is_outside == nh->info().is_outside) continue; - std::queue to_visit; - to_visit.push(seed); + std::array ids; + for(int pos=0; pos<3; ++pos) + { + Vertex_handle vh = ch->vertex(Dt::vertex_triple_index(s, pos)); + auto insertion_res = vertex_to_id.emplace(vh, vertex_to_id.size()); + if(insertion_res.second) // successful insertion, never-seen-before vertex + points.push_back(m_dt.point(vh)); - std::vector points; - std::vector > faces; - std::size_t idx = 0; + ids[pos] = insertion_res.first->second; + } - while(!to_visit.empty()) - { - const Cell_handle cell = to_visit.front(); - CGAL_assertion(!cell->info().is_outside && !m_dt.is_infinite(cell)); + faces.emplace_back(std::array{ids[0], ids[1], ids[2]}); + } + } - to_visit.pop(); + template + void extract_manifold_surface(OutputMesh& output_mesh, + OVPM ovpm) const + { + namespace PMP = Polygon_mesh_processing; - if(cell->tds_data().processed()) - continue; +#ifdef CGAL_AW3_DEBUG + std::cout << "> Extract manifold wrap... ()" << std::endl; +#endif - cell->tds_data().mark_processed(); + CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles())) + CGAL_assertion(!is_non_manifold(v)); - for(int fid=0; fid<4; ++fid) - { - const Cell_handle neighbor = cell->neighbor(fid); - if(neighbor->info().is_outside) - { - // There shouldn't be any artificial vertex on the inside/outside boundary - // (past initialization) -// CGAL_assertion(cell->vertex((fid + 1)&3)->info() == DEFAULT); -// CGAL_assertion(cell->vertex((fid + 2)&3)->info() == DEFAULT); -// CGAL_assertion(cell->vertex((fid + 3)&3)->info() == DEFAULT); - - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 0))); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 1))); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 2))); - faces.push_back({idx, idx + 1, idx + 2}); - idx += 3; - } - else - { - to_visit.push(neighbor); - } - } - } + clear(output_mesh); - PMP::duplicate_non_manifold_edges_in_polygon_soup(points, faces); + std::vector points; + std::vector > faces; + extract_boundary(points, faces); - CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(faces)); - PMP::polygon_soup_to_polygon_mesh(points, faces, output_mesh, - CGAL::parameters::default_values(), - CGAL::parameters::vertex_point_map(ovpm)); + if(faces.empty()) + { +#ifdef CGAL_AW3_DEBUG + std::cout << "Empty wrap?..." << std::endl; +#endif + return; + } - PMP::stitch_borders(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); - CGAL_assertion(is_closed(output_mesh)); + if(!PMP::is_polygon_soup_a_polygon_mesh(faces)) + { + CGAL_warning_msg(false, "Failed to extract a manifold boundary!"); + return; } - for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit) - cit->tds_data().clear(); + PMP::polygon_soup_to_polygon_mesh(points, faces, output_mesh, + CGAL::parameters::default_values(), + CGAL::parameters::vertex_point_map(ovpm)); CGAL_postcondition(!is_empty(output_mesh)); CGAL_postcondition(is_valid_polygon_mesh(output_mesh)); CGAL_postcondition(is_closed(output_mesh)); - - PMP::orient_to_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); + CGAL_postcondition(PMP::does_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm))); } template - void extract_manifold_surface(OutputMesh& output_mesh, - OVPM ovpm) const + void extract_possibly_non_manifold_surface(OutputMesh& output_mesh, + OVPM ovpm) const { namespace PMP = Polygon_mesh_processing; + using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + using face_descriptor = typename boost::graph_traits::face_descriptor; + #ifdef CGAL_AW3_DEBUG - std::cout << "> Extract wrap... ()" << std::endl; + std::cout << "> Extract possibly non-manifold wrap... ()" << std::endl; #endif - CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles())) - CGAL_assertion(!is_non_manifold(v)); - clear(output_mesh); - // boundary faces to polygon soup std::vector points; - std::vector > faces; + std::vector > polygons; - std::unordered_map vertex_to_id; - std::size_t nv = 0; + // Explode the polygon soup into indepent triangles, and stitch back edge by edge by walking along the exterior + std::map facet_ids; + std::size_t idx = 0; - for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) + for(auto fit=m_dt.all_facets_begin(), fend=m_dt.all_facets_end(); fit!=fend; ++fit) { Facet f = *fit; if(!f.first->info().is_outside) f = m_dt.mirror_facet(f); - const Cell_handle c = f.first; + const Cell_handle ch = f.first; const int s = f.second; - const Cell_handle nh = c->neighbor(s); - if(c->info().is_outside == nh->info().is_outside) + const Cell_handle nh = ch->neighbor(s); + if(ch->info().is_outside == nh->info().is_outside) continue; - std::array ids; - for(int pos=0; pos<3; ++pos) - { - Vertex_handle vh = c->vertex(Dt::vertex_triple_index(s, pos)); - auto insertion_res = vertex_to_id.emplace(vh, nv); - if(insertion_res.second) // successful insertion, never-seen-before vertex - { - points.push_back(m_dt.point(vh)); - ++nv; - } + facet_ids[f] = idx / 3; - ids[pos] = insertion_res.first->second; - } + points.push_back(m_dt.point(ch, Dt::vertex_triple_index(s, 0))); + points.push_back(m_dt.point(ch, Dt::vertex_triple_index(s, 1))); + points.push_back(m_dt.point(ch, Dt::vertex_triple_index(s, 2))); + polygons.push_back({idx, idx + 1, idx + 2}); - faces.emplace_back(std::array{ids[0], ids[1], ids[2]}); + idx += 3; } - if(faces.empty()) - return; - - if(!PMP::is_polygon_soup_a_polygon_mesh(faces)) + if(polygons.empty()) { - CGAL_warning_msg(false, "Could NOT extract mesh..."); +#ifdef CGAL_AW3_DEBUG + std::cout << "Empty wrap?..." << std::endl; +#endif return; } - PMP::polygon_soup_to_polygon_mesh(points, faces, output_mesh, - CGAL::parameters::default_values(), + CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(polygons)); + + std::unordered_map i2f; + PMP::polygon_soup_to_polygon_mesh(points, polygons, output_mesh, + CGAL::parameters::polygon_to_face_output_iterator(std::inserter(i2f, i2f.end())), CGAL::parameters::vertex_point_map(ovpm)); + auto face_to_facet = get(CGAL::dynamic_face_property_t(), output_mesh); + + idx = 0; + for(auto fit=m_dt.all_facets_begin(), fend=m_dt.all_facets_end(); fit!=fend; ++fit) + { + Facet f = *fit; + if(!f.first->info().is_outside) + f = m_dt.mirror_facet(f); + + const Cell_handle ch = f.first; + const int s = f.second; + const Cell_handle nh = ch->neighbor(s); + if(ch->info().is_outside == nh->info().is_outside) + continue; + + put(face_to_facet, i2f[idx++], f); + } + + // grab the stitchable halfedges + std::vector > to_stitch; + + for(face_descriptor f : faces(output_mesh)) + { + const Facet& tr_f = get(face_to_facet, f); + const Cell_handle ch = tr_f.first; + CGAL_assertion(ch->info().is_outside); + + for(halfedge_descriptor h : halfedges_around_face(halfedge(f, output_mesh), output_mesh)) + { + const vertex_descriptor sv = source(h, output_mesh); + const vertex_descriptor tv = target(h, output_mesh); + + // only need the pair of halfedges once + if(get(ovpm, sv) > get(ovpm, tv)) + continue; + + // One could avoid these point comparisons by using the fact that we know that the graph + // has faces built in a specific order (through BGL::add_face()), but it's better to make + // this code more generic (and it is not very costly). + auto graph_descriptor_to_triangulation_handle = [&](const vertex_descriptor v) + { + const Point_3& p = get(ovpm, v); + for(int i=0; i<4; ++i) + if(ch->vertex(i)->point() == p) + return ch->vertex(i); + + CGAL_assertion(false); + return Vertex_handle(); + }; + + const Vertex_handle s_vh = graph_descriptor_to_triangulation_handle(sv); + const Vertex_handle t_vh = graph_descriptor_to_triangulation_handle(tv); + CGAL_assertion(get(ovpm, sv) == m_dt.point(s_vh)); + CGAL_assertion(get(ovpm, tv) == m_dt.point(t_vh)); + + const int facet_third_id = 6 - (ch->index(s_vh) + ch->index(t_vh) + tr_f.second); // 0 + 1 + 2 + 3 = 6 + Vertex_handle third_vh = ch->vertex(facet_third_id); + + // walk around the edge (in the exterior of the wrap) till meeting an inside cell + Cell_handle start_ch = ch, curr_ch = ch; + do + { + const int i = curr_ch->index(s_vh); + const int j = curr_ch->index(t_vh); + + // the facet is incident to the outside cell, and we walk in the exterior + const int facet_third_id = 6 - (curr_ch->index(s_vh) + curr_ch->index(t_vh) + curr_ch->index(third_vh)); + third_vh = curr_ch->vertex(facet_third_id); + curr_ch = curr_ch->neighbor(Dt::next_around_edge(i,j)); + + if(!curr_ch->info().is_outside) + break; + } + while(curr_ch != start_ch); + + CGAL_assertion(curr_ch != start_ch); + CGAL_assertion(!curr_ch->info().is_outside); + + const int opp_id = 6 - (curr_ch->index(s_vh) + curr_ch->index(t_vh) + curr_ch->index(third_vh)); + const Facet tr_f2 = m_dt.mirror_facet(Facet(curr_ch, opp_id)); + CGAL_assertion(facet_ids.count(Facet(curr_ch, opp_id)) == 0); + CGAL_assertion(tr_f2.first->info().is_outside); + CGAL_assertion(tr_f2.first->neighbor(tr_f2.second) == curr_ch); + CGAL_assertion(tr_f2.first->has_vertex(s_vh) && tr_f2.first->has_vertex(t_vh)); + + const face_descriptor f2 = i2f[facet_ids.at(tr_f2)]; + halfedge_descriptor h2 = halfedge(f2, output_mesh), done = h2; + while(get(ovpm, target(h2, output_mesh)) != get(ovpm, source(h, output_mesh))) + { + h2 = next(h2, output_mesh); + CGAL_assertion(h2 != done); + if(h2 == done) + break; + } + + CGAL_assertion(get(ovpm, source(h, output_mesh)) == get(ovpm, target(h2, output_mesh))); + CGAL_assertion(get(ovpm, target(h, output_mesh)) == get(ovpm, source(h2, output_mesh))); + CGAL_assertion(get(ovpm, target(next(h2, output_mesh), output_mesh)) == m_dt.point(third_vh)); + + to_stitch.emplace_back(opposite(h, output_mesh), opposite(h2, output_mesh)); + } + } + + PMP::internal::stitch_halfedge_range(to_stitch, output_mesh, ovpm); + + collect_garbage(output_mesh); + CGAL_postcondition(!is_empty(output_mesh)); CGAL_postcondition(is_valid_polygon_mesh(output_mesh)); CGAL_postcondition(is_closed(output_mesh)); - - PMP::orient_to_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); + CGAL_postcondition(PMP::does_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm))); } +public: template void extract_surface(OutputMesh& output_mesh, OVPM ovpm, From 4d50ec46b361ca0c912f3725d91fe673ff6ed869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 20 Sep 2023 12:53:12 +0200 Subject: [PATCH 007/133] Consider all cases in facet_status In a normal run of the algorithm, we shall never ask the facet status of a facet that is already outside, but it's better to be complete and it costs nothing. --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 6e8e323e85a9..7c48a51ba6c5 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1027,6 +1027,15 @@ class Alpha_wrap_3 // skip if neighbor is OUTSIDE or infinite const Cell_handle ch = f.first; const int id = f.second; + + if(!ch->info().is_outside) + { +#ifdef CGAL_AW3_DEBUG_FACET_STATUS + std::cout << "Facet is inside" << std::endl; +#endif + return IRRELEVANT; + } + const Cell_handle nh = ch->neighbor(id); if(m_dt.is_infinite(nh)) return TRAVERSABLE; From bff07b2fc9ef0c26209475deae428ed77c29fecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 20 Sep 2023 12:55:11 +0200 Subject: [PATCH 008/133] Simplify the gate comparer: we can also sort artificial facets like normal facets Artificial facets are *not* infinite facets. --- .../include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index 8d63e34c9e3b..824d27bc2c10 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -68,11 +68,6 @@ struct Less_gate template bool operator()(const Gate& a, const Gate& b) const { - // @fixme? make it a total order by comparing addresses if both gates are bbox facets - if(a.is_artificial_facet()) - return true; - else if(b.is_artificial_facet()) - return false; return a.priority() > b.priority(); } }; From 5304f739b9f4e26c49630a1fe2970e5c5711b20e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 20 Sep 2023 12:57:02 +0200 Subject: [PATCH 009/133] Enable restarting from a previous wrap --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 82 ++++++++++++++++--- .../internal/parameters_interface.h | 1 + 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 7c48a51ba6c5..9a0ee2ddb619 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -176,8 +176,8 @@ class Alpha_wrap_3 Oracle m_oracle; SC_Iso_cuboid_3 m_bbox; - FT m_alpha, m_sq_alpha; - FT m_offset, m_sq_offset; + FT m_alpha = FT(-1), m_sq_alpha = FT(-1); + FT m_offset = FT(-1), m_sq_offset = FT(-1); Dt m_dt; Alpha_PQ m_queue; @@ -268,6 +268,20 @@ class Alpha_wrap_3 const bool do_enforce_manifoldness = choose_parameter(get_parameter(in_np, internal_np::do_enforce_manifoldness), true); + // This parameter enables avoiding recomputing the triangulation from scratch when wrapping + // the same meshes for multiple values of alpha (and typically the same offset values). + // + // /!\ Warning /!\ + // + // If this is enabled, the 3D triangulation will NEVER be cleared and re-initialized + // at launch. This means that the triangulation is NOT cleared, even when: + // - the triangulation is empty; you will get nothing. + // - you use an alpha value that is greater than what was used in a previous run; you will + // obtain a denser result than what you might expect. + // - you use a different offset value between runs, you might then get points that are not + // on the offset surface corresponding to your latter offset value. + const bool resuming = choose_parameter(get_parameter(in_np, internal_np::refine_triangulation), false); + #ifdef CGAL_AW3_TIMER CGAL::Real_timer t; t.start(); @@ -275,7 +289,7 @@ class Alpha_wrap_3 visitor.on_alpha_wrapping_begin(*this); - if(!initialize(alpha, offset, seeds)) + if(!initialize(alpha, offset, seeds, resuming)) return; #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP @@ -648,6 +662,35 @@ class Alpha_wrap_3 return true; } + // This function is used in the case of resumption of a previous run: m_dt is not cleared, + // and we fill the queue with the new parameters. + bool initialize_from_existing_triangulation() + { + std::cout << "restart from a DT of " << m_dt.number_of_cells() << " cells" << std::endl; + + Real_timer t; + t.start(); + + for(Cell_handle ch : m_dt.all_cell_handles()) + { + if(!ch->info().is_outside) + continue; + + for(int i=0; i<4; ++i) + { + if(ch->neighbor(i)->info().is_outside) + continue; + + push_facet(std::make_pair(ch, i)); + } + } + + t.stop(); + std::cout << t.time() << " for scanning" << std::endl; + + return true; + } + private: void extract_boundary(std::vector& points, std::vector >& faces) const @@ -1105,7 +1148,8 @@ class Alpha_wrap_3 template bool initialize(const double alpha, const double offset, - const SeedRange& seeds) + const SeedRange& seeds, + const bool resuming = false) { #ifdef CGAL_AW3_DEBUG std::cout << "> Initialize..." << std::endl; @@ -1121,20 +1165,38 @@ class Alpha_wrap_3 return false; } + if(resuming) + { + if(offset != m_offset) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Warning: resuming with a different offset!" << std::endl; +#endif + } + } + m_alpha = FT(alpha); m_sq_alpha = square(m_alpha); m_offset = FT(offset); m_sq_offset = square(m_offset); - m_dt.clear(); m_queue.clear(); - insert_bbox_corners(); - - if(seeds.empty()) - return initialize_from_infinity(); + if(resuming) + { + return initialize_from_existing_triangulation(); + } else - return initialize_with_cavities(seeds); + { + m_dt.clear(); + + insert_bbox_corners(); + + if(seeds.empty()) + return initialize_from_infinity(); + else + return initialize_with_cavities(seeds); + } } template diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 7792ad5cdb60..435075df6e2a 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -237,6 +237,7 @@ CGAL_add_named_parameter(smooth_constrained_edges_t, smooth_constrained_edges, s // List of named parameters used in Alpha_wrap_3 CGAL_add_named_parameter(do_enforce_manifoldness_t, do_enforce_manifoldness, do_enforce_manifoldness) CGAL_add_named_parameter(seed_points_t, seed_points, seed_points) +CGAL_add_named_parameter(refine_triangulation_t, refine_triangulation, refine_triangulation) // SMDS_3 parameters CGAL_add_named_parameter(surface_facets_t, surface_facets, surface_facets) From 36017331c2e12a62a055943732b1cfed4d128eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 20 Sep 2023 12:58:30 +0200 Subject: [PATCH 010/133] Add an example of successive AW3 restarts --- .../examples/Alpha_wrap_3/CMakeLists.txt | 1 + .../Alpha_wrap_3/successive_wraps.cpp | 151 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt index 2014b9baa7ca..11dec5f4134d 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt @@ -12,3 +12,4 @@ create_single_source_cgal_program("triangle_soup_wrap.cpp") create_single_source_cgal_program("point_set_wrap.cpp") create_single_source_cgal_program("wrap_from_cavity.cpp") create_single_source_cgal_program("mixed_inputs_wrap.cpp") +create_single_source_cgal_program("successive_wraps.cpp") diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp new file mode 100644 index 000000000000..600d533ee411 --- /dev/null +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp @@ -0,0 +1,151 @@ +#define CGAL_AW3_TIMER + +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace PMP = CGAL::Polygon_mesh_processing; + +using K = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = K::FT; +using Point_3 = K::Point_3; + +using Mesh = CGAL::Surface_mesh; + +// We want decreasing alphas, and these are relative ratios, so they need to be increasing +const std::vector relative_alphas = { 1, 2/*50, 100, 150, 200, 250*/ }; +const FT relative_offset = 600; + +int main(int argc, char** argv) +{ + std::cout.precision(17); + std::cerr.precision(17); + + // Read the input + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/cube.off"); + std::cout << "Reading " << filename << "..." << std::endl; + + Mesh mesh; + if(!PMP::IO::read_polygon_mesh(filename, mesh) || is_empty(mesh) || !is_triangle_mesh(mesh)) + { + std::cerr << "Invalid input." << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Input: " << num_vertices(mesh) << " vertices, " << num_faces(mesh) << " faces" << std::endl; + + const CGAL::Bbox_3 bbox = CGAL::Polygon_mesh_processing::bbox(mesh); + const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) + + CGAL::square(bbox.ymax() - bbox.ymin()) + + CGAL::square(bbox.zmax() - bbox.zmin())); + + // =============================================================================================== + // Naive approach: + + CGAL::Real_timer t; + double total_time = 0.; + + for(std::size_t i=0; i>> [" << i << "] alpha: " << alpha << " offset: " << offset << std::endl; + + Mesh wrap; + CGAL::alpha_wrap_3(mesh, alpha, offset, wrap, + CGAL::parameters::do_enforce_manifoldness(false)); + + t.stop(); + std::cout << " Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl; + std::cout << " Elapsed time: " << t.time() << " s." << std::endl; + + std::string input_name = std::string(filename); + input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); + input_name = input_name.substr(0, input_name.find_last_of(".")); + std::string output_name = input_name + + "_" + std::to_string(static_cast(relative_alphas[i])) + + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + std::cout << "Writing to " << output_name << std::endl; + CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); + + total_time += t.time(); + } + + std::cout << "Total elapsed time (naive): " << total_time << " s.\n" << std::endl; + + // =============================================================================================== + // Re-use approach + // + // Here, we restart from the triangulation of the previous state, and carve according + // to a (smaller) alpha value. This enables considerable speed-up: the cumulated time taken + // to run `n` successive instances of `{alpha_wrap(alpha_i)}_(i=1...n)` will be equal to the + // time taken to run alpha_wrap(alpha_n) from scratch. + // + // For example: + // naive: + // alpha_wrap(alpha_1, ...) ---> 2s + // alpha_wrap(alpha_2, ...) ---> 4s + // alpha_wrap(alpha_3, ...) ---> 8s + // will become with reusability: + // alpha_wrap(alpha_1, ..., reuse) ---> 2s + // alpha_wrap(alpha_2, ..., reuse) ---> 2s // 2+2 = 4s = naive alpha_2 + // alpha_wrap(alpha_3, ..., reuse) ---> 4s // 2+2+4 = 8s = naive alpha_3 + // Thus, if we care about the intermediate results, we save 6s (8s instead of 14s). + // The speed-up increases with the number of intermediate results, and if the alpha values + // are close. + // + // !! Warning !! + // The result of alpha_wrap(alpha_1, ...) followed by alpha_wrap(alpha_2, ...) with alpha_2 + // smaller than alpha_1 is going to be close but NOT exactly equal to that produced by calling + // alpha_wrap(alpha_2, ...) directly. + + total_time = 0.; + t.reset(); + + using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle; + using Wrapper = CGAL::Alpha_wraps_3::internal::Alpha_wrap_3; + Wrapper wrapper; // contains the triangulation that is being refined iteratively + + for(std::size_t i=0; i>> [" << i << "] alpha: " << alpha << " offset: " << offset << std::endl; + + // The triangle mesh oracle can be initialized with alpha to internally perform a split + // of too-big facets while building the AABB Tree. This split in fact yields a significant + // speed-up for meshes with elements that are large compared to alpha. This speed-up makes it + // faster to re-build the AABB tree for every value of alpha than to use a non-optimized tree. + Oracle oracle(alpha); + oracle.add_triangle_mesh(mesh, CGAL::parameters::default_values()); + wrapper.oracle() = oracle; + + Mesh wrap; + wrapper(alpha, offset, wrap, + CGAL::parameters::do_enforce_manifoldness(false) + .refine_triangulation((i != 0))); + + t.stop(); + std::cout << " Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl; + std::cout << " Elapsed time: " << t.time() << " s." << std::endl; + + total_time += t.time(); + } + + std::cout << "Total elapsed time (successive): " << total_time << " s." << std::endl; + + return EXIT_SUCCESS; +} From 19cb693a1b9ff119593057c76402493b03e474e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 20 Sep 2023 12:59:46 +0200 Subject: [PATCH 011/133] Improve debug code --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 84 +++++++++++++------ 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 9a0ee2ddb619..0579297c4335 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1053,6 +1053,24 @@ class Alpha_wrap_3 TRAVERSABLE }; + inline const char* get_status_message(const Facet_queue_status status) + { + constexpr std::size_t status_count = 3; + + // Messages corresponding to Error_code list above. Must be kept in sync! + static const char* message[status_count] = { + "Irrelevant facet", + "Artificial facet", + "Traversable facet" + }; + + if(status > status_count || status < 0) + return "Unknown status"; + else + return message[status]; + } + +public: // @speed some decent time may be spent constructing Facet (pairs) for no reason as it's always // just to grab the .first and .second as soon as it's constructed, and not due to API requirements // e.g. from DT3 @@ -1062,9 +1080,9 @@ class Alpha_wrap_3 #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "facet status: " - << f.first->vertex((f.second + 1)&3)->point() << " " - << f.first->vertex((f.second + 2)&3)->point() << " " - << f.first->vertex((f.second + 3)&3)->point() << std::endl; + << m_dt.point(f.first, Dt::vertex_triple_index(f.second, 0)) << " " + << m_dt.point(f.first, Dt::vertex_triple_index(f.second, 1)) << " " + << m_dt.point(f.first, Dt::vertex_triple_index(f.second, 2)) << std::endl; #endif // skip if neighbor is OUTSIDE or infinite @@ -1119,6 +1137,7 @@ class Alpha_wrap_3 return IRRELEVANT; } +private: bool push_facet(const Facet& f) { CGAL_precondition(f.first->info().is_outside); @@ -1127,19 +1146,29 @@ class Alpha_wrap_3 if(m_queue.contains_with_bounds_check(Gate(f))) return false; - const Facet_queue_status s = facet_status(f); - if(s == IRRELEVANT) + const Facet_queue_status status = facet_status(f); + if(status == IRRELEVANT) return false; const Cell_handle ch = f.first; - const int id = f.second; - const Point_3& p0 = m_dt.point(ch, (id+1)&3); - const Point_3& p1 = m_dt.point(ch, (id+2)&3); - const Point_3& p2 = m_dt.point(ch, (id+3)&3); + const int s = f.second; + const Point_3& p0 = m_dt.point(ch, Dt::vertex_triple_index(s, 0)); + const Point_3& p1 = m_dt.point(ch, Dt::vertex_triple_index(s, 1)); + const Point_3& p2 = m_dt.point(ch, Dt::vertex_triple_index(s, 2)); - // @todo should prob be the real value we compare to alpha instead of squared_radius + // @todo should prob be the real value that we compare to alpha instead of squared_radius const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); - m_queue.resize_and_push(Gate(f, sqr, (s == ARTIFICIAL_FACET))); + m_queue.resize_and_push(Gate(f, sqr, (status == ARTIFICIAL_FACET))); + +#ifdef CGAL_AW3_DEBUG_QUEUE + static int gid = 0; + std::cout << "Queue insertion #" << gid++ << "\n" + << " ch = " << &*ch << " (" << m_dt.is_infinite(ch) << ") " << "\n" + << "\t" << p0 << "\n\t" << p1 << "\n\t" << p2 << std::endl; + std::cout << " Status: " << get_status_message(status) << std::endl; + std::cout << " SQR: " << sqr << std::endl; + std::cout << " Artificiality: " << (status == ARTIFICIAL_FACET) << std::endl; +#endif return true; } @@ -1160,7 +1189,7 @@ class Alpha_wrap_3 if(!is_positive(alpha) || !is_positive(offset)) { #ifdef CGAL_AW3_DEBUG - std::cout << "Error: invalid input parameters" << std::endl; + std::cerr << "Error: invalid input parameters: " << alpha << " and" << offset << std::endl; #endif return false; } @@ -1230,7 +1259,9 @@ class Alpha_wrap_3 std::cout << m_queue.size() << " facets in the queue" << std::endl; std::cout << "Face " << fid++ << "\n" << "c = " << &*ch << " (" << m_dt.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_dt.is_infinite(neighbor) << ")" << "\n" - << m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl; + << m_dt.point(ch, Dt::vertex_triple_index(id, 0)) << "\n" + << m_dt.point(ch, Dt::vertex_triple_index(id, 1)) << "\n" + << m_dt.point(ch, Dt::vertex_triple_index(id, 2)) << std::endl; std::cout << "Priority: " << gate.priority() << std::endl; #endif @@ -1246,7 +1277,9 @@ class Alpha_wrap_3 std::string face_name = "results/steps/face_" + std::to_string(static_cast(i++)) + ".xyz"; std::ofstream face_out(face_name); face_out.precision(17); - face_out << "3\n" << m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl; + face_out << "3\n" << m_dt.point(ch, Dt::vertex_triple_index(id, 0)) << "\n" + << m_dt.point(ch, Dt::vertex_triple_index(id, 1)) << "\n" + << m_dt.point(ch, Dt::vertex_triple_index(id, 2)) << std::endl; face_out.close(); #endif @@ -1373,7 +1406,7 @@ class Alpha_wrap_3 inc_cells.reserve(64); m_dt.incident_cells(v, std::back_inserter(inc_cells)); - // Flood one inside and outside CC. + // Flood one inside and outside CC within the cell umbrella of the vertex. // Process both an inside and an outside CC to also detect edge pinching. // If there are still unprocessed afterwards, there is a non-manifoldness issue. // @@ -1664,7 +1697,8 @@ class Alpha_wrap_3 private: void check_queue_sanity() { - std::cout << "Check queue sanity..." << std::endl; + std::cout << "\t~~~ Check queue sanity ~~~" << std::endl; + std::vector queue_gates; Gate previous_top_gate = m_queue.top(); while(!m_queue.empty()) @@ -1674,15 +1708,16 @@ class Alpha_wrap_3 const Facet& current_f = current_gate.facet(); const Cell_handle ch = current_f.first; const int id = current_f.second; - const Point_3& p0 = m_dt.point(ch, (id+1)&3); - const Point_3& p1 = m_dt.point(ch, (id+2)&3); - const Point_3& p2 = m_dt.point(ch, (id+3)&3); + const Point_3& p0 = m_dt.point(ch, Dt::vertex_triple_index(id, 0)); + const Point_3& p1 = m_dt.point(ch, Dt::vertex_triple_index(id, 1)); + const Point_3& p2 = m_dt.point(ch, Dt::vertex_triple_index(id, 2)); const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); - std::cout << "At Facet with VID " << get(Gate_ID_PM
(), current_gate) << std::endl; - - if(current_gate.priority() != sqr) - std::cerr << "Error: facet in queue has wrong priority" << std::endl; + std::cout << "At Facet with VID " << get(Gate_ID_PM
(), current_gate) << "\n"; + std::cout << "\t" << p0 << "\n\t" << p1 << "\n\t" << p2 << "\n"; + std::cout << " Artificiality: " << current_gate.is_artificial_facet() << "\n"; + std::cout << " SQR: " << sqr << "\n"; + std::cout << " Priority " << current_gate.priority() << std::endl; if(Less_gate()(current_gate, previous_top_gate)) std::cerr << "Error: current gate has higher priority than the previous top" << std::endl; @@ -1691,7 +1726,8 @@ class Alpha_wrap_3 m_queue.pop(); } - std::cout << "End sanity check" << std::endl; + + std::cout << "\t~~~ End queue sanity check ~~~" << std::endl; // Rebuild CGAL_assertion(m_queue.empty()); From c82f2a9d9c2c082f477b7d5e2af7f57e319e3acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 27 Sep 2023 10:11:31 +0200 Subject: [PATCH 012/133] Update some variable names to reflect the genericity of the triangulation --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 9 +-- .../internal/gate_priority_queue.h | 16 ++--- .../Alpha_wrap_3/internal/geometry_utils.h | 62 +++++++++---------- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index f2ad170c95e7..8f7b1f5efc9c 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -290,7 +290,7 @@ class Alpha_wrap_3 extract_surface(output_mesh, ovpm, true /*tolerate non manifoldness*/); #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP - dump_triangulation_faces("intermediate_dt3.off", false /*only_boundary_faces*/); + dump_triangulation_faces("intermediate_tr.off", false /*only_boundary_faces*/); IO::write_polygon_mesh("intermediate.off", output_mesh, CGAL::parameters::vertex_point_map(ovpm).stream_precision(17)); #endif @@ -350,7 +350,7 @@ class Alpha_wrap_3 #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP IO::write_polygon_mesh("final.off", output_mesh, CGAL::parameters::stream_precision(17)); - dump_triangulation_faces("final_dt3.off", false /*only_boundary_faces*/); + dump_triangulation_faces("final_tr.off", false /*only_boundary_faces*/); #endif #endif @@ -643,7 +643,9 @@ class Alpha_wrap_3 // and we fill the queue with the new parameters. bool initialize_from_existing_triangulation() { - std::cout << "restart from a DT of " << m_tr.number_of_cells() << " cells" << std::endl; +#ifdef CGAL_AW3_DEBUG_INITIALIZATION + std::cout << "Restart from a DT of " << m_tr.number_of_cells() << " cells" << std::endl; +#endif Real_timer t; t.start(); @@ -1050,7 +1052,6 @@ class Alpha_wrap_3 public: // @speed some decent time may be spent constructing Facet (pairs) for no reason as it's always // just to grab the .first and .second as soon as it's constructed, and not due to API requirements - // e.g. from DT3 Facet_queue_status facet_status(const Facet& f) const { CGAL_precondition(!m_tr.is_infinite(f)); diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index 824d27bc2c10..5e14a4d08ea1 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -28,11 +28,11 @@ namespace Alpha_wraps_3 { namespace internal { // Represents an alpha-traversable facet in the mutable priority queue -template +template class Gate { - using Facet = typename DT3::Facet; - using FT = typename DT3::Geom_traits::FT; + using Facet = typename Tr::Facet; + using FT = typename Tr::Geom_traits::FT; private: Facet m_facet; @@ -65,24 +65,24 @@ class Gate struct Less_gate { - template - bool operator()(const Gate& a, const Gate& b) const + template + bool operator()(const Gate& a, const Gate& b) const { return a.priority() > b.priority(); } }; -template +template struct Gate_ID_PM { - using key_type = Gate; + using key_type = Gate; using value_type = std::size_t; using reference = std::size_t; using category = boost::readable_property_map_tag; inline friend value_type get(Gate_ID_PM, const key_type& k) { - using Facet = typename DT3::Facet; + using Facet = typename Tr::Facet; const Facet& f = k.facet(); return (4 * f.first->time_stamp() + f.second); diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h index d3814d0f3b25..7d66cfd19f41 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h @@ -40,16 +40,16 @@ struct Orientation_of_circumcenter } }; -template +template bool -less_squared_radius_of_min_empty_sphere(typename Dt::Geom_traits::FT sq_alpha, - const typename Dt::Facet& fh, - const Dt& dt) +less_squared_radius_of_min_empty_sphere(typename Tr::Geom_traits::FT sq_alpha, + const typename Tr::Facet& fh, + const Tr& tr) { - using Cell_handle = typename Dt::Cell_handle; - using Point = typename Dt::Point; + using Cell_handle = typename Tr::Cell_handle; + using Point = typename Tr::Point; - using CK = typename Dt::Geom_traits; + using CK = typename Tr::Geom_traits; using Exact_kernel = typename Exact_kernel_selector::Exact_kernel; using Approximate_kernel = Simple_cartesian; using C2A = Cartesian_converter; @@ -65,17 +65,17 @@ less_squared_radius_of_min_empty_sphere(typename Dt::Geom_traits::FT sq_alpha, const int ic = fh.second; const Cell_handle n = c->neighbor(ic); - const Point& p1 = dt.point(c, Dt::vertex_triple_index(ic,0)); - const Point& p2 = dt.point(c, Dt::vertex_triple_index(ic,1)); - const Point& p3 = dt.point(c, Dt::vertex_triple_index(ic,2)); + const Point& p1 = tr.point(c, Tr::vertex_triple_index(ic,0)); + const Point& p2 = tr.point(c, Tr::vertex_triple_index(ic,1)); + const Point& p3 = tr.point(c, Tr::vertex_triple_index(ic,2)); // This is not actually possible in the context of alpha wrapping, but keeping it for genericity // and because it does not cost anything. - if(dt.is_infinite(n)) + if(tr.is_infinite(n)) { Orientation ori = orientation_of_circumcenter(p1, p2, p3, - dt.point(c, 0), dt.point(c, 1), - dt.point(c, 2), dt.point(c, 3)); + tr.point(c, 0), tr.point(c, 1), + tr.point(c, 2), tr.point(c, 3)); if(ori == POSITIVE) { @@ -84,18 +84,18 @@ less_squared_radius_of_min_empty_sphere(typename Dt::Geom_traits::FT sq_alpha, } else { - Comparison_result cr = compare_squared_radius(dt.point(c, 0), dt.point(c, 1), - dt.point(c, 2), dt.point(c, 3), + Comparison_result cr = compare_squared_radius(tr.point(c, 0), tr.point(c, 1), + tr.point(c, 2), tr.point(c, 3), sq_alpha); return cr == LARGER; } } - if(dt.is_infinite(c)) + if(tr.is_infinite(c)) { Orientation ori = orientation_of_circumcenter(p1, p2, p3, - dt.point(n, 0), dt.point(n, 1), - dt.point(n, 2), dt.point(n, 3)); + tr.point(n, 0), tr.point(n, 1), + tr.point(n, 2), tr.point(n, 3)); if(ori == NEGATIVE) { @@ -104,8 +104,8 @@ less_squared_radius_of_min_empty_sphere(typename Dt::Geom_traits::FT sq_alpha, } else { - Comparison_result cr = compare_squared_radius(dt.point(n, 0), dt.point(n, 1), - dt.point(n, 2), dt.point(n, 3), + Comparison_result cr = compare_squared_radius(tr.point(n, 0), tr.point(n, 1), + tr.point(n, 2), tr.point(n, 3), sq_alpha); return cr == LARGER; } @@ -113,40 +113,40 @@ less_squared_radius_of_min_empty_sphere(typename Dt::Geom_traits::FT sq_alpha, // both c and n are finite if(orientation_of_circumcenter(p1, p2, p3, - dt.point(c, 0), dt.point(c, 1), dt.point(c, 2), dt.point(c, 3)) != + tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)) != orientation_of_circumcenter(p1, p2, p3, - dt.point(n, 0), dt.point(n, 1), dt.point(n, 2), dt.point(n, 3))) + tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3))) { Comparison_result cr = compare_squared_radius(p1, p2, p3, sq_alpha); #ifdef CGAL_AW3_DEBUG_TRAVERSABILITY std::cout << "dual crosses the face; CR: " - << typename Dt::Geom_traits().compute_squared_radius_3_object()(p1, p2, p3) + << typename Tr::Geom_traits().compute_squared_radius_3_object()(p1, p2, p3) << " sq alpha " << sq_alpha << std::endl; #endif return cr == LARGER; } else { - Comparison_result cr = compare_squared_radius(dt.point(c, 0), dt.point(c, 1), - dt.point(c, 2), dt.point(c, 3), + Comparison_result cr = compare_squared_radius(tr.point(c, 0), tr.point(c, 1), + tr.point(c, 2), tr.point(c, 3), sq_alpha); #ifdef CGAL_AW3_DEBUG_TRAVERSABILITY std::cout << "dual does not cross the face; CR(c): " - << typename Dt::Geom_traits().compute_squared_radius_3_object()(dt.point(c, 0), dt.point(c, 1), - dt.point(c, 2), dt.point(c, 3)) + << typename Tr::Geom_traits().compute_squared_radius_3_object()(tr.point(c, 0), tr.point(c, 1), + tr.point(c, 2), tr.point(c, 3)) << " sq alpha " << sq_alpha << std::endl; #endif if(cr != LARGER) return false; - cr = compare_squared_radius(dt.point(n, 0), dt.point(n, 1), - dt.point(n, 2), dt.point(n, 3), + cr = compare_squared_radius(tr.point(n, 0), tr.point(n, 1), + tr.point(n, 2), tr.point(n, 3), sq_alpha); #ifdef CGAL_AW3_DEBUG_TRAVERSABILITY std::cout << "dual does not cross the face; CR(n): " - << typename Dt::Geom_traits().compute_squared_radius_3_object()(dt.point(n, 0), dt.point(n, 1), - dt.point(n, 2), dt.point(n, 3)) + << typename Tr::Geom_traits().compute_squared_radius_3_object()(tr.point(n, 0), tr.point(n, 1), + tr.point(n, 2), tr.point(n, 3)) << " sq alpha " << sq_alpha << std::endl; #endif From 62bb2a58d098dc08076f2165d104670dfa65388a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 27 Sep 2023 10:13:39 +0200 Subject: [PATCH 013/133] Put the warnings outside of verbosity macros (too important) --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 8f7b1f5efc9c..3ee6061d0d89 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1173,15 +1173,11 @@ class Alpha_wrap_3 return false; } - if(resuming) - { - if(offset != m_offset) - { -#ifdef CGAL_AW3_DEBUG - std::cerr << "Warning: resuming with a different offset!" << std::endl; -#endif - } - } + if(resuming && alpha > m_alpha) + std::cerr << "Warning: resuming with an alpha greater than last iteration!" << std::endl; + + if(resuming && offset != m_offset) + std::cerr << "Warning: resuming with a different offset!" << std::endl; m_alpha = FT(alpha); m_sq_alpha = square(m_alpha); From bc8351f15678b90955a9d5c2a5cc4b0389b49642 Mon Sep 17 00:00:00 2001 From: Mael Date: Wed, 27 Sep 2023 11:06:49 +0200 Subject: [PATCH 014/133] Fix typo --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 6d544be058d6..639c9a3f4685 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1418,7 +1418,7 @@ class Alpha_wrap_3 squared_distance(m_dt.point(c, 0), m_dt.point(c, 2)), squared_distance(m_dt.point(c, 0), m_dt.point(c, 3)), squared_distance(m_dt.point(c, 1), m_dt.point(c, 2)), - squared_distance(m_dt.point(c, 3), m_dt.point(c, 3)), + squared_distance(m_dt.point(c, 1), m_dt.point(c, 3)), squared_distance(m_dt.point(c, 2), m_dt.point(c, 3)) }); }; From 00f167a8357ab5fe72fb22e0a547c5543f8f1d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 29 Sep 2023 11:02:47 +0200 Subject: [PATCH 015/133] Add benchmarking scripts --- .../benchmark/Alpha_wrap_3/CMakeLists.txt | 15 + .../compute_performance_benchmark_data.py | 61 ++++ .../generate_performance_benchmark_charts.py | 156 ++++++++++ .../Performance/performance_benchmark.cpp | 65 +++++ .../Quality/compute_quality_benchmark_data.py | 54 ++++ .../Alpha_wrap_3/Quality/distance_utils.h | 151 ++++++++++ .../generate_quality_benchmark_charts.py | 182 ++++++++++++ .../Quality/quality_benchmark.cpp | 271 ++++++++++++++++++ .../compute_robustness_benchmark_data.py | 96 +++++++ .../generate_robustness_benchmark_charts.py | 154 ++++++++++ .../Robustness/robustness_benchmark.cpp | 106 +++++++ .../benchmark/Alpha_wrap_3/benchmarking.sh | 86 ++++++ .../CGAL/Alpha_wrap_3/internal/validation.h} | 0 .../test_AW3_cavity_initializations.cpp | 2 +- .../Alpha_wrap_3/test_AW3_manifoldness.cpp | 2 +- .../Alpha_wrap_3/test_AW3_multiple_calls.cpp | 2 +- .../Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp | 2 +- 17 files changed, 1401 insertions(+), 4 deletions(-) create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/CMakeLists.txt create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/compute_performance_benchmark_data.py create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/generate_performance_benchmark_charts.py create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/performance_benchmark.cpp create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/compute_quality_benchmark_data.py create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/distance_utils.h create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/generate_quality_benchmark_charts.py create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp create mode 100755 Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/generate_robustness_benchmark_charts.py create mode 100644 Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp create mode 100755 Alpha_wrap_3/benchmark/Alpha_wrap_3/benchmarking.sh rename Alpha_wrap_3/{test/Alpha_wrap_3/alpha_wrap_validation.h => include/CGAL/Alpha_wrap_3/internal/validation.h} (100%) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/CMakeLists.txt b/Alpha_wrap_3/benchmark/Alpha_wrap_3/CMakeLists.txt new file mode 100644 index 000000000000..a9aa0d1d63cb --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/CMakeLists.txt @@ -0,0 +1,15 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + +cmake_minimum_required(VERSION 3.1...3.20) +project(Alpha_wrap_3_Benchmark) + +find_package(CGAL REQUIRED) + +include_directories (BEFORE ../../include ./Quality ./Robustness) # AW3 includes +include_directories (BEFORE ../../../CGAL-Patches/include) + +# create a target per cppfile +create_single_source_cgal_program("Performance/performance_benchmark.cpp") +create_single_source_cgal_program("Quality/quality_benchmark.cpp") +create_single_source_cgal_program("Robustness/robustness_benchmark.cpp") diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/compute_performance_benchmark_data.py b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/compute_performance_benchmark_data.py new file mode 100644 index 000000000000..86c57d351465 --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/compute_performance_benchmark_data.py @@ -0,0 +1,61 @@ +# Copyright (c) 2019-2023 Google LLC (USA). +# All rights reserved. +# +# This file is part of CGAL (www.cgal.org). +# +# $URL$ +# $Id$ +# SPDX-License-Identifier: GPL-3.0-or-later +# +# +# Author(s) : Pierre Alliez +# Michael Hemmer +# Cedric Portaneri +# +#!/usr/bin/python + +import os, sys, subprocess, datetime, time, getopt + +def compute_performance_benchmark_data(execname, filename, alpha): + + output = "" + cmd = ("/usr/bin/time", "-v", + execname, "-i", + filename, "-a", alpha) + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + start_new_session=True) + + outs, errs = proc.communicate() + output = outs.decode("utf-8") + errs.decode("utf-8") + + for output_line in output.split("\n"): + if "User time (seconds): " in output_line: + print(output_line[len("User time (seconds): "):]) + continue + if "Maximum resident set size (kbytes): " in output_line: + print(output_line[len("Maximum resident set size (kbytes): "):]) + continue + +def main(argv): + execname="" + filename="" + alpha="" + try: + opts, args = getopt.getopt(sys.argv[1:], 'e:i:a:') + except getopt.GetoptError: + sys.exit(2) + for opt, arg in opts: + if opt == "-e": + execname = arg + elif opt == "-i": + filename = arg + elif opt == "-a": + alpha = arg + + compute_performance_benchmark_data(execname, filename, alpha) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/generate_performance_benchmark_charts.py b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/generate_performance_benchmark_charts.py new file mode 100644 index 000000000000..445b69232778 --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/generate_performance_benchmark_charts.py @@ -0,0 +1,156 @@ +# Copyright (c) 2019-2023 Google LLC (USA). +# All rights reserved. +# +# This file is part of CGAL (www.cgal.org). +# +# $URL$ +# $Id$ +# SPDX-License-Identifier: GPL-3.0-or-later +# +# +# Author(s) : Pierre Alliez +# Michael Hemmer +# Cedric Portaneri +# +#!/usr/bin/python + +import os, sys, subprocess, datetime, time, signal, getopt +import numpy as np +import matplotlib.pyplot as plt + +def main(argv): + + inputdir="" + outputdir="" + commit_hash="" + alpha="" + do_diff=False + diffdir="" + diff_hash="" + try: + opts, args = getopt.getopt(sys.argv[1:], 'i:a:o:c:d:p:') + except getopt.GetoptError: + sys.exit(2) + for opt, arg in opts: + if opt == "-i": + inputdir = arg + elif opt == "-a": + alpha = arg + elif opt == "-o": + outputdir = arg + elif opt == "-c": + commit_hash = arg + elif opt == "-d": + diff_hash = arg + do_diff = True + elif opt == "-p": + diffdir = arg + + all_metric = { + "Time_(second)" : {}, + "Memory_Peak_(kbytes)" : {}} + num_input = 0 + for filename in os.listdir(inputdir) : + new_path = os.path.join(inputdir,filename) + new_file = open(new_path) + is_empty_new = os.path.getsize(new_path) <= 1 + if do_diff : + old_path = os.path.join(diffdir,filename) + old_file = open(old_path) + is_empty_old = os.path.getsize(old_path) <= 1 + for key in all_metric: + if is_empty_new or is_empty_old : + new_val = 0. + old_val = 0. + else : + new_val = float(new_file.readline().rstrip('\n')) + old_val = float(old_file.readline().rstrip('\n')) + mesh_id = str(filename.split('.')[0]) + all_metric[key][mesh_id] = [new_val, old_val] + else : + for key in all_metric: + if is_empty_new : + new_val = 0. + else : + new_val = float(new_file.readline().rstrip('\n')) + mesh_id = str(filename.split('.')[0]) + all_metric[key][mesh_id] = [new_val, new_val] + num_input = num_input+1 + + # update .pdf chart + date_now = datetime.datetime.now() + date_for_filename = str(date_now.year) +"_"+ str(date_now.month) +"_"+ str(date_now.day) +"_"+ str(date_now.hour) +"h"+ str(date_now.minute) +"mn" + for key in all_metric: + goal = 0 + num_el = range(len(all_metric[key])) + avg_diff_to_goal = 0. + avg = 0. + x1 = [] + x2 = [] + for value in all_metric[key].values() : + avg += value[0] + diff_to_goal = abs(value[1]-goal) - abs(value[0]-goal) + avg_diff_to_goal += diff_to_goal + x1.append(value[0]) + x2.append(value[1]) + avg_diff_to_goal /= float(len(all_metric[key])) + avg /= float(len(all_metric[key])) + + plt.figure(figsize=(8,8)) + if do_diff : + plt.hist(x2, bins=100, color='tab:green', alpha=0.5) + plt.hist(x1, bins=100, color='tab:blue', alpha=0.5) + plt.vlines(x = goal, ymin=plt.ylim()[0], ymax=plt.ylim()[1], linestyles='dashed') + + title = "" + if do_diff : + title += "Diff between " + commit_hash + " and " + diff_hash + " on " + str(num_input) + " meshes from Thingi10K\nAlpha = Bbox diag length / " + alpha + else : + title += "Benchmarking on " + str(num_input) + " meshes from Thingi10K\nAlpha = Bbox diag length / " + alpha + + avg_str = str(format(abs(avg), '.2f')) + if key == "Time_(second)" : + title += "\nIn average we spend " + avg_str + " seconds" + else : + title += "\nIn average we use up to " + avg_str + " kbytes" + + if do_diff and avg_diff_to_goal == 0. : + title += "\nNo change between the two commits" + elif do_diff : + avg_diff_str = str(format(abs(avg_diff_to_goal), '.2f')) + if key == "Time_(second)" : + if avg_diff_to_goal < 0 : + title += "\nIn average we get slower by " + else : + title += "\nIn average we get faster " + title += avg_diff_str + " seconds" + else : + if avg_diff_to_goal < 0 : + title += "\nIn average we use " + avg_diff_str + " more" + else : + title += "\nIn average we use " + avg_diff_str + " less" + title += " kbytes" + + plt.title(title, fontsize=15) + plt.xlabel(key.replace("_"," "), fontsize=14) + plt.ylabel("# of meshes", fontsize=14) + plt.tick_params(axis="x", labelsize=9) + plt.tick_params(axis="y", labelsize=9) + + chart_filename = "" + if do_diff : + chart_filename += "diff_"+commit_hash+"_"+diff_hash+"_"+key+"_"+date_for_filename+".pdf" + else : + chart_filename += "results_"+commit_hash+"_"+key+"_"+date_for_filename+".pdf" + chart_path = os.path.join(outputdir+"/charts",chart_filename) + if os.path.isfile(chart_path) : + os.remove(chart_path) + plt.savefig(chart_path, bbox_inches="tight") + plt.close() + + print("pdf updated") + + sys.exit() + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/performance_benchmark.cpp b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/performance_benchmark.cpp new file mode 100644 index 000000000000..207b4704635a --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/performance_benchmark.cpp @@ -0,0 +1,65 @@ +#include +#include + +#include + +#include + +#include +#include +#include +#include + +using K = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = K::Point_3; +using Vector_3 = K::Vector_3; + +using Mesh = CGAL::Surface_mesh; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) +{ + const int argc_check = argc - 1; + const char* entry_name_ptr = nullptr; + double relative_alpha_ratio = 20., relative_offset_ratio = 600.; + + for(int i=1; i points; + std::vector > faces; + if(!CGAL::IO::read_polygon_soup(entry_name_ptr, points, faces) || faces.empty()) + { + std::cerr << "Error: Invalid input data." << std::endl; + return EXIT_FAILURE; + } + + CGAL::Bbox_3 bbox; + for(const Point_3& p : points) + bbox += p.bbox(); + + const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) + + CGAL::square(bbox.ymax() - bbox.ymin()) + + CGAL::square(bbox.zmax() - bbox.zmin())); + const double alpha = diag_length / relative_alpha_ratio; + const double offset = diag_length / relative_offset_ratio; + + Mesh wrap; + CGAL::alpha_wrap_3(points, faces, alpha, offset, wrap); + + return EXIT_SUCCESS; +} diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/compute_quality_benchmark_data.py b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/compute_quality_benchmark_data.py new file mode 100644 index 000000000000..3b996cb57490 --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/compute_quality_benchmark_data.py @@ -0,0 +1,54 @@ +# Copyright (c) 2019-2023 Google LLC (USA). +# All rights reserved. +# +# This file is part of CGAL (www.cgal.org). +# +# $URL$ +# $Id$ +# SPDX-License-Identifier: GPL-3.0-or-later +# +# +# Author(s) : Pierre Alliez +# Michael Hemmer +# Cedric Portaneri +# +#!/usr/bin/python + +import os, sys, subprocess, datetime, time, getopt + +def compute_quality_benchmark_data(execname, filename, alpha): + + output = "" + cmd = (execname, "-i", + filename, "-a", alpha) + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + start_new_session=True) + + outs, errs = proc.communicate() + output = outs.decode("utf-8") + errs.decode("utf-8") + + print(output) + +def main(argv): + execname="" + filename="" + alpha="" + try: + opts, args = getopt.getopt(sys.argv[1:], 'e:i:a:') + except getopt.GetoptError: + sys.exit(2) + for opt, arg in opts: + if opt == "-e": + execname = arg + elif opt == "-i": + filename = arg + elif opt == "-a": + alpha = arg + + compute_quality_benchmark_data(execname, filename, alpha) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/distance_utils.h b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/distance_utils.h new file mode 100644 index 000000000000..379573e9c90a --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/distance_utils.h @@ -0,0 +1,151 @@ +// Copyright (c) 2019-2022 Google LLC (USA). +// 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) : Pierre Alliez +// Michael Hemmer +// Cedric Portaneri + +#ifndef CGAL_ALPHA_WRAP_3_BENCHMARK_ALPHA_WRAP_3_QUALITY_DISTANCE_H_ +#define CGAL_ALPHA_WRAP_3_BENCHMARK_ALPHA_WRAP_3_QUALITY_DISTANCE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Aw3i { + +enum Distance_metric { HAUSDORFF = 0, MEAN = 1, RMS = 2 }; + +template +inline double approximate_hausdorff_distance(const std::vector& sample_points, + const AABBTree& tree, + Point& hint) +{ + double hdist = 0; + for(const Point& pt : sample_points) + { + hint = tree.closest_point(pt, hint); + auto dist = CGAL::squared_distance(hint, pt); + double d = CGAL::to_double(CGAL::approximate_sqrt(dist)); + if(d > hdist) + hdist = d; + } + + return hdist; +} + +template +inline double approximate_mean_distance(const std::vector& sample_points, + const AABBTree& tree, + Point& hint) +{ + double mdist = 0; + for(const Point& pt : sample_points) + { + hint = tree.closest_point(pt, hint); + auto dist = CGAL::squared_distance(hint, pt); + double d = CGAL::to_double(CGAL::approximate_sqrt(dist)); + mdist += d; + } + + return mdist / sample_points.size(); +} + +template +inline double approximate_rms_distance(const std::vector& sample_points, + const AABBTree& tree, + Point& hint) +{ + double rmsdist = 0; + for(const Point& pt : sample_points) + { + hint = tree.closest_point(pt, hint); + auto dist = CGAL::squared_distance(hint, pt); + rmsdist += CGAL::to_double(dist); + } + + return CGAL::to_double(CGAL::approximate_sqrt(rmsdist / sample_points.size())); +} + +template +inline double approximate_distance(const TriangleMesh& tm1, + const TriangleMesh& tm2, + const Distance_metric& metric) +{ + using GT = typename CGAL::GetGeomTraits::type; + using Point_3 = typename GT::Point_3; + + using Primitive = CGAL::AABB_face_graph_triangle_primitive; + using AABB_traits = CGAL::AABB_traits; + using AABB_tree = CGAL::AABB_tree; + + using CGAL::parameters::choose_parameter; + using CGAL::parameters::get_parameter; + + std::vector original_sample_points; + CGAL::Polygon_mesh_processing::sample_triangle_mesh(tm1, std::back_inserter(original_sample_points), + CGAL::parameters::all_default()); + + std::vector sample_points(std::begin(original_sample_points), + std::end(original_sample_points)); + CGAL::spatial_sort(sample_points.begin(), sample_points.end()); + + AABB_tree tree(faces(tm2).first, faces(tm2).second, tm2); + tree.build(); + + auto vpm_2 = get(CGAL::vertex_point, tm2); + Point_3 hint = get(vpm_2, *vertices(tm2).first); + + if(metric == HAUSDORFF) + return approximate_hausdorff_distance(sample_points, tree, hint); + else if(metric == MEAN) + return approximate_mean_distance(sample_points, tree, hint); + else if(metric == RMS) + return approximate_rms_distance(sample_points, tree, hint); + else + std::cerr << "Metric unknown\n" << std::endl; + + return -1.0; +} + +template +double get_longest_diag_bbox(const TriangleMesh& tm) +{ + CGAL::Bbox_3 bbox = CGAL::Polygon_mesh_processing::bbox(tm); + return std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) + + CGAL::square(bbox.ymax() - bbox.ymin()) + + CGAL::square(bbox.zmax() - bbox.zmin())); +} + +template +inline double approximate_distance_relative_to_bbox(const TriangleMesh& tm1, + const TriangleMesh& tm2, + const Distance_metric& metric) +{ + double longest_diag_length = get_longest_diag_bbox(tm1); + return approximate_distance(tm1, tm2, metric) / longest_diag_length; +} + +template +inline double approximate_distance_relative_to_bbox(const TriangleMesh& tm1, + const TriangleMesh& tm2, + const Distance_metric& metric, + const FT& longest_diag_length) +{ + return approximate_distance(tm1, tm2, metric) / CGAL::to_double(longest_diag_length); +} + +} // namespace Aw3i + +#endif // CGAL_CGAL_ALPHA_WRAP_3_BENCHMARK_ALPHA_WRAP_3_QUALITY_DISTANCE_H_ diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/generate_quality_benchmark_charts.py b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/generate_quality_benchmark_charts.py new file mode 100644 index 000000000000..0df5ed5e0f4e --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/generate_quality_benchmark_charts.py @@ -0,0 +1,182 @@ +# Copyright (c) 2019-2023 Google LLC (USA). +# All rights reserved. +# +# This file is part of CGAL (www.cgal.org). +# +# $URL$ +# $Id$ +# SPDX-License-Identifier: GPL-3.0-or-later +# +# +# Author(s) : Pierre Alliez +# Michael Hemmer +# Cedric Portaneri +# +#!/usr/bin/python + +import os, sys, subprocess, datetime, time, signal, getopt +import numpy as np +import matplotlib.pyplot as plt + +def main(argv): + + inputdir="" + outputdir="" + commit_hash="" + alpha="" + do_diff=False + diffdir="" + diff_hash="" + try: + opts, args = getopt.getopt(sys.argv[1:], 'i:a:o:c:d:p:') + except getopt.GetoptError: + sys.exit(2) + for opt, arg in opts: + if opt == "-i": + inputdir = arg + elif opt == "-a": + alpha = arg + elif opt == "-o": + outputdir = arg + elif opt == "-c": + commit_hash = arg + elif opt == "-d": + diff_hash = arg + do_diff = True + elif opt == "-p": + diffdir = arg + + all_metric = { + "Mean_Min_Angle_(degree)" : {}, + "Mean_Max_Angle_(degree)" : {}, + "Mean_Radius_Ratio" : {}, + "Mean_Edge_Ratio" : {}, + "Mean_Aspect_Ratio" : {}, + "Complexity_(#_of_triangle)" : {}, + "#_of_almost_degenerate_triangle" : {}, + "Hausdorff_distance_output_to_input_(%_of_bbox_diag)" : {}} + num_input = 0 + print("inputdir = ", inputdir) + for filename in os.listdir(inputdir) : + new_path = os.path.join(inputdir,filename) + new_file = open(new_path) + if do_diff : + old_path = os.path.join(diffdir,filename) + old_file = open(old_path) + is_empty_old = os.path.getsize(old_path) <= 1 + for key in all_metric : + try : + new_val = float(new_file.readline().rstrip('\n')) + old_val = float(old_file.readline().rstrip('\n')) + mesh_id = str(filename.split('.')[0]) + all_metric[key][mesh_id] = [new_val, old_val] + except ValueError: + pass + else : + for key in all_metric : + try : + new_val = float(new_file.readline().rstrip('\n')) + mesh_id = str(filename.split('.')[0]) + all_metric[key][mesh_id] = [new_val, new_val] + except ValueError: + pass + num_input = num_input+1 + + # update .pdf chart + date_now = datetime.datetime.now() + date_for_filename = str(date_now.year) +"_"+ str(date_now.month) +"_"+ str(date_now.day) +"_"+ str(date_now.hour) +"h"+ str(date_now.minute) +"mn" + for key in all_metric: + goal = 0 + if key == "Mean_Min_Angle_(degree)" or key == "Mean_Max_Angle_(degree)": + goal = 60 + elif key == "Mean_Radius_Ratio" or key == "Mean_Edge_Ratio" or key == "Mean_Aspect_Ratio" : + goal = 1 + + num_el = range(len(all_metric[key])) + avg_diff_to_goal = 0. + avg = 0. + x1 = [] + x2 = [] + for value in all_metric[key].values() : + avg += value[0] + diff_to_goal = abs(value[1]-goal) - abs(value[0]-goal) + avg_diff_to_goal += diff_to_goal + x1.append(value[0]) + x2.append(value[1]) + avg_diff_to_goal /= float(len(all_metric[key])) + avg /= float(len(all_metric[key])) + + plt.figure(figsize=(8,8)) + if do_diff : + plt.hist(x2, bins=100, color='tab:green', alpha=0.5) + plt.hist(x1, bins=100, color='tab:blue', alpha=0.5) + plt.vlines(x = goal, ymin=plt.ylim()[0], ymax=plt.ylim()[1], linestyles='dashed') + + title = "" + if do_diff : + title += "Diff between " + commit_hash + " and " + diff_hash + " on " + str(num_input) + " meshes from Thingi10K\nAlpha = Bbox diag length / " + alpha + else : + title += "Benchmarking on " + str(num_input) + " meshes from Thingi10K\nAlpha = Bbox diag length / " + alpha + + avg_str = str(format(abs(avg), '.2f')) + if key == "Mean_Min_Angle_(degree)" or key == "Mean_Max_Angle_(degree)": + title += "\nIn average we have " + avg_str + "ยฐ" + elif key == "Mean_Radius_Ratio" or key == "Mean_Edge_Ratio" or key == "Mean_Aspect_Ratio" : + title += "\nIn average we have a ratio of " + avg_str + elif key == "Hausdorff_distance_output_to_input_(%_of_bbox_diag)" : + title += "\nIn average we have a distance of " + avg_str + "% of bbox diag" + elif key == "Complexity_(#_of_triangle)" or key == "#_of_almost_degenerate_triangle" : + title += "\nIn average we have " + avg_str + " triangles" + + if do_diff and avg_diff_to_goal == 0. : + title += "\nNo change between the two commits" + elif do_diff : + avg_diff_str = str(format(abs(avg_diff_to_goal), '.2f')) + if key == "Mean_Min_Angle_(degree)" or key == "Mean_Max_Angle_(degree)": + if avg_diff_to_goal < 0 : + title += "\nIn average we loose " + else : + title += "\nIn average we gain " + title += avg_diff_str + "ยฐ toward 60ยฐ" + elif key == "Mean_Radius_Ratio" or key == "Mean_Edge_Ratio" or key == "Mean_Aspect_Ratio" : + if avg_diff_to_goal < 0 : + title += "\nIn average we loose " + else : + title += "\nIn average we gain " + title += avg_diff_str + " of ratio toward 1" + elif key == "Hausdorff_distance_output_to_input_(%_of_bbox_diag)" : + if avg_diff_to_goal < 0 : + title += "\nIn average we increase by " + else : + title += "\nIn average we reduce by " + title += avg_diff_str + " the bbox ratio" + elif key == "Complexity_(#_of_triangle)" or key == "#_of_almost_degenerate_triangle" : + if avg_diff_to_goal < 0 : + title += "\nIn average we get " + avg_diff_str + " more" + else : + title += "\nIn average we get " + avg_diff_str + " less" + title += " triangles" + + plt.title(title, fontsize=15) + plt.xlabel(key.replace("_"," "), fontsize=14) + plt.ylabel("# of meshes", fontsize=14) + plt.tick_params(axis="x", labelsize=9) + plt.tick_params(axis="y", labelsize=9) + + chart_filename = "" + if do_diff : + chart_filename += "diff_"+commit_hash+"_"+diff_hash+"_"+key+"_"+date_for_filename+".pdf" + else : + chart_filename += "results_"+commit_hash+"_"+key+"_"+date_for_filename+".pdf" + chart_path = os.path.join(outputdir+"/charts",chart_filename) + if os.path.isfile(chart_path) : + os.remove(chart_path) + plt.savefig(chart_path, bbox_inches="tight") + plt.close() + + print("pdf updated") + + sys.exit() + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp new file mode 100644 index 000000000000..4565cca641a1 --- /dev/null +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp @@ -0,0 +1,271 @@ +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = Kernel::Point_3; +using Vector_3 = Kernel::Vector_3; +using Triangle_3 = Kernel::Triangle_3; +using FT = Kernel::FT; + +using Mesh = CGAL::Surface_mesh; +using face_descriptor = boost::graph_traits::face_descriptor; + +using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle; +using Dt = CGAL::Alpha_wraps_3::internal::Alpha_wrap_3::Triangulation; + +namespace PMP = CGAL::Polygon_mesh_processing; + +std::array triangle_angles(const Triangle_3& tr) +{ + FT sq_a = CGAL::squared_distance(tr[0], tr[1]); + FT sq_b = CGAL::squared_distance(tr[1], tr[2]); + FT sq_c = CGAL::squared_distance(tr[2], tr[0]); + + FT two_ab = 2. * CGAL::sqrt(sq_a) * CGAL::sqrt(sq_b); + FT two_bc = 2. * CGAL::sqrt(sq_b) * CGAL::sqrt(sq_c); + FT two_ca = 2. * CGAL::sqrt(sq_c) * CGAL::sqrt(sq_a); + + FT angle_a = (sq_b + sq_c - sq_a) / two_bc; + FT angle_b = (sq_c + sq_a - sq_b) / two_ca; + FT angle_c = (sq_a + sq_b - sq_c) / two_ab; + if(angle_a < -1.) angle_a = -1.; + if(angle_b < -1.) angle_b = -1.; + if(angle_c < -1.) angle_c = -1.; + if(angle_a > 1.) angle_a = 1.; + if(angle_b > 1.) angle_b = 1.; + if(angle_c > 1.) angle_c = 1.; + angle_a = std::acos(angle_a); + angle_b = std::acos(angle_b); + angle_c = std::acos(angle_c); + + return {angle_a, angle_b, angle_c}; +} + +bool is_almost_degenerate(const Triangle_3& tr, + double threshold) +{ + FT sq_area = tr.squared_area(); + return (CGAL::sqrt(CGAL::to_double(sq_area)) < threshold); +} + +auto surface_mesh_face_to_triangle(const face_descriptor fd, + const Mesh& sm) +{ + typename boost::graph_traits::halfedge_descriptor hd = halfedge(fd,sm); + return Triangle_3(sm.point(target(hd,sm)), + sm.point(target(next(hd,sm),sm)), + sm.point(target(next(next(hd,sm),sm),sm))); +} + +double mean_min_angle(const Mesh& mesh) +{ + double mean_min_angle = 0.; + for(const face_descriptor f : faces(mesh)) + { + const Triangle_3 tr = surface_mesh_face_to_triangle(f, mesh); + std::array angles = triangle_angles(tr); + + FT min_angle = std::min({angles[0], angles[1], angles[2]}); + + min_angle = min_angle * (180.0 / CGAL_PI); + mean_min_angle += min_angle; + } + + mean_min_angle /= static_cast(mesh.number_of_faces()); + return mean_min_angle; +} + +double mean_max_angle(const Mesh& mesh) +{ + double mean_max_angle = 0.; + for(const face_descriptor f : faces(mesh)) + { + const Triangle_3 tr = surface_mesh_face_to_triangle(f, mesh); + std::array angles = triangle_angles(tr); + + FT max_angle = std::max({angles[0], angles[1], angles[2]}); + + max_angle = max_angle * (180.0 / CGAL_PI); + mean_max_angle += max_angle; + } + + mean_max_angle /= static_cast(mesh.number_of_faces()); + return mean_max_angle; +} + +double mean_radius_ratio(const Mesh& mesh, + double degenerate_threshold) +{ + double mean_radius_ratio = 0.; + size_t num_almost_degenerate_tri = 0; + for(const face_descriptor f : faces(mesh)) + { + const Triangle_3 tr = surface_mesh_face_to_triangle(f, mesh); + if(is_almost_degenerate(tr, degenerate_threshold)) + { + ++num_almost_degenerate_tri; + continue; + } + + FT circumsphere_radius = std::sqrt(CGAL::squared_radius(tr[0], tr[1], tr[2])); + + FT a = std::sqrt(CGAL::squared_distance(tr[0], tr[1])); + FT b = std::sqrt(CGAL::squared_distance(tr[1], tr[2])); + FT c = std::sqrt(CGAL::squared_distance(tr[2], tr[0])); + FT s = 0.5 * (a + b + c); + FT inscribed_radius = std::sqrt((s * (s - a) * (s - b) * (s - c)) / s); + FT radius_ratio = circumsphere_radius / inscribed_radius; + radius_ratio /= 2.; // normalized + mean_radius_ratio += radius_ratio; + } + + mean_radius_ratio /= static_cast(mesh.number_of_faces() - num_almost_degenerate_tri); + return mean_radius_ratio; +} + +double mean_edge_ratio(const Mesh& mesh, + double degenerate_threshold) +{ + double mean_edge_ratio = 0.; + size_t num_almost_degenerate_tri = 0; + + for(const face_descriptor f : faces(mesh)) + { + const Triangle_3 tr = surface_mesh_face_to_triangle(f, mesh); + if(is_almost_degenerate(tr, degenerate_threshold)) + { + ++num_almost_degenerate_tri; + continue; + } + + FT a = std::sqrt(CGAL::squared_distance(tr[0], tr[1])); + FT b = std::sqrt(CGAL::squared_distance(tr[1], tr[2])); + FT c = std::sqrt(CGAL::squared_distance(tr[2], tr[0])); + FT min_edge = std::min({a, b, c}); + FT max_edge = std::max({a, b, c}); + FT edge_ratio = max_edge / min_edge; + + mean_edge_ratio += edge_ratio; + } + + mean_edge_ratio /= static_cast(mesh.number_of_faces() - num_almost_degenerate_tri); + return mean_edge_ratio; +} + +double mean_aspect_ratio(const Mesh& mesh, + double degenerate_threshold) +{ + double mean_aspect_ratio = 0.; + size_t num_almost_degenerate_tri = 0; + for(const face_descriptor f : faces(mesh)) + { + const Triangle_3 tr = surface_mesh_face_to_triangle(f, mesh); + if(is_almost_degenerate(tr, degenerate_threshold)) + { + ++num_almost_degenerate_tri; + continue; + } + + FT a = std::sqrt(CGAL::squared_distance(tr[0], tr[1])); + FT b = std::sqrt(CGAL::squared_distance(tr[1], tr[2])); + FT c = std::sqrt(CGAL::squared_distance(tr[2], tr[0])); + FT s = 0.5 * (a + b + c); + FT inscribed_radius = std::sqrt((s * (s - a) * (s - b) * (s - c)) / s); + FT max_edge = std::max({a, b, c}); + FT aspect_ratio = max_edge / inscribed_radius; + aspect_ratio /= (2. * std::sqrt(3.)); // normalized + mean_aspect_ratio += aspect_ratio; + } + + mean_aspect_ratio /= static_cast(mesh.number_of_faces() - num_almost_degenerate_tri); + return mean_aspect_ratio; +} + +size_t num_almost_degenerate_tri(const Mesh& mesh, + double degenerate_threshold) +{ + size_t num_almost_degenerate_tri = 0; + for(const face_descriptor f : faces(mesh)) + { + const Triangle_3 tr = surface_mesh_face_to_triangle(f, mesh); + if(is_almost_degenerate(tr, degenerate_threshold)) + { + ++num_almost_degenerate_tri; + } + } + return num_almost_degenerate_tri; +} + +int main(int argc, char** argv) +{ + const int argc_check = argc - 1; + char *entry_name_ptr = nullptr; + double relative_alpha_ratio = 20.; + double relative_offset_ratio = 600.; + + for(int i=1; i +#include + +#include +#include + +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = Kernel::Point_3; +using Mesh = CGAL::Surface_mesh; + +namespace CGAL { +namespace Alpha_wraps_3 { +namespace internal { +namespace { + +enum Robustness_benchmark_exit_code +{ + // Success + VALID_SOLID_OUTPUT = 0, + + // Failure + OUTPUT_IS_NOT_TRIANGLE_MESH = 1, + OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD = 2, + OUTPUT_HAS_BORDERS = 3, + OUTPUT_HAS_DEGENERATED_FACES = 4, + OUTPUT_HAS_GEOMETRIC_SELF_INTERSECTIONS = 5, + OUTPUT_DOES_NOT_BOUND_VOLUME = 6, + OUTPUT_DOES_NOT_CONTAIN_INPUT = 7, + OUTPUT_DISTANCE_IS_TOO_LARGE = 8, +}; + +} // namespace +} // namespace internal +} // namespace Alpha_wraps_3 +} // namespace CGAL + +namespace PMP = CGAL::Polygon_mesh_processing; +namespace AW3i = CGAL::Alpha_wraps_3::internal; + +int main(int argc, char** argv) +{ + const int argc_check = argc - 1; + char* entry_name_ptr = nullptr; + double relative_alpha_ratio = 20.; + double relative_offset_ratio = 600.; + + for(int i=1; i $2/Robustness/results/$5/$filename.log + + python3 $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/compute_performance_benchmark_data.py \ + -e $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/build-release/performance_benchmark -i $6 -a $3 \ + > $2/Performance/results/$5/$filename.log + + python3 $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/compute_quality_benchmark_data.py \ + -e $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/build-release/quality_benchmark -i $6 -a $3 \ + > $2/Quality/results/$5/$filename.log +} +export -f compute_benchmark_data + +# $1: directory containing the alpha wrap project +# $2: directory containing the input data folder +# $3: directory containing the output results +# $4: alpha value +# $5: timeout value for robustness benchmark in seconds +# $6: number of virtual thread used +# $7: hash of the latest commit +# $8: hash of a commit to perform the diff with latest +cd $1 + +mkdir -p $3/Robustness/results/$7 +mkdir -p $3/Performance/results/$7 +mkdir -p $3/Quality/results/$7 +mkdir -p $3/Robustness/charts_data +mkdir -p $3/Performance/charts_data +mkdir -p $3/Quality/charts_data +mkdir -p $3/Robustness/charts +mkdir -p $3/Performance/charts +mkdir -p $3/Quality/charts +mkdir -p $3/Robustness/log +mkdir -p $3/Performance/log +mkdir -p $3/Quality/log +mkdir -p $3/charts + +find $2 -mindepth 1 | parallel -j$6 compute_benchmark_data $1 $3 $4 $5 $7 ::: + +python3 $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/generate_robustness_benchmark_charts.py -i $3/Robustness/results/$7 -o $3/Robustness -a $4 -c $7 + +if [ -z "$8" ]; then + python3 $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/generate_performance_benchmark_charts.py -i $3/Performance/results/$7 -o $3/Performance -a $4 -c $7; +else + python3 $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/Performance/generate_performance_benchmark_charts.py -i $3/Performance/results/$7 -o $3/Performance -a $4 -c $7 -p $3/Performance/results/$8 -d $8; +fi + +if [ -z "$8" ]; then + python3 $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/generate_quality_benchmark_charts.py -i $3/Quality/results/$7 -o $3/Quality -a $4 -c $7; +else + python3 $1/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/generate_quality_benchmark_charts.py -i $3/Quality/results/$7 -o $3/Quality -a $4 -c $7 -p $3/Quality/results/$8 -d $8; +fi + +charts_path="$(ls "$3/Robustness/charts"/* -dArt | tail -n 1) $(ls "$3/Performance/charts"/* -dArt | tail -n 2) $(ls "$3/Quality/charts"/* -dArt | tail -n 9)" + +pdfjam --nup 2x6 $charts_path --outfile $3/charts/results_$7_$8_alpha_$4_$(date '+%Y-%m-%d_%H:%M:%S').pdf diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/alpha_wrap_validation.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/validation.h similarity index 100% rename from Alpha_wrap_3/test/Alpha_wrap_3/alpha_wrap_validation.h rename to Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/validation.h diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp index d7567bab205b..1e37919756ab 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp @@ -6,7 +6,7 @@ #include #include -#include "alpha_wrap_validation.h" +#include #include diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp index 638431e30567..189cc73fa2dc 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp @@ -5,7 +5,7 @@ //#define CGAL_AW3_DEBUG_QUEUE #include -#include "alpha_wrap_validation.h" +#include #include #include diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp index e2abc6f1f12f..a7abdf6674e5 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp @@ -4,7 +4,7 @@ #include #include -#include "alpha_wrap_validation.h" +#include #include #include diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp index 470d48e40d44..e7a362fc7098 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp @@ -6,7 +6,7 @@ //#define CGAL_AW3_DEBUG_QUEUE #include -#include "alpha_wrap_validation.h" +#include #include #include From 53c89475a379a29e6516b0d93746653c4b255e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 29 Sep 2023 11:12:17 +0200 Subject: [PATCH 016/133] Rename a variable --- Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp index ffcedc7f1cbb..4e96d6c1116c 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp @@ -105,8 +105,8 @@ int main(int argc, char** argv) CGAL::Alpha_wraps_3::internal::Alpha_wrap_3 aw3(oracle); - Mesh output_mesh; - aw3(alpha, offset, output_mesh); + Mesh wrap; + aw3(alpha, offset, wrap); t.stop(); std::cout << "Took " << t.time() << std::endl; @@ -123,7 +123,7 @@ int main(int argc, char** argv) std::string output_name = ts_name + "_" + ss_name + "_" + ps_name + "_" + std::to_string(static_cast(relative_alpha)) + "_" + std::to_string(static_cast(relative_offset)) + ".off"; std::cout << "Writing to " << output_name << std::endl; - CGAL::IO::write_polygon_mesh(output_name, output_mesh, CGAL::parameters::stream_precision(17)); + CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); return EXIT_SUCCESS; } From e3854f68e3269da5d3ecb472c0f1a69f5f78999c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 29 Sep 2023 11:12:31 +0200 Subject: [PATCH 017/133] Expose useful typedefs from Alpha_wrapper_3 --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 3ee6061d0d89..3aaabefd94fc 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -124,8 +124,13 @@ class Alpha_wrap_3 using Default_Tds = CGAL::Triangulation_data_structure_3; using Default_Triangulation = CGAL::Delaunay_triangulation_3; +public: using Triangulation = typename Default::Get::type; + // Use the geom traits from the triangulation, and trust the (advanced) user that provided it + using Geom_traits = typename Triangulation::Geom_traits; + +private: using Cell_handle = typename Triangulation::Cell_handle; using Facet = typename Triangulation::Facet; using Vertex_handle = typename Triangulation::Vertex_handle; @@ -134,9 +139,6 @@ class Alpha_wrap_3 using Gate = internal::Gate; using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; - // Use the geom traits from the triangulation, and trust the (advanced) user that provided it - using Geom_traits = typename Triangulation::Geom_traits; - using FT = typename Geom_traits::FT; using Point_3 = typename Geom_traits::Point_3; using Vector_3 = typename Geom_traits::Vector_3; From cfae913d77ec5e346aed9e5d3c90e3d591dea4ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 29 Sep 2023 11:13:31 +0200 Subject: [PATCH 018/133] Complete the sort functor in AW3's main queue --- .../internal/gate_priority_queue.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index 5e14a4d08ea1..a9bdd7e0491b 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -68,6 +68,24 @@ struct Less_gate template bool operator()(const Gate& a, const Gate& b) const { + // If one is artificial and the other is not, give priority to the artificial facet + // + // The artificial facet are given highest priority because they need to be treated + // regardless of their circumradius. Treating them first allow the part that depends + // on alpha to be treated uniformly in a way: whatever the alpha, we'll do the same + // first treatmen + if(a.is_artificial_facet() != b.is_artificial_facet()) + return a.is_artificial_facet(); + + if(a.priority() == b.priority()) + { + // arbitrary, the sole purpose is to make it a total order for determinism + if(a.facet().first->time_stamp() == b.facet().first->time_stamp()) + return a.facet().second < b.facet().second; + + return a.facet().first->time_stamp() < b.facet().first->time_stamp(); + } + return a.priority() > b.priority(); } }; From 7e2386f97e9d935bd61d3120736832eca3200f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 29 Sep 2023 11:14:42 +0200 Subject: [PATCH 019/133] Use the real circumradius value to sort the facets Meaning, use the value that we compare against alpha, and not simply the radius of the smallest circumscribing ball. This strongly changes the order of the queue and thus thus results are very different, but still the same (same guarantees, same element quality, only a little bit more elements, etc.) Also a massive, ~35% speed-up, that needs to be investigated. --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 11 +-- .../Alpha_wrap_3/internal/geometry_utils.h | 74 +++++++++++++++++++ 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 3aaabefd94fc..14ad83cdbd36 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1131,17 +1131,16 @@ class Alpha_wrap_3 if(status == IRRELEVANT) return false; + const FT sqr = smallest_squared_radius_3(f, m_tr); + m_queue.resize_and_push(Gate(f, sqr, (status == ARTIFICIAL_FACET))); + +#ifdef CGAL_AW3_DEBUG_QUEUE const Cell_handle ch = f.first; const int s = f.second; const Point_3& p0 = m_tr.point(ch, Triangulation::vertex_triple_index(s, 0)); const Point_3& p1 = m_tr.point(ch, Triangulation::vertex_triple_index(s, 1)); const Point_3& p2 = m_tr.point(ch, Triangulation::vertex_triple_index(s, 2)); - // @todo should prob be the real value that we compare to alpha instead of squared_radius - const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); - m_queue.resize_and_push(Gate(f, sqr, (status == ARTIFICIAL_FACET))); - -#ifdef CGAL_AW3_DEBUG_QUEUE static int gid = 0; std::cout << "Queue insertion #" << gid++ << "\n" << " ch = " << &*ch << " (" << m_tr.is_infinite(ch) << ") " << "\n" @@ -1151,6 +1150,8 @@ class Alpha_wrap_3 std::cout << " Artificiality: " << (status == ARTIFICIAL_FACET) << std::endl; #endif + CGAL_assertion(status == ARTIFICIAL_FACET || sqr >= m_sq_alpha); + return true; } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h index 7d66cfd19f41..f39a47012862 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h @@ -154,6 +154,80 @@ less_squared_radius_of_min_empty_sphere(typename Tr::Geom_traits::FT sq_alpha, } } +template +bool +smallest_squared_radius_3(const typename Tr::Facet& fh, + const Tr& tr) +{ + using Cell_handle = typename Tr::Cell_handle; + using Point = typename Tr::Point; + using FT = typename Tr::Geom_traits::FT; + + using CK = typename Tr::Geom_traits; + using Exact_kernel = typename Exact_kernel_selector::Exact_kernel; + using Approximate_kernel = Simple_cartesian; + using C2A = Cartesian_converter; + using C2E = typename Exact_kernel_selector::C2E; + + using Orientation_of_circumcenter = Filtered_predicate, + Orientation_of_circumcenter, + C2E, C2A>; + + Orientation_of_circumcenter orientation_of_circumcenter; + + auto squared_radius = tr.geom_traits().compute_squared_radius_3_object(); + + const Cell_handle c = fh.first; + const int ic = fh.second; + const Cell_handle n = c->neighbor(ic); + + const Point& p1 = tr.point(c, Tr::vertex_triple_index(ic,0)); + const Point& p2 = tr.point(c, Tr::vertex_triple_index(ic,1)); + const Point& p3 = tr.point(c, Tr::vertex_triple_index(ic,2)); + + // This is not actually possible in the context of alpha wrapping, but keeping it for genericity + // and because it does not cost anything. + if(tr.is_infinite(n)) + { + Orientation ori = orientation_of_circumcenter(p1, p2, p3, + tr.point(c, 0), tr.point(c, 1), + tr.point(c, 2), tr.point(c, 3)); + if(ori == POSITIVE) + return squared_radius(p1, p2, p3); + else + return squared_radius(tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)); + } + + if(tr.is_infinite(c)) + { + Orientation ori = orientation_of_circumcenter(p1, p2, p3, + tr.point(n, 0), tr.point(n, 1), + tr.point(n, 2), tr.point(n, 3)); + if(ori == NEGATIVE) + return squared_radius(p1, p2, p3); + else + return squared_radius(tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3)); + } + + // both c and n are finite + if(orientation_of_circumcenter(p1, p2, p3, + tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)) != + orientation_of_circumcenter(p1, p2, p3, + tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3))) + { + // Dual crosses the face + return squared_radius(p1, p2, p3); + } + else + { + // Dual does not crosses the face + FT cr = squared_radius(tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)); + FT cnr = squared_radius(tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3)); + return (CGAL::min)(cr, cnr); + } +} + + } // namespace internal } // namespace Alpha_wraps_3 } // namespace CGAL From be42e0fbe887abff709b4c18d5070b5261ad71ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 29 Sep 2023 11:19:39 +0200 Subject: [PATCH 020/133] Minor debug code cleaning --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 14ad83cdbd36..a7130c2a3774 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1228,8 +1228,10 @@ class Alpha_wrap_3 CGAL_precondition(!m_tr.is_infinite(f)); const Cell_handle ch = f.first; - const int id = f.second; - const Cell_handle neighbor = ch->neighbor(id); + const int s = f.second; + CGAL_precondition(ch->is_outside()); + + const Cell_handle neighbor = ch->neighbor(s); #ifdef CGAL_AW3_DEBUG_QUEUE static int fid = 0; @@ -1237,10 +1239,11 @@ class Alpha_wrap_3 std::cout << m_queue.size() << " facets in the queue" << std::endl; std::cout << "Face " << fid++ << "\n" << "c = " << &*ch << " (" << m_tr.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_tr.is_infinite(neighbor) << ")" << "\n" - << m_tr.point(ch, Triangulation::vertex_triple_index(id, 0)) << "\n" - << m_tr.point(ch, Triangulation::vertex_triple_index(id, 1)) << "\n" - << m_tr.point(ch, Triangulation::vertex_triple_index(id, 2)) << std::endl; - std::cout << "Priority: " << gate.priority() << std::endl; + << m_tr.point(ch, Triangulation::vertex_triple_index(s, 0)) << "\n" + << m_tr.point(ch, Triangulation::vertex_triple_index(s, 1)) << "\n" + << m_tr.point(ch, Triangulation::vertex_triple_index(s, 2)) << std::endl; + std::cout << "Artificiality: " << gate.is_artificial_facet() << std::endl; + std::cout << "Priority: " << gate.priority() << " (sq alpha: " << m_sq_alpha << ")" << std::endl; #endif visitor.before_facet_treatment(*this, gate); @@ -1255,9 +1258,9 @@ class Alpha_wrap_3 std::string face_name = "results/steps/face_" + std::to_string(static_cast(i++)) + ".xyz"; std::ofstream face_out(face_name); face_out.precision(17); - face_out << "3\n" << m_tr.point(ch, Triangulation::vertex_triple_index(id, 0)) << "\n" - << m_tr.point(ch, Triangulation::vertex_triple_index(id, 1)) << "\n" - << m_tr.point(ch, Triangulation::vertex_triple_index(id, 2)) << std::endl; + face_out << "3\n" << m_tr.point(ch, Triangulation::vertex_triple_index(s, 0)) << "\n" + << m_tr.point(ch, Triangulation::vertex_triple_index(s, 1)) << "\n" + << m_tr.point(ch, Triangulation::vertex_triple_index(s, 2)) << std::endl; face_out.close(); #endif From 8ccce4c536ea7c3e04f1a15d34e6ca362ae84bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 29 Sep 2023 11:19:52 +0200 Subject: [PATCH 021/133] Avoid one useless facet check This doesn't bring any speed-up because it was a very fast exit in push_facet(): the neighbor was necessarily outside (since we come from it), and we are done. --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index a7130c2a3774..2174363240b6 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1355,15 +1355,16 @@ class Alpha_wrap_3 } } } - else + else // no need for a Steiner point, carve through and continue { // tag neighbor as OUTSIDE neighbor->is_outside() = true; // for each finite facet of neighbor, push it to the queue - for(int i=0; i<4; ++i) + const int mi = m_tr.mirror_index(ch, s); + for(int i=1; i<4; ++i) { - const Facet neighbor_f = std::make_pair(neighbor, i); + const Facet neighbor_f = std::make_pair(neighbor, (mi+i)&3); push_facet(neighbor_f); } } From 05e11d381f952251538a134bd114871b1eb90173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 9 Aug 2021 17:32:43 +0200 Subject: [PATCH 022/133] add experimental function to refine a mesh along an isocurve --- .../internal/refine_mesh_at_isolevel.h | 129 ++++++++++++++++++ .../Polygon_mesh_processing/CMakeLists.txt | 5 + .../test_geodesic_isolevel_refinement.cmd | 1 + .../test_geodesic_isolevel_refinement.cpp | 63 +++++++++ 4 files changed, 198 insertions(+) create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h new file mode 100644 index 000000000000..f4b0f7cc6497 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h @@ -0,0 +1,129 @@ +// Copyright (c) 2021 GeometryFactory (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) : Sebastien Loriot + +#ifndef CGAL_POLYGON_MESH_PROCESSING_CLIP_H +#define CGAL_POLYGON_MESH_PROCESSING_CLIP_H + +#include + +#include + +namespace CGAL { +namespace Polygon_mesh_processing { +namespace experimental { + + +template +void refine_mesh_at_isolevel(PolygonMesh& pm, + ValueMap value_map, + typename boost::property_traits::value_type isovalue, + const NamedParameters& np) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + using parameters::choose_parameter; + using parameters::get_parameter; + using parameters::is_default_parameter; + + typedef Static_boolean_property_map Default_ECM; + typedef typename internal_np::Lookup_named_param_def::type ECM; + typedef typename GetVertexPointMap < PolygonMesh, NamedParameters>::type VPM; + + VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_property_map(vertex_point, pm)); + + ECM ecm = choose_parameter(get_parameter(np, internal_np::edge_is_constrained), Default_ECM()); + + std::unordered_map > faces_to_split; + std::vector to_split; + for (edge_descriptor e : edges(pm)) + { + vertex_descriptor src = source(e, pm), tgt = target(e, pm); + if (get(value_map, src)==isovalue) + { + for (halfedge_descriptor h : halfedges_around_source(halfedge(e, pm), pm)) + { + face_descriptor f = face(h, pm); + if (f!=boost::graph_traits::null_face()) + faces_to_split[f].push_back(opposite(h, pm)); + } + continue; + } + if (get(value_map, tgt)==isovalue) + { + for (halfedge_descriptor h : halfedges_around_target(halfedge(e, pm), pm)) + { + face_descriptor f = face(h, pm); + if (f!=boost::graph_traits::null_face()) + faces_to_split[f].push_back(h); + } + continue; + } + if ( (get(value_map, tgt) < isovalue) != (get(value_map, src) < isovalue) ) + { + to_split.push_back(e); + } + } + + for (edge_descriptor e : to_split) + { + vertex_descriptor src = source(e, pm), tgt = target(e, pm); + double ds = get(value_map, src); + double dt = get(value_map, tgt); + double alpha = (isovalue - dt) / (ds - dt); + halfedge_descriptor hnew = CGAL::Euler::split_edge(halfedge(e, pm), pm); + put(vpm, target(hnew, pm), barycenter(get(vpm,src), alpha, get(vpm, tgt), 1-alpha)); + put(value_map, target(hnew, pm) , isovalue); + face_descriptor f = face(hnew, pm); + if (f!=boost::graph_traits::null_face()) + faces_to_split[f].push_back(hnew); + hnew=pm.prev(opposite(hnew, pm)); + f = face(hnew, pm); + if (f!=boost::graph_traits::null_face()) + faces_to_split[f].push_back(hnew); + } + + for (const auto& p : faces_to_split) + { + if(p.second.size()!=2) continue; + + std::pair res = edge(target(p.second[0],pm), + target(p.second[1],pm), pm); + if (res.second) + { + // no split as the edge already exists (the two vertices are on the isolevel) + put(ecm, res.first, true); + continue; + } + + halfedge_descriptor hnew = CGAL::Euler::split_face(p.second[0], p.second[1], pm); + put(ecm, edge(hnew, pm), true); + } +} + +template +void refine_mesh_at_isolevel(PolygonMesh& pm, + ValueMap value_map, + typename boost::property_traits::value_type iso_level) +{ + refine_mesh_at_isolevel(pm, value_map, iso_level, parameters::all_default()); +} + +} } } // end of CGAL::Polygon_mesh_processing::experimental + + +#endif diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index eb9b98cbe593..6f5d1e7c7ce9 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -125,6 +125,11 @@ else() message(STATUS "NOTICE: Tests are not using Ceres.") endif() +if (TARGET CGAL::Eigen3_support) + create_single_source_cgal_program("test_geodesic_isolevel_refinement.cpp") + target_link_libraries( test_geodesic_isolevel_refinement PUBLIC CGAL::Eigen3_support) +endif() + if(BUILD_TESTING) set_tests_properties( "execution of triangulate_hole_Polyhedron_3_no_delaunay_test" diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd new file mode 100644 index 000000000000..36105ee3a020 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd @@ -0,0 +1 @@ +${CGAL_DATA_DIR}/meshes/elephant.off 0.001 0.01 0.05 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 10 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp new file mode 100644 index 000000000000..a2098c63e3b9 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp @@ -0,0 +1,63 @@ +#include +#include + +#include + +#include +#include + +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Surface_mesh Triangle_mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; + +typedef Triangle_mesh::Property_map Vertex_distance_map; +typedef CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3 Heat_method; + +int main(int argc, char* argv[]) +{ + const char* filename = argv[1]; + + Triangle_mesh tm; + if(!CGAL::IO::read_polygon_mesh(filename, tm) || + CGAL::is_empty(tm) || !CGAL::is_triangle_mesh(tm)) + { + std::cerr << "Invalid input file." << std::endl; + return EXIT_FAILURE; + } + + //property map for the distance values to the source set + Vertex_distance_map vertex_distance = tm.add_property_map("v:distance", 0).first; + + Heat_method hm(tm); + + //add the first vertex as the source set + vertex_descriptor s = *(vertices(tm).first); + hm.add_source(s); + hm.estimate_geodesic_distances(vertex_distance); + + //property map for the constrained status of edges + auto ecm = tm.add_property_map("e:is_constrained", 0).first; + + + for (int i=2; i splitted; + + CGAL::Polygon_mesh_processing::split_connected_components(tm, splitted, CGAL::parameters::edge_is_constrained_map(ecm)); + +#ifdef CGAL_TEST_SUITE + assert(splitted.size() == 22); +#else + for(std::size_t i=0; i Date: Sat, 30 Sep 2023 08:41:07 +0200 Subject: [PATCH 023/133] add doc --- .../internal/refine_mesh_at_isolevel.h | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h index f4b0f7cc6497..8bb6502865f7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h @@ -10,10 +10,10 @@ // // Author(s) : Sebastien Loriot -#ifndef CGAL_POLYGON_MESH_PROCESSING_CLIP_H -#define CGAL_POLYGON_MESH_PROCESSING_CLIP_H +#ifndef CGAL_POLYGON_MESH_PROCESSING_REFINE_MESH_AT_ISOLEVEL_H +#define CGAL_POLYGON_MESH_PROCESSING_REFINE_MESH_AT_ISOLEVEL_H -#include +#include #include @@ -21,12 +21,43 @@ namespace CGAL { namespace Polygon_mesh_processing { namespace experimental { - -template +/*! \ingroup PkgPolygonMeshProcessingRef + * Function object that computes the intersection of a plane with + * a triangulated surface mesh. + * + * @tparam PolygonMesh a model of the concepts `EdgeListGraph` and `FaceListGraph` + * @tparam ValueMap a model of the concept `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and with its value type being model of `LessThanComparable`. + * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" for `pm` + * + * @param pm the polygon mesh to be refined + * @param value_map the property map containing value at each vertex for a given function defined over the mesh + * @param isovalue the value used to defined the cut locus of edges having their incident vertices associated with + * values respectively larger and smaller than `isovalue` in `value_map` + * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamNBegin{edge_is_constrained_map} + * \cgalParamDescription{an ouput property map associating `true` to all new edges added by the cut, and false to input edges. + * \cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits::%edge_descriptor` + * as key type and `bool` as value type} + * \cgalParamDefault{No marks on edges will be put} + * \cgalParamNBegin{vertex_point_map} + * \cgalParamDescription{a property map associating points to the vertices of `pm`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and `%Point_3` as value type} + * \cgalParamDefault{`boost::get(CGAL::vertex_point, pm)`} + * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` + * must be available in `PolygonMesh`.} + * \cgalParamNEnd + * \cgalNamedParamsEnd + * + */ +template void refine_mesh_at_isolevel(PolygonMesh& pm, ValueMap value_map, typename boost::property_traits::value_type isovalue, - const NamedParameters& np) + const NamedParameters& np = parameters::default_values()) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; @@ -115,14 +146,6 @@ void refine_mesh_at_isolevel(PolygonMesh& pm, } } -template -void refine_mesh_at_isolevel(PolygonMesh& pm, - ValueMap value_map, - typename boost::property_traits::value_type iso_level) -{ - refine_mesh_at_isolevel(pm, value_map, iso_level, parameters::all_default()); -} - } } } // end of CGAL::Polygon_mesh_processing::experimental From c17841356a3228ff9509a6edc58bc22fee672071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 2 Oct 2023 13:10:38 +0200 Subject: [PATCH 024/133] Minor error message tweak --- Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp index 8742a2a20011..aeb47b80152e 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp @@ -23,7 +23,7 @@ int main(int argc, char** argv) Point_container points; if(!CGAL::IO::read_points(filename, std::back_inserter(points)) || points.empty()) { - std::cerr << "Invalid input." << std::endl; + std::cerr << "Invalid input:" << filename << std::endl; return EXIT_FAILURE; } diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp index 600d533ee411..59010d1212ea 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp @@ -35,7 +35,7 @@ int main(int argc, char** argv) Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh) || is_empty(mesh) || !is_triangle_mesh(mesh)) { - std::cerr << "Invalid input." << std::endl; + std::cerr << "Invalid input:" << filename << std::endl; return EXIT_FAILURE; } diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp index 00e2e4fd9fc5..369cf375a6ff 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp @@ -25,7 +25,7 @@ int main(int argc, char** argv) Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh) || is_empty(mesh) || !is_triangle_mesh(mesh)) { - std::cerr << "Invalid input." << std::endl; + std::cerr << "Invalid input:" << filename << std::endl; return EXIT_FAILURE; } diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp index 626e3bdc3ba4..6e1321c302dd 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp @@ -30,7 +30,7 @@ int main(int argc, char** argv) std::vector > faces; if(!CGAL::IO::read_polygon_soup(filename, points, faces) || faces.empty()) { - std::cerr << "Invalid input." << std::endl; + std::cerr << "Invalid input:" << filename << std::endl; return EXIT_FAILURE; } diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp index 113215b631a1..682cffac3390 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp @@ -70,7 +70,7 @@ int main(int argc, char** argv) Faces faces; if(!CGAL::IO::read_polygon_soup(filename, points, faces) || faces.empty()) { - std::cerr << "Invalid input." << std::endl; + std::cerr << "Invalid input:" << filename << std::endl; return EXIT_FAILURE; } diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp index 1c1d6c7b3d72..9de47aefbcd2 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp @@ -25,7 +25,7 @@ int main(int argc, char** argv) if(!PMP::IO::read_polygon_mesh(filename, input) || is_empty(input) || !is_triangle_mesh(input)) { - std::cerr << "Invalid input." << std::endl; + std::cerr << "Invalid input:" << filename << std::endl; return EXIT_FAILURE; } From 9fa445f21754a1ac7923f2b5d190647ebd818dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 2 Oct 2023 13:13:40 +0200 Subject: [PATCH 025/133] Change nomenclature to clarify the different types of gate permissiveness --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 39 +++++++++++-------- .../internal/gate_priority_queue.h | 16 ++++---- .../Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 6 +-- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 2174363240b6..7c9509b9185a 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -523,7 +523,7 @@ class Alpha_wrap_3 continue; } - // Mark the seeds and icosahedron vertices as "artificial vertices" such that the facets + // Mark the seeds and icosahedron vertices as "scaffolding vertices" such that the facets // incident to these vertices are always traversable regardless of their circumcenter. // This is done because otherwise some cavities can appear on the mesh: non-traversable facets // with two vertices on the offset, and the third being a deeper inside seed / ico_seed. @@ -592,11 +592,12 @@ class Alpha_wrap_3 std::vector inc_cells; inc_cells.reserve(64); m_tr.incident_cells(seed_v, std::back_inserter(inc_cells)); + for(Cell_handle ch : inc_cells) ch->is_outside() = cavity_cell_outside_tag(ch); } - // Might as well go through the full triangulation since only seeds should have been inserted + // Should be cheap enough to go through the full triangulation as only seeds have been inserted for(Cell_handle ch : m_tr.all_cell_handles()) { if(!ch->is_outside()) @@ -1027,21 +1028,24 @@ class Alpha_wrap_3 } private: + // A permissive gate is a gate that we can traverse without checking its circumradius enum Facet_queue_status { IRRELEVANT = 0, - ARTIFICIAL_FACET, + HAS_INFINITE_NEIGHBOR, // the cell incident to the mirrored facet is infinite (permissive) + SCAFFOLDING, // incident to a SEED or BBOX vertex (permissive) TRAVERSABLE }; inline const char* get_status_message(const Facet_queue_status status) { - constexpr std::size_t status_count = 3; + constexpr std::size_t status_count = 4; // Messages corresponding to Error_code list above. Must be kept in sync! static const char* message[status_count] = { "Irrelevant facet", - "Artificial facet", + "Facet incident to infinite neighbor", + "Facet with a bbox/seed vertex", "Traversable facet" }; @@ -1079,7 +1083,7 @@ class Alpha_wrap_3 const Cell_handle nh = ch->neighbor(id); if(m_tr.is_infinite(nh)) - return TRAVERSABLE; + return HAS_INFINITE_NEIGHBOR; if(nh->is_outside()) { @@ -1089,7 +1093,7 @@ class Alpha_wrap_3 return IRRELEVANT; } - // push if facet is connected to artificial vertices + // push if facet is connected to scaffolding vertices for(int i=0; i<3; ++i) { const Vertex_handle vh = ch->vertex(Triangulation::vertex_triple_index(id, i)); @@ -1097,9 +1101,9 @@ class Alpha_wrap_3 vh->type() == AW3i::Vertex_type:: SEED_VERTEX) { #ifdef CGAL_AW3_DEBUG_FACET_STATUS - std::cout << "artificial facet due to artificial vertex #" << i << std::endl; + std::cout << "Scaffolding facet due to vertex #" << i << std::endl; #endif - return ARTIFICIAL_FACET; + return SCAFFOLDING; } } @@ -1132,7 +1136,8 @@ class Alpha_wrap_3 return false; const FT sqr = smallest_squared_radius_3(f, m_tr); - m_queue.resize_and_push(Gate(f, sqr, (status == ARTIFICIAL_FACET))); + const bool is_permissive = (status == HAS_INFINITE_NEIGHBOR || status == SCAFFOLDING); + m_queue.resize_and_push(Gate(f, sqr, is_permissive)); #ifdef CGAL_AW3_DEBUG_QUEUE const Cell_handle ch = f.first; @@ -1147,10 +1152,10 @@ class Alpha_wrap_3 << "\t" << p0 << "\n\t" << p1 << "\n\t" << p2 << std::endl; std::cout << " Status: " << get_status_message(status) << std::endl; std::cout << " SQR: " << sqr << std::endl; - std::cout << " Artificiality: " << (status == ARTIFICIAL_FACET) << std::endl; + std::cout << " Permissiveness: " << is_permissive << std::endl; #endif - CGAL_assertion(status == ARTIFICIAL_FACET || sqr >= m_sq_alpha); + CGAL_assertion(is_permissive || sqr >= m_sq_alpha); return true; } @@ -1242,8 +1247,8 @@ class Alpha_wrap_3 << m_tr.point(ch, Triangulation::vertex_triple_index(s, 0)) << "\n" << m_tr.point(ch, Triangulation::vertex_triple_index(s, 1)) << "\n" << m_tr.point(ch, Triangulation::vertex_triple_index(s, 2)) << std::endl; - std::cout << "Artificiality: " << gate.is_artificial_facet() << std::endl; std::cout << "Priority: " << gate.priority() << " (sq alpha: " << m_sq_alpha << ")" << std::endl; + std::cout << "Permissiveness: " << gate.is_permissive_facet() << std::endl; #endif visitor.before_facet_treatment(*this, gate); @@ -1547,7 +1552,7 @@ class Alpha_wrap_3 } // Some lambdas for the comparer - auto has_artificial_vertex = [](Cell_handle c) -> bool + auto has_scaffolding_vertex = [](Cell_handle c) -> bool { for(int i=0; i<4; ++i) { @@ -1625,9 +1630,9 @@ class Alpha_wrap_3 // @todo give topmost priority to cells with > 1 non-manifold vertex? auto comparer = [&](Cell_handle l, Cell_handle r) -> bool { - if(has_artificial_vertex(l)) + if(has_scaffolding_vertex(l)) return false; - if(has_artificial_vertex(r)) + if(has_scaffolding_vertex(r)) return true; const int l_bf_count = count_boundary_facets(l, v); @@ -1706,7 +1711,7 @@ class Alpha_wrap_3 std::cout << "At Facet with VID " << get(Gate_ID_PM(), current_gate) << "\n"; std::cout << "\t" << p0 << "\n\t" << p1 << "\n\t" << p2 << "\n"; - std::cout << " Artificiality: " << current_gate.is_artificial_facet() << "\n"; + std::cout << " Permissiveness: " << current_gate.is_permissive_facet() << "\n"; std::cout << " SQR: " << sqr << "\n"; std::cout << " Priority " << current_gate.priority() << std::endl; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index a9bdd7e0491b..b091b2cabe24 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -37,17 +37,17 @@ class Gate private: Facet m_facet; FT m_priority; // circumsphere sq_radius - bool m_is_artificial_facet; + bool m_is_permissive_facet; public: // Constructors Gate(const Facet& facet, const FT& priority, - const bool is_artificial_facet) + const bool is_permissive_facet) : m_facet(facet), m_priority(priority), - m_is_artificial_facet(is_artificial_facet) + m_is_permissive_facet(is_permissive_facet) { CGAL_assertion(priority >= 0); } @@ -60,7 +60,7 @@ class Gate public: const Facet& facet() const { return m_facet; } const FT& priority() const { return m_priority; } - bool is_artificial_facet() const { return m_is_artificial_facet; } + bool is_permissive_facet() const { return m_is_permissive_facet; } }; struct Less_gate @@ -68,14 +68,14 @@ struct Less_gate template bool operator()(const Gate& a, const Gate& b) const { - // If one is artificial and the other is not, give priority to the artificial facet + // If one is permissive and the other is not, give priority to the permissive facet // - // The artificial facet are given highest priority because they need to be treated + // The permissive facet are given highest priority because they need to be treated // regardless of their circumradius. Treating them first allow the part that depends // on alpha to be treated uniformly in a way: whatever the alpha, we'll do the same // first treatmen - if(a.is_artificial_facet() != b.is_artificial_facet()) - return a.is_artificial_facet(); + if(a.is_permissive_facet() != b.is_permissive_facet()) + return a.is_permissive_facet(); if(a.priority() == b.priority()) { diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index a1b29fd5689d..e66d6c83dd3f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -113,10 +113,10 @@ struct Iterative_AW3_visualization_visitor if(!points || !faces || !fcolors || !vcolors) return; - // If the next top of the queue has vertices on the bbox, don't draw (as to avoid producing + // If the next top of the queue has vertices on the bbox, don't draw (try to avoid producing // spikes in the visualization) // const auto& gate = wrapper.queue().top(); -// if(wrapper.triangulation().number_of_vertices() > 500 && gate.is_artificial_facet()) +// if(wrapper.triangulation().number_of_vertices() > 500 && gate.is_permissive_facet()) // return; // Skip some... @@ -216,7 +216,7 @@ struct AW3_interrupter_visitor { } // Only overload this one because it gives a better state of the wrap (for other visitor calls, - // we often get tetrahedral spikes because there are artificial gates in the queue) + // we often get tetrahedral spikes because there are scaffolding gates in the queue) template void before_Steiner_point_insertion(const Wrapper& wrapper, const Point& p) { From 7d12160e185cfe8b7cde24138d6e4372197ef626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 3 Oct 2023 11:52:04 +0200 Subject: [PATCH 026/133] update doc --- .../PackageDescription.txt | 1 + .../Polygon_mesh_processing/CMakeLists.txt | 2 + .../geodesic_isolevel_refinement.cpp} | 33 +++++++++----- .../{internal => }/refine_mesh_at_isolevel.h | 44 ++++++++++++------- .../Polygon_mesh_processing/CMakeLists.txt | 5 --- .../test_geodesic_isolevel_refinement.cmd | 1 - 6 files changed, 51 insertions(+), 35 deletions(-) rename Polygon_mesh_processing/{test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp => examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp} (65%) rename Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/{internal => }/refine_mesh_at_isolevel.h (79%) delete mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index b17c41399d0b..1d17b286dc5c 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -258,6 +258,7 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage. - `CGAL::Polygon_mesh_processing::triangle()` - `CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces()` - `CGAL::Polygon_mesh_processing::detect_corners_of_regions()` +- `CGAL::Polygon_mesh_processing::refine_mesh_at_isolevel()` \cgalCRPSection{I/O Functions} - \link PMP_IO_grp `CGAL::Polygon_mesh_processing::IO::read_polygon_mesh()`\endlink diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index c755ecf63e8e..0ad5f79a261b 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -73,6 +73,8 @@ if(TARGET CGAL::Eigen3_support) target_link_libraries(delaunay_remeshing_example PUBLIC CGAL::Eigen3_support) create_single_source_cgal_program("remesh_almost_planar_patches.cpp") target_link_libraries(remesh_almost_planar_patches PUBLIC CGAL::Eigen3_support) + create_single_source_cgal_program("geodesic_isolevel_refinement.cpp") + target_link_libraries(geodesic_isolevel_refinement PUBLIC CGAL::Eigen3_support) else() message(STATUS "NOTICE: Examples that use Eigen will not be compiled.") endif() diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp similarity index 65% rename from Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp rename to Polygon_mesh_processing/examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp index a2098c63e3b9..76f97bf3dc66 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -21,7 +21,7 @@ typedef CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3 He int main(int argc, char* argv[]) { - const char* filename = argv[1]; + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/elephant.off"); Triangle_mesh tm; if(!CGAL::IO::read_polygon_mesh(filename, tm) || @@ -31,33 +31,42 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } + // default isovalues for cutting the mesh + std::vector isovalues = {0.001, 0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 10}; + + if (argc>2) + { + isovalues.clear(); + for (int i=2; i("v:distance", 0).first; Heat_method hm(tm); - //add the first vertex as the source set + //use heat method to compute approximated geodesic distances to the source vertex `s` vertex_descriptor s = *(vertices(tm).first); hm.add_source(s); hm.estimate_geodesic_distances(vertex_distance); - //property map for the constrained status of edges + // property map to flag new cut edge added in the mesh auto ecm = tm.add_property_map("e:is_constrained", 0).first; + // refine the mesh along isovalues + for (double isovalue : isovalues) + CGAL::Polygon_mesh_processing::refine_mesh_at_isolevel(tm, vertex_distance, isovalue, CGAL::parameters::edge_is_constrained_map(ecm)); - for (int i=2; i splitted; - CGAL::Polygon_mesh_processing::split_connected_components(tm, splitted, CGAL::parameters::edge_is_constrained_map(ecm)); -#ifdef CGAL_TEST_SUITE - assert(splitted.size() == 22); -#else + assert(argc!=1 || splitted.size() == 22); + + // export each submesh in a file for(std::size_t i=0; i::%vertex_descriptor` - * as key type and with its value type being model of `LessThanComparable`. + * @tparam ValueMap a model of the concept `ReadWritePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and with its value type being the type of the coordinates of points associated with vertices + * in the vertex map provided to the `vertex_point_map()` named parameter. * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" for `pm` * - * @param pm the polygon mesh to be refined - * @param value_map the property map containing value at each vertex for a given function defined over the mesh - * @param isovalue the value used to defined the cut locus of edges having their incident vertices associated with - * values respectively larger and smaller than `isovalue` in `value_map` + * @param pm the polygon mesh to be refined. + * @param value_map the property map containing value at each vertex for a given function defined over the mesh. + * @param isovalue the value used to defined * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin * \cgalParamNBegin{edge_is_constrained_map} - * \cgalParamDescription{an ouput property map associating `true` to all new edges added by the cut, and false to input edges. + * \cgalParamDescription{an ouput property map associating `true` to all new edges added by the cut, and false to input edges.} * \cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits::%edge_descriptor` * as key type and `bool` as value type} * \cgalParamDefault{No marks on edges will be put} + * \cgalParamNEnd + * * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `pm`} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` @@ -53,7 +62,7 @@ namespace experimental { * \cgalNamedParamsEnd * */ -template +template void refine_mesh_at_isolevel(PolygonMesh& pm, ValueMap value_map, typename boost::property_traits::value_type isovalue, @@ -63,6 +72,7 @@ void refine_mesh_at_isolevel(PolygonMesh& pm, typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::property_map::value_type FT; using parameters::choose_parameter; using parameters::get_parameter; @@ -113,9 +123,9 @@ void refine_mesh_at_isolevel(PolygonMesh& pm, for (edge_descriptor e : to_split) { vertex_descriptor src = source(e, pm), tgt = target(e, pm); - double ds = get(value_map, src); - double dt = get(value_map, tgt); - double alpha = (isovalue - dt) / (ds - dt); + FT ds = get(value_map, src); + FT dt = get(value_map, tgt); + FT alpha = (isovalue - dt) / (ds - dt); halfedge_descriptor hnew = CGAL::Euler::split_edge(halfedge(e, pm), pm); put(vpm, target(hnew, pm), barycenter(get(vpm,src), alpha, get(vpm, tgt), 1-alpha)); put(value_map, target(hnew, pm) , isovalue); @@ -146,7 +156,7 @@ void refine_mesh_at_isolevel(PolygonMesh& pm, } } -} } } // end of CGAL::Polygon_mesh_processing::experimental +} } // end of CGAL::Polygon_mesh_processing #endif diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 6f5d1e7c7ce9..eb9b98cbe593 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -125,11 +125,6 @@ else() message(STATUS "NOTICE: Tests are not using Ceres.") endif() -if (TARGET CGAL::Eigen3_support) - create_single_source_cgal_program("test_geodesic_isolevel_refinement.cpp") - target_link_libraries( test_geodesic_isolevel_refinement PUBLIC CGAL::Eigen3_support) -endif() - if(BUILD_TESTING) set_tests_properties( "execution of triangulate_hole_Polyhedron_3_no_delaunay_test" diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd deleted file mode 100644 index 36105ee3a020..000000000000 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_geodesic_isolevel_refinement.cmd +++ /dev/null @@ -1 +0,0 @@ -${CGAL_DATA_DIR}/meshes/elephant.off 0.001 0.01 0.05 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 10 From 42b5aab4b170761f473d8464eea4bba75ee8d7cd Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 3 Oct 2023 11:18:58 +0200 Subject: [PATCH 027/133] Update Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/refine_mesh_at_isolevel.h --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index 7e916fc76980..8a649b15ead4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -45,7 +45,7 @@ namespace Polygon_mesh_processing { * * \cgalNamedParamsBegin * \cgalParamNBegin{edge_is_constrained_map} - * \cgalParamDescription{an ouput property map associating `true` to all new edges added by the cut, and false to input edges.} + * \cgalParamDescription{an output property map associating `true` to all new edges added by the cut, and `false` to input edges.} * \cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits::%edge_descriptor` * as key type and `bool` as value type} * \cgalParamDefault{No marks on edges will be put} From ad5ae27c42ccf59683cd84a6ac52c6d6c6043d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 4 Oct 2023 22:49:06 +0200 Subject: [PATCH 028/133] Factorize code generating filenames out of examples --- .../Alpha_wrap_3/mixed_inputs_wrap.cpp | 5 +++-- .../examples/Alpha_wrap_3/output_helper.h | 19 +++++++++++++++++++ .../examples/Alpha_wrap_3/point_set_wrap.cpp | 8 +++----- .../Alpha_wrap_3/successive_wraps.cpp | 9 +++------ .../Alpha_wrap_3/triangle_mesh_wrap.cpp | 9 +++------ .../Alpha_wrap_3/triangle_soup_wrap.cpp | 9 +++------ .../examples/Alpha_wrap_3/volumetric_wrap.cpp | 9 +++------ .../Alpha_wrap_3/wrap_from_cavity.cpp | 8 +++----- 8 files changed, 40 insertions(+), 36 deletions(-) create mode 100644 Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp index 4e96d6c1116c..fdba4de5f514 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp @@ -120,8 +120,9 @@ int main(int argc, char** argv) std::string ps_name = std::string(ps_filename); ps_name = ps_name.substr(ps_name.find_last_of("/") + 1, ps_name.length() - 1); ps_name = ps_name.substr(0, ps_name.find_last_of(".")); - std::string output_name = ts_name + "_" + ss_name + "_" + ps_name + "_" + std::to_string(static_cast(relative_alpha)) - + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + std::string output_name = ts_name + "_" + ss_name + "_" + ps_name + "_" + + std::to_string(static_cast(relative_alpha)) + "_" + + std::to_string(static_cast(relative_offset)) + ".off"; std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h b/Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h new file mode 100644 index 000000000000..3ce1155f4ef5 --- /dev/null +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h @@ -0,0 +1,19 @@ +#ifndef CGAL_ALPHA_WRAP_3_EXAMPLES_OUTPUT_HELPER_H +#define CGAL_ALPHA_WRAP_3_EXAMPLES_OUTPUT_HELPER_H + +#include + +std::string generate_output_name(std::string input_name, + const double alpha, + const double offset) +{ + input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); + input_name = input_name.substr(0, input_name.find_last_of(".")); + std::string output_name = input_name + + "_" + std::to_string(static_cast(alpha)) + + "_" + std::to_string(static_cast(offset)) + ".off"; + + return output_name; +} + +#endif // CGAL_ALPHA_WRAP_3_EXAMPLES_OUTPUT_HELPER_H \ No newline at end of file diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp index aeb47b80152e..a602cf5c58bf 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp @@ -1,3 +1,5 @@ +#include "output_helper.h" + #include #include @@ -53,11 +55,7 @@ int main(int argc, char** argv) std::cout << "Took " << t.time() << " s." << std::endl; // Save the result - std::string input_name = std::string(filename); - input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); - input_name = input_name.substr(0, input_name.find_last_of(".")); - std::string output_name = input_name + "_" + std::to_string(static_cast(relative_alpha)) - + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + const std::string output_name = generate_output_name(filename, relative_alpha, relative_offset); std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp index 59010d1212ea..f9b35f88b1f7 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp @@ -1,5 +1,7 @@ #define CGAL_AW3_TIMER +#include "output_helper.h" + #include #include @@ -69,12 +71,7 @@ int main(int argc, char** argv) std::cout << " Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl; std::cout << " Elapsed time: " << t.time() << " s." << std::endl; - std::string input_name = std::string(filename); - input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); - input_name = input_name.substr(0, input_name.find_last_of(".")); - std::string output_name = input_name - + "_" + std::to_string(static_cast(relative_alphas[i])) - + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + const std::string output_name = generate_output_name(filename, relative_alphas[i], relative_offset); std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp index 369cf375a6ff..d49534904461 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp @@ -1,3 +1,5 @@ +#include "output_helper.h" + #include #include @@ -56,12 +58,7 @@ int main(int argc, char** argv) std::cout << "Took " << t.time() << " s." << std::endl; // Save the result - std::string input_name = std::string(filename); - input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); - input_name = input_name.substr(0, input_name.find_last_of(".")); - std::string output_name = input_name - + "_" + std::to_string(static_cast(relative_alpha)) - + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + const std::string output_name = generate_output_name(filename, relative_alpha, relative_offset); std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp index 6e1321c302dd..51e04974c28a 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_soup_wrap.cpp @@ -1,3 +1,5 @@ +#include "output_helper.h" + #include #include @@ -63,12 +65,7 @@ int main(int argc, char** argv) std::cout << "Took " << t.time() << " s." << std::endl; // Save the result - std::string input_name = std::string(filename); - input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); - input_name = input_name.substr(0, input_name.find_last_of(".")); - std::string output_name = input_name - + "_" + std::to_string(static_cast(relative_alpha)) - + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + const std::string output_name = generate_output_name(filename, relative_alpha, relative_offset); std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp index 682cffac3390..3ac28de33022 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp @@ -1,3 +1,5 @@ +#include "output_helper.h" + #include #include @@ -113,12 +115,7 @@ int main(int argc, char** argv) auto dt = aw3.triangulation(); // Save the result - std::string input_name = std::string(filename); - input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); - input_name = input_name.substr(0, input_name.find_last_of(".")); - std::string output_name = input_name - + "_" + std::to_string(static_cast(relative_alpha)) - + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + const std::string output_name = generate_output_name(filename, relative_alpha, relative_offset); std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp index 9de47aefbcd2..9422e4d969be 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp @@ -1,3 +1,5 @@ +#include "output_helper.h" + #include #include @@ -64,11 +66,7 @@ int main(int argc, char** argv) std::cout << "Took " << t.time() << " s." << std::endl; // Save the result - std::string input_name = std::string(filename); - input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); - input_name = input_name.substr(0, input_name.find_last_of(".")); - std::string output_name = input_name + "_cavity_" + std::to_string(static_cast(relative_alpha)) - + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + const std::string output_name = generate_output_name(filename, relative_alpha, relative_offset); std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); From 660d6203308e7e32bbe37b0aea020f9a818459a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 4 Oct 2023 22:52:32 +0200 Subject: [PATCH 029/133] Accelerate trees manually to avoid skewing timers in flood_fill() If one day this becomes annoying because one wishes to call oracle.add_XXX() multiple times AND it's a significant runtime burden, we can just add a function add_XXXs() with a single call of accelerate_distance_queries() --- .../include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h | 6 ++++++ .../CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h | 6 ++++++ .../CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h | 6 ++++++ .../CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h index 7bad2ff313d4..8ccbf049a33e 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h @@ -115,6 +115,12 @@ class Point_set_oracle this->tree().insert(std::next(std::cbegin(m_points), old_size), std::cend(m_points)); + // Manually constructing it here purely for profiling reasons: if we keep the lazy approach, + // it will be done at the first treatment of a facet that needs a Steiner point. + // So if one wanted to bench the flood fill runtime, it would be skewed by the time it takes + // to accelerate the tree. + this->tree().accelerate_distance_queries(); + CGAL_postcondition(this->tree().size() == m_points.size()); } }; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h index d02a9f9faaf8..08e76dc6f5d3 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h @@ -113,6 +113,12 @@ class Segment_soup_oracle #endif this->tree().insert(std::next(std::cbegin(m_segments), old_size), std::cend(m_segments)); + // Manually constructing it here purely for profiling reasons: if we keep the lazy approach, + // it will be done at the first treatment of a facet that needs a Steiner point. + // So if one wanted to bench the flood fill runtime, it would be skewed by the time it takes + // to accelerate the tree. + this->tree().accelerate_distance_queries(); + CGAL_postcondition(this->tree().size() == m_segments.size()); } }; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h index c87f82ac75fe..869c108693d2 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h @@ -164,6 +164,12 @@ class Triangle_mesh_oracle Splitter_base::split_and_insert_datum(tr, this->tree(), this->geom_traits()); } + // Manually constructing it here purely for profiling reasons: if we keep the lazy approach, + // it will be done at the first treatment of a facet that needs a Steiner point. + // So if one wanted to bench the flood fill runtime, it would be skewed by the time it takes + // to accelerate the tree. + this->tree().accelerate_distance_queries(); + #ifdef CGAL_AW3_DEBUG std::cout << "Tree: " << this->tree().size() << " primitives (" << num_faces(tmesh) << " faces in input)" << std::endl; #endif diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h index 0a8f589fc2df..35966be46447 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h @@ -169,6 +169,12 @@ class Triangle_soup_oracle Splitter_base::split_and_insert_datum(tr, this->tree(), this->geom_traits()); } + // Manually constructing it here purely for profiling reasons: if we keep the lazy approach, + // it will be done at the first treatment of a facet that needs a Steiner point. + // So if one wanted to bench the flood fill runtime, it would be skewed by the time it takes + // to accelerate the tree. + this->tree().accelerate_distance_queries(); + #ifdef CGAL_AW3_DEBUG std::cout << "Tree: " << this->tree().size() << " primitives (" << faces.size() << " faces in input)" << std::endl; #endif From 88468764767950cda8daae96f5ab47885776afa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 4 Oct 2023 22:54:06 +0200 Subject: [PATCH 030/133] Check for degenerate segments + add warnings --- .../internal/Segment_soup_oracle.h | 20 +++++++++++++++++-- .../internal/Triangle_mesh_oracle.h | 5 +++++ .../internal/Triangle_soup_oracle.h | 10 ++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h index 08e76dc6f5d3..63f3532cf67e 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h @@ -40,7 +40,8 @@ struct SS_oracle_traits { using Geom_traits = Alpha_wrap_AABB_geom_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 - using Segments = std::vector; + using Segment = typename GT_::Segment_3; + using Segments = std::vector; using SR_iterator = typename Segments::const_iterator; using Primitive = AABB_primitive; @@ -105,8 +107,22 @@ class Segment_soup_oracle return; } + typename Geom_traits::Is_degenerate_3 is_degenerate = this->geom_traits().is_degenerate_3_object(); + const std::size_t old_size = m_segments.size(); - m_segments.insert(std::cend(m_segments), std::cbegin(segments), std::cend(segments)); + + for(const Segment& s : segments) + { + if(is_degenerate(s)) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Warning: ignoring degenerate segment " << s << std::endl; +#endif + continue; + } + + m_segments.push_back(s); + } #ifdef CGAL_AW3_DEBUG std::cout << "Insert into AABB tree (segments)..." << std::endl; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h index 869c108693d2..ffd8326a44f6 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h @@ -153,7 +153,12 @@ class Triangle_mesh_oracle for(face_descriptor f : faces(tmesh)) { if(Polygon_mesh_processing::is_degenerate_triangle_face(f, tmesh, np)) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Warning: ignoring degenerate face " << f << std::endl; +#endif continue; + } const Point_ref p0 = get(vpm, source(halfedge(f, tmesh), tmesh)); const Point_ref p1 = get(vpm, target(halfedge(f, tmesh), tmesh)); diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h index 35966be46447..27322a554e36 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h @@ -164,7 +164,12 @@ class Triangle_soup_oracle const Triangle_3 tr = triangle(p0, p1, p2); if(is_degenerate(tr)) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Warning: ignoring degenerate face " << tr << std::endl; +#endif continue; + } Splitter_base::split_and_insert_datum(tr, this->tree(), this->geom_traits()); } @@ -190,7 +195,12 @@ class Triangle_soup_oracle for(const Triangle_3& tr : triangles) { if(is_degenerate(tr)) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Warning: ignoring degenerate triangle " << tr << std::endl; +#endif continue; + } Splitter_base::split_and_insert_datum(tr, this->tree(), this->geom_traits()); } From 85c53f203ddf9ee118e401e8dae11bb84c8bfa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 5 Oct 2023 14:33:47 +0200 Subject: [PATCH 031/133] Add a new function to the AW3 visitor: go_further() --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 7c9509b9185a..c103a4e4c41e 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -92,6 +92,9 @@ struct Wrapping_default_visitor template void on_flood_fill_begin(const AlphaWrapper&) { } + template + constexpr bool go_further(const Wrapper& wrapper) { return true; } + template void before_facet_treatment(const AlphaWrapper&, const Gate&) { } @@ -1212,7 +1215,7 @@ class Alpha_wrap_3 } template - void alpha_flood_fill(Visitor& visitor) + bool alpha_flood_fill(Visitor& visitor) { #ifdef CGAL_AW3_DEBUG std::cout << "> Flood fill..." << std::endl; @@ -1251,10 +1254,6 @@ class Alpha_wrap_3 std::cout << "Permissiveness: " << gate.is_permissive_facet() << std::endl; #endif - visitor.before_facet_treatment(*this, gate); - - m_queue.pop(); - #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP static int i = 0; std::string step_name = "results/steps/step_" + std::to_string(static_cast(i)) + ".off"; @@ -1269,6 +1268,13 @@ class Alpha_wrap_3 face_out.close(); #endif + if(!visitor.go_further(*this)) + return false; + + visitor.before_facet_treatment(*this, gate); + + m_queue.pop(); + if(m_tr.is_infinite(neighbor)) { neighbor->is_outside() = true; @@ -1384,6 +1390,8 @@ class Alpha_wrap_3 CGAL_postcondition_code( if(!fit->first->is_outside()) f = m_tr.mirror_facet(f);) CGAL_postcondition( facet_status(f) == IRRELEVANT); CGAL_postcondition_code(}) + + return true; } private: From 3ff06d5099471c39a9e0c364138e38f7dc75634d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 5 Oct 2023 14:34:29 +0200 Subject: [PATCH 032/133] Fix return type of function returning smallest circumradius --- .../include/CGAL/Alpha_wrap_3/internal/geometry_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h index f39a47012862..991f9e48e25a 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h @@ -155,7 +155,7 @@ less_squared_radius_of_min_empty_sphere(typename Tr::Geom_traits::FT sq_alpha, } template -bool +typename Tr::Geom_traits::FT smallest_squared_radius_3(const typename Tr::Facet& fh, const Tr& tr) { From 76add8023e6bec512e7cdb7f6e234fd6835f20ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 5 Oct 2023 14:35:42 +0200 Subject: [PATCH 033/133] Add debug code --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 2 +- .../Alpha_wrap_3/internal/geometry_utils.h | 41 +++++++++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index c103a4e4c41e..9792b828a610 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -671,7 +671,7 @@ class Alpha_wrap_3 } t.stop(); - std::cout << t.time() << " for scanning" << std::endl; + std::cout << t.time() << " for scanning a queue of size " << m_queue.size() << std::endl; return true; } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h index 991f9e48e25a..7f5f60de701c 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/geometry_utils.h @@ -61,6 +61,10 @@ less_squared_radius_of_min_empty_sphere(typename Tr::Geom_traits::FT sq_alpha, Orientation_of_circumcenter orientation_of_circumcenter; +#ifdef CGAL_AW3_DEBUG_TRAVERSABILITY + std::cout << "Checking for traversability of facet" << std::endl; +#endif + const Cell_handle c = fh.first; const int ic = fh.second; const Cell_handle n = c->neighbor(ic); @@ -73,6 +77,11 @@ less_squared_radius_of_min_empty_sphere(typename Tr::Geom_traits::FT sq_alpha, // and because it does not cost anything. if(tr.is_infinite(n)) { +#ifdef CGAL_AW3_DEBUG_TRAVERSABILITY + std::cerr << "Warning: computing less_squared_radius_of_min_empty_sphere() with an infinite neighbor?" << std::endl; +#endif + CGAL_assertion(!tr.is_infinite(c)); + Orientation ori = orientation_of_circumcenter(p1, p2, p3, tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)); @@ -97,6 +106,10 @@ less_squared_radius_of_min_empty_sphere(typename Tr::Geom_traits::FT sq_alpha, tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3)); +#ifdef CGAL_AW3_DEBUG_TRAVERSABILITY + std::cout << "Cell 'c' is infinite; Orientation: " << ori << std::endl; +#endif + if(ori == NEGATIVE) { Comparison_result cr = compare_squared_radius(p1, p2, p3, sq_alpha); @@ -177,6 +190,12 @@ smallest_squared_radius_3(const typename Tr::Facet& fh, auto squared_radius = tr.geom_traits().compute_squared_radius_3_object(); +#ifdef CGAL_AW3_DEBUG_TRAVERSABILITY + std::cout << "Computing circumradius of facet" << std::endl; +#endif + + CGAL_precondition(!tr.is_infinite(fh)); + const Cell_handle c = fh.first; const int ic = fh.second; const Cell_handle n = c->neighbor(ic); @@ -189,6 +208,8 @@ smallest_squared_radius_3(const typename Tr::Facet& fh, // and because it does not cost anything. if(tr.is_infinite(n)) { + CGAL_assertion(!tr.is_infinite(c)); + Orientation ori = orientation_of_circumcenter(p1, p2, p3, tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)); @@ -203,6 +224,11 @@ smallest_squared_radius_3(const typename Tr::Facet& fh, Orientation ori = orientation_of_circumcenter(p1, p2, p3, tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3)); + +#ifdef CGAL_AW3_DEBUG_TRAVERSABILITY + std::cout << "Cell 'c' is infinite; Orientation: " << ori << std::endl; +#endif + if(ori == NEGATIVE) return squared_radius(p1, p2, p3); else @@ -215,14 +241,21 @@ smallest_squared_radius_3(const typename Tr::Facet& fh, orientation_of_circumcenter(p1, p2, p3, tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3))) { - // Dual crosses the face +#ifdef CGAL_AW3_DEBUG_TRAVERSABILITY + std::cout << "dual crosses the face; CR: " << squared_radius(p1, p2, p3) << std::endl; +#endif + return squared_radius(p1, p2, p3); } else { - // Dual does not crosses the face - FT cr = squared_radius(tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)); - FT cnr = squared_radius(tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3)); + const FT cr = squared_radius(tr.point(c, 0), tr.point(c, 1), tr.point(c, 2), tr.point(c, 3)); + const FT cnr = squared_radius(tr.point(n, 0), tr.point(n, 1), tr.point(n, 2), tr.point(n, 3)); + +#ifdef CGAL_AW3_DEBUG_TRAVERSABILITY + std::cout << "dual does not cross the face; CR(c): " << cr << " CRn: " << cnr << std::endl; +#endif + return (CGAL::min)(cr, cnr); } } From fb3623cfa90f95e0163ac454352dcf427ab6fddd Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Mon, 9 Oct 2023 05:10:30 +0200 Subject: [PATCH 034/133] Apply suggestions from code review Co-authored-by: Andreas Fabri --- .../Polygon_mesh_processing/refine_mesh_at_isolevel.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index 8a649b15ead4..7a3b2c0765e5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -28,8 +28,8 @@ namespace Polygon_mesh_processing { * The placement of new vertices on edges will be done by linear interpolation * using the aforementioned values. * New vertices will be associated `isovalue` in `value_map` when created. - * Additionally new edges will be added by connecting new vertices created sharing - * a common incident face. Note that in case more that two new vertices are added + * Additionally, new edges will be added by connecting new vertices created sharing + * a common incident face. Note that in case more than two new vertices are added * on a face boundary, no edges will be created in that face. * * @tparam PolygonMesh a model of the concepts `EdgeListGraph` and `FaceListGraph` @@ -39,7 +39,7 @@ namespace Polygon_mesh_processing { * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" for `pm` * * @param pm the polygon mesh to be refined. - * @param value_map the property map containing value at each vertex for a given function defined over the mesh. + * @param value_map the property map containing a value at each vertex for a given function defined over the mesh. * @param isovalue the value used to defined * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * @@ -72,7 +72,7 @@ void refine_mesh_at_isolevel(PolygonMesh& pm, typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename boost::property_map::value_type FT; + typedef typename boost::property_traits::value_type FT; using parameters::choose_parameter; using parameters::get_parameter; From 1c91f49cbdafc980f1e6f32a74fb24b98bf12fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 9 Oct 2023 05:14:38 +0200 Subject: [PATCH 035/133] update changes --- Installation/CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 8ee04d38577d..ef51234bb6e7 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -52,6 +52,10 @@ Release date: October 2023 `CGAL::Simplicial_mesh_cell_base_3` have been modified to enable passing a geometric traits and a custom cell base class. +### [Polygon Mesh Processing](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolygonMeshProcessing) +- added the function `CGAL::Polygon_mesh_processing::refine_mesh_at_isolevel()` that refines a polygon mesh + along an isocurve. + [Release 5.6](https://github.com/CGAL/cgal/releases/tag/v5.6) ----------- From 584771e6a752d45d4089e33bfc01cef98f584aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 9 Oct 2023 05:34:55 +0200 Subject: [PATCH 036/133] rename --- .../geodesic_isolevel_refinement.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp index 76f97bf3dc66..29f43453e87a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/geodesic_isolevel_refinement.cpp @@ -59,14 +59,14 @@ int main(int argc, char* argv[]) CGAL::Polygon_mesh_processing::refine_mesh_at_isolevel(tm, vertex_distance, isovalue, CGAL::parameters::edge_is_constrained_map(ecm)); // split the mesh in connected components bounded by the isocurves - std::vector splitted; - CGAL::Polygon_mesh_processing::split_connected_components(tm, splitted, CGAL::parameters::edge_is_constrained_map(ecm)); + std::vector edges_split; + CGAL::Polygon_mesh_processing::split_connected_components(tm, edges_split, CGAL::parameters::edge_is_constrained_map(ecm)); - assert(argc!=1 || splitted.size() == 22); + assert(argc!=1 || edges_split.size() == 22); // export each submesh in a file - for(std::size_t i=0; i Date: Mon, 9 Oct 2023 12:12:31 +0200 Subject: [PATCH 037/133] Remove obsolete sort at every iteration There was a need for sorting at every iteration when the sorting used criteria which were changing with every iteration. This is no longer the case after c7b9317. Also make it deterministic. --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 639c9a3f4685..ba4635889b4b 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1440,15 +1440,17 @@ class Alpha_wrap_3 // Prioritize: // - cells without bbox vertices - // - cells that already have a large number of boundary facets // - small cells when equal number of boundary facets - // @todo give topmost priority to cells with > 1 non-manifold vertex? + // + // Note that these are properties that do not depend on where the surface is, so we can + // sort once. However, if a criterion such as the number of inside cells were added, + // one would need to sort again after each modification of is_outside() statuses. auto comparer = [&](Cell_handle l, Cell_handle r) -> bool { - if(has_artificial_vertex(l)) - return false; - if(has_artificial_vertex(r)) - return true; + CGAL_precondition(!m_dt.is_infinite(l) && !m_dt.is_infinite(r)); + + if(has_artificial_vertex(l) != has_artificial_vertex(r)) + return has_artificial_vertex(r); return sq_longest_edge(l) < sq_longest_edge(r); }; @@ -1457,17 +1459,13 @@ class Alpha_wrap_3 inc_cells.reserve(64); m_dt.finite_incident_cells(v, std::back_inserter(inc_cells)); -#define CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE -#ifndef CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE - std::sort(inc_cells.begin(), inc_cells.end(), comparer); // sort once -#endif + // 'std::stable_sort' to have determinism without having to write something like: + // if(longest_edge(l) == longest_edge(r)) return ... + // in the comparer. It's a small range, so the cost does not matter. + std::stable_sort(inc_cells.begin(), inc_cells.end(), comparer); for(auto cit=inc_cells.begin(), cend=inc_cells.end(); cit!=cend; ++cit) { -#ifdef CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE - // sort at every iteration since the number of boundary facets evolves - std::sort(cit, cend, comparer); -#endif Cell_handle ic = *cit; CGAL_assertion(!m_dt.is_infinite(ic)); From 2f1992f131dd107d4c7cd3251181afb92cee12fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 9 Oct 2023 15:16:10 +0200 Subject: [PATCH 038/133] Add LIFO queue But keep the old one, because we might need something sorted in the future. Also it is needed to do interrupting, because the intermediate is really ugly for a LIFO queue. --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 72 +++++++++++++++---- .../Alpha_wrap_triangulation_cell_base_3.h | 27 ++++++- .../internal/gate_priority_queue.h | 40 +++++++++++ 3 files changed, 124 insertions(+), 15 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 9792b828a610..08f09fcdd4ce 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -49,7 +49,9 @@ #include #include #include -#include +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + #include +#endif #include #include #include @@ -140,7 +142,18 @@ class Alpha_wrap_3 using Locate_type = typename Triangulation::Locate_type; using Gate = internal::Gate; + + // A sorted queue is a priority queue sorted by circumradius, and is experimentally much slower, + // but intermediate results are visually nice: somewhat uniform meshes. + // + // An unsorted queue is a LIFO queue, and is experimentally much faster (~35%), + // but intermediate results are not useful: a LIFO will mean carving is done very deep + // before than wide +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; +#else + using Alpha_PQ = std::stack; +#endif using FT = typename Geom_traits::FT; using Point_3 = typename Geom_traits::Point_3; @@ -166,20 +179,27 @@ class Alpha_wrap_3 public: Alpha_wrap_3() +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + // '4096' is an arbitrary, not-too-small value for the largest ID in queue initialization : m_queue(4096) - { } - - Alpha_wrap_3(const Oracle& oracle) - : m_oracle(oracle), - m_tr(Geom_traits(oracle.geom_traits())), - // used to set up the initial MPQ, use some arbitrary not-too-small value - m_queue(4096) +#endif { // Due to the Steiner point computation being a dichotomy, the algorithm is inherently inexact // and passing exact kernels is explicitly disabled to ensure no misunderstanding. static_assert(std::is_floating_point::value); } + Alpha_wrap_3(const Oracle& oracle) + : +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + m_queue(4096), +#endif + m_oracle(oracle), + m_tr(Geom_traits(oracle.geom_traits())) + { + static_assert(std::is_floating_point::value); + } + public: const Geom_traits& geom_traits() const { return m_tr.geom_traits(); } Oracle& oracle() { return m_oracle; } @@ -1130,17 +1150,23 @@ class Alpha_wrap_3 { CGAL_precondition(f.first->is_outside()); +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE // skip if f is already in queue if(m_queue.contains_with_bounds_check(Gate(f))) return false; +#endif const Facet_queue_status status = facet_status(f); if(status == IRRELEVANT) return false; +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE const FT sqr = smallest_squared_radius_3(f, m_tr); const bool is_permissive = (status == HAS_INFINITE_NEIGHBOR || status == SCAFFOLDING); m_queue.resize_and_push(Gate(f, sqr, is_permissive)); +#else + m_queue.push(Gate(f, m_tr)); +#endif #ifdef CGAL_AW3_DEBUG_QUEUE const Cell_handle ch = f.first; @@ -1154,11 +1180,13 @@ class Alpha_wrap_3 << " ch = " << &*ch << " (" << m_tr.is_infinite(ch) << ") " << "\n" << "\t" << p0 << "\n\t" << p1 << "\n\t" << p2 << std::endl; std::cout << " Status: " << get_status_message(status) << std::endl; + #ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE std::cout << " SQR: " << sqr << std::endl; std::cout << " Permissiveness: " << is_permissive << std::endl; -#endif CGAL_assertion(is_permissive || sqr >= m_sq_alpha); + #endif // CGAL_AW3_USE_SORTED_PRIORITY_QUEUE +#endif // CGAL_AW3_DEBUG_QUEUE return true; } @@ -1195,7 +1223,11 @@ class Alpha_wrap_3 m_offset = FT(offset); m_sq_offset = square(m_offset); +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE m_queue.clear(); +#else + m_queue = { }; +#endif if(resuming) { @@ -1232,6 +1264,15 @@ class Alpha_wrap_3 // const& to something that will be popped, but safe as `ch` && `id` are extracted before the pop const Gate& gate = m_queue.top(); + +#ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + if(gate.is_zombie()) + { + m_queue.pop(); + continue; + } +#endif + const Facet& f = gate.facet(); CGAL_precondition(!m_tr.is_infinite(f)); @@ -1304,6 +1345,7 @@ class Alpha_wrap_3 std::back_inserter(boundary_facets), std::back_inserter(conflict_zone)); +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE // Purge the queue of facets that will be deleted/modified by the Steiner point insertion, // and which might have been gates for(const Cell_handle& cch : conflict_zone) @@ -1322,6 +1364,7 @@ class Alpha_wrap_3 if(m_queue.contains_with_bounds_check(Gate(mf))) m_queue.erase(Gate(mf)); } +#endif visitor.before_Steiner_point_insertion(*this, steiner_point); @@ -1715,18 +1758,23 @@ class Alpha_wrap_3 const Point_3& p0 = m_tr.point(ch, Triangulation::vertex_triple_index(id, 0)); const Point_3& p1 = m_tr.point(ch, Triangulation::vertex_triple_index(id, 1)); const Point_3& p2 = m_tr.point(ch, Triangulation::vertex_triple_index(id, 2)); - const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); - std::cout << "At Facet with VID " << get(Gate_ID_PM(), current_gate) << "\n"; + std::cout << "Facet with VID " << get(Gate_ID_PM(), current_gate) << "\n"; std::cout << "\t" << p0 << "\n\t" << p1 << "\n\t" << p2 << "\n"; + +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE std::cout << " Permissiveness: " << current_gate.is_permissive_facet() << "\n"; - std::cout << " SQR: " << sqr << "\n"; + std::cout << " SQR: " << geom_traits().compute_squared_radius_3_object()(p0, p1, p2) << "\n"; std::cout << " Priority " << current_gate.priority() << std::endl; if(Less_gate()(current_gate, previous_top_gate)) std::cerr << "Error: current gate has higher priority than the previous top" << std::endl; previous_top_gate = current_gate; +#else + if(current_gate.is_zombie()) + std::cout << "Gate is a zombie!" << std::endl; +#endif m_queue.pop(); } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h index db1df61c8f65..b586d495f0d3 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h @@ -25,9 +25,6 @@ template < typename GT, class Alpha_wrap_triangulation_cell_base_3 : public Cb { -private: - bool outside = false; - public: typedef typename Cb::Vertex_handle Vertex_handle; typedef typename Cb::Cell_handle Cell_handle; @@ -39,6 +36,14 @@ class Alpha_wrap_triangulation_cell_base_3 using Other = Alpha_wrap_triangulation_cell_base_3; }; +private: + bool outside = false; + +#ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + unsigned int m_erase_counter; +#endif + +public: Alpha_wrap_triangulation_cell_base_3() : Cb() {} @@ -55,8 +60,24 @@ class Alpha_wrap_triangulation_cell_base_3 : Cb(v0, v1, v2, v3, n0, n1, n2, n3) {} +public: bool is_outside() const { return outside; } bool& is_outside() { return outside; } + +#ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + unsigned int erase_counter() const + { + return m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + m_erase_counter = c; + } + void increment_erase_counter() + { + ++m_erase_counter; + } +#endif }; template diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index b091b2cabe24..f017f9be8cf4 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -27,6 +27,8 @@ namespace CGAL { namespace Alpha_wraps_3 { namespace internal { +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + // Represents an alpha-traversable facet in the mutable priority queue template class Gate @@ -90,6 +92,44 @@ struct Less_gate } }; +#else // CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + +// Represents an alpha-traversable facet in the mutable priority queue +template +class Gate +{ + using Facet = typename Tr::Facet; + using FT = typename Tr::Geom_traits::FT; + +private: + Facet m_facet, m_mirror_facet; + const unsigned int m_erase_counter_mem; + const unsigned int m_mirror_erase_counter_mem; + +public: + // Constructors + Gate(const Facet& facet, + const Tr& tr) + : + m_facet(facet), + m_mirror_facet(tr.mirror_facet(facet)), + m_erase_counter_mem(m_facet.first->erase_counter()), + m_mirror_erase_counter_mem(m_mirror_facet.first->erase_counter()) + { + } + +public: + const Facet& facet() const { return m_facet; } + + const bool is_zombie() const + { + return (m_facet.first->erase_counter() != m_erase_counter_mem) || + (m_mirror_facet.first->erase_counter() != m_mirror_erase_counter_mem); + } +}; + +#endif // CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + template struct Gate_ID_PM { From 7d2de68d1cf7665acaa415dcaffc507dccd9f15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 9 Oct 2023 16:55:57 -0700 Subject: [PATCH 039/133] add missing include directive --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index 7a3b2c0765e5..4e9082996e49 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -15,6 +15,7 @@ #include +#include #include namespace CGAL { From 0e9da7ab960b4abebf6738547d260c3c5e0af5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 10 Oct 2023 12:19:44 +0200 Subject: [PATCH 040/133] Debug code and minor cleaning --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 117 +++++++++++------- .../internal/gate_priority_queue.h | 4 +- 2 files changed, 72 insertions(+), 49 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 08f09fcdd4ce..2764546c3181 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -175,6 +175,7 @@ class Alpha_wrap_3 FT m_offset = FT(-1), m_sq_offset = FT(-1); Triangulation m_tr; + Alpha_PQ m_queue; public: @@ -250,24 +251,33 @@ class Alpha_wrap_3 using parameters::get_parameter_reference; using parameters::choose_parameter; + // using OVPM = typename CGAL::GetVertexPointMap::type; OVPM ovpm = choose_parameter(get_parameter(out_np, internal_np::vertex_point), get_property_map(vertex_point, output_mesh)); - typedef typename internal_np::Lookup_named_param_def < - internal_np::visitor_t, - InputNamedParameters, - Wrapping_default_visitor // default - >::reference Visitor; + // + using Visitor = typename internal_np::Lookup_named_param_def< + internal_np::visitor_t, + InputNamedParameters, + Wrapping_default_visitor // default + >::reference; Wrapping_default_visitor default_visitor; Visitor visitor = choose_parameter(get_parameter_reference(in_np, internal_np::visitor), default_visitor); - std::vector no_seeds; + // using Seeds = typename internal_np::Lookup_named_param_def< - internal_np::seed_points_t, InputNamedParameters, std::vector >::reference; + internal_np::seed_points_t, + InputNamedParameters, + std::vector >::reference; + + std::vector no_seeds; Seeds seeds = choose_parameter(get_parameter_reference(in_np, internal_np::seed_points), no_seeds); + // Whether or not some cells should be reflagged as "inside" after the refinement+carving loop + // as ended, as to ensure that the result is not only combinatorially manifold, but also + // geometrically manifold. const bool do_enforce_manifoldness = choose_parameter(get_parameter(in_np, internal_np::do_enforce_manifoldness), true); // This parameter enables avoiding recomputing the triangulation from scratch when wrapping @@ -294,9 +304,16 @@ class Alpha_wrap_3 if(!initialize(alpha, offset, seeds, resuming)) return; +#ifdef CGAL_AW3_TIMER + t.stop(); + std::cout << "Initialization took: " << t.time() << " s." << std::endl; + t.reset(); + t.start(); +#endif + #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP extract_surface(output_mesh, ovpm, true /*tolerate non manifoldness*/); - CGAL::IO::write_polygon_mesh("initial_cavities.off", output_mesh, + CGAL::IO::write_polygon_mesh("starting_wrap.off", output_mesh, CGAL::parameters::vertex_point_map(ovpm).stream_precision(17)); #endif @@ -305,20 +322,20 @@ class Alpha_wrap_3 #ifdef CGAL_AW3_TIMER t.stop(); std::cout << "Flood filling took: " << t.time() << " s." << std::endl; + t.reset(); + t.start(); #endif if(do_enforce_manifoldness) { -#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS - std::cout << "> Make manifold..." << std::endl; - +#ifdef CGAL_AW3_DEBUG extract_surface(output_mesh, ovpm, true /*tolerate non manifoldness*/); -#ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP - dump_triangulation_faces("intermediate_tr.off", false /*only_boundary_faces*/); - IO::write_polygon_mesh("intermediate.off", output_mesh, + #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP + dump_triangulation_faces("carved_tr.off", false /*only_boundary_faces*/); + IO::write_polygon_mesh("carved_wrap.off", output_mesh, CGAL::parameters::vertex_point_map(ovpm).stream_precision(17)); -#endif + #endif FT base_vol = 0; if(is_closed(output_mesh)) // might not be due to manifoldness @@ -327,19 +344,16 @@ class Alpha_wrap_3 std::cerr << "Warning: couldn't compute volume before manifoldness fixes (mesh is not closed)" << std::endl; #endif -#ifdef CGAL_AW3_TIMER - t.reset(); - t.start(); -#endif - make_manifold(); #ifdef CGAL_AW3_TIMER t.stop(); - std::cout << "\nManifoldness post-processing took: " << t.time() << " s." << std::endl; + std::cout << "Manifoldness post-processing took: " << t.time() << " s." << std::endl; + t.reset(); + t.start(); #endif -#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS +#ifdef CGAL_AW3_DEBUG if(!is_zero(base_vol)) { extract_surface(output_mesh, ovpm, false /*do not tolerate non-manifoldness*/); @@ -751,7 +765,7 @@ class Alpha_wrap_3 if(faces.empty()) { #ifdef CGAL_AW3_DEBUG - std::cout << "Empty wrap?..." << std::endl; + std::cerr << "Warning: empty wrap?..." << std::endl; #endif return; } @@ -791,7 +805,8 @@ class Alpha_wrap_3 std::vector points; std::vector > polygons; - // Explode the polygon soup into indepent triangles, and stitch back edge by edge by walking along the exterior + // Explode the polygon soup into indepent triangles, and stitch it back + // edge by edge by walking along the exterior std::map facet_ids; std::size_t idx = 0; @@ -817,10 +832,15 @@ class Alpha_wrap_3 idx += 3; } +#ifdef CGAL_AW3_DEBUG + std::cout << "\t" << points.size() << " points" << std::endl; + std::cout << "\t" << polygons.size() << " polygons" << std::endl; +#endif + if(polygons.empty()) { #ifdef CGAL_AW3_DEBUG - std::cout << "Empty wrap?..." << std::endl; + std::cerr << "Warning: empty wrap?..." << std::endl; #endif return; } @@ -1280,14 +1300,14 @@ class Alpha_wrap_3 const int s = f.second; CGAL_precondition(ch->is_outside()); - const Cell_handle neighbor = ch->neighbor(s); + const Cell_handle nh = ch->neighbor(s); #ifdef CGAL_AW3_DEBUG_QUEUE static int fid = 0; std::cout << m_tr.number_of_vertices() << " DT vertices" << std::endl; std::cout << m_queue.size() << " facets in the queue" << std::endl; std::cout << "Face " << fid++ << "\n" - << "c = " << &*ch << " (" << m_tr.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_tr.is_infinite(neighbor) << ")" << "\n" + << "c = " << &*ch << " (" << m_tr.is_infinite(ch) << "), n = " << &*nh << " (" << m_tr.is_infinite(nh) << ")" << "\n" << m_tr.point(ch, Triangulation::vertex_triple_index(s, 0)) << "\n" << m_tr.point(ch, Triangulation::vertex_triple_index(s, 1)) << "\n" << m_tr.point(ch, Triangulation::vertex_triple_index(s, 2)) << std::endl; @@ -1316,14 +1336,14 @@ class Alpha_wrap_3 m_queue.pop(); - if(m_tr.is_infinite(neighbor)) + if(m_tr.is_infinite(nh)) { - neighbor->is_outside() = true; + nh->is_outside() = true; continue; } Point_3 steiner_point; - if(compute_steiner_point(ch, neighbor, steiner_point)) + if(compute_steiner_point(ch, nh, steiner_point)) { // std::cout << CGAL::abs(CGAL::approximate_sqrt(m_oracle.squared_distance(steiner_point)) - m_offset) // << " vs " << 1e-2 * m_offset << std::endl; @@ -1332,7 +1352,7 @@ class Alpha_wrap_3 // locate cells that are going to be destroyed and remove their facet from the queue int li, lj = 0; Locate_type lt; - const Cell_handle conflict_cell = m_tr.locate(steiner_point, lt, li, lj, neighbor); + const Cell_handle conflict_cell = m_tr.locate(steiner_point, lt, li, lj, nh); CGAL_assertion(lt != Triangulation::VERTEX); // Using small vectors like in Triangulation_3 does not bring any runtime improvement @@ -1379,10 +1399,10 @@ class Alpha_wrap_3 std::vector new_cells; new_cells.reserve(32); m_tr.incident_cells(vh, std::back_inserter(new_cells)); - for(const Cell_handle& ch : new_cells) + for(const Cell_handle& new_ch : new_cells) { - // std::cout << "new cell has time stamp " << ch->time_stamp() << std::endl; - ch->is_outside() = m_tr.is_infinite(ch); + // std::cout << "new cell has time stamp " << new_ch->time_stamp() << std::endl; + new_ch->is_outside() = m_tr.is_infinite(new_ch); } // Push all new boundary facets to the queue. @@ -1390,19 +1410,19 @@ class Alpha_wrap_3 // because we need to handle internal facets, infinite facets, and also more subtle changes // such as a new cell being marked inside which now creates a boundary // with its incident "outside" flagged cell. - for(Cell_handle ch : new_cells) + for(Cell_handle new_ch : new_cells) { for(int i=0; i<4; ++i) { - if(m_tr.is_infinite(ch, i)) + if(m_tr.is_infinite(new_ch, i)) continue; - const Cell_handle nh = ch->neighbor(i); - if(nh->is_outside() == ch->is_outside()) // not on the boundary + const Cell_handle new_nh = new_ch->neighbor(i); + if(new_nh->is_outside() == new_ch->is_outside()) // not on the boundary continue; - const Facet boundary_f = std::make_pair(ch, i); - if(ch->is_outside()) + const Facet boundary_f = std::make_pair(new_ch, i); + if(new_ch->is_outside()) push_facet(boundary_f); else push_facet(m_tr.mirror_facet(boundary_f)); @@ -1411,14 +1431,13 @@ class Alpha_wrap_3 } else // no need for a Steiner point, carve through and continue { - // tag neighbor as OUTSIDE - neighbor->is_outside() = true; + nh->is_outside() = true; // for each finite facet of neighbor, push it to the queue const int mi = m_tr.mirror_index(ch, s); for(int i=1; i<4; ++i) { - const Facet neighbor_f = std::make_pair(neighbor, (mi+i)&3); + const Facet neighbor_f = std::make_pair(nh, (mi+i)&3); push_facet(neighbor_f); } } @@ -1590,6 +1609,10 @@ class Alpha_wrap_3 { namespace PMP = Polygon_mesh_processing; +#ifdef CGAL_AW3_DEBUG + std::cout << "> Make manifold..." << std::endl; +#endif + // This seems more harmful than useful after the priority queue has been introduced since // it adds a lot of flat cells into the triangulation, which then get added to the mesh // during manifoldness fixing. @@ -1802,17 +1825,17 @@ class Alpha_wrap_3 for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) { - Cell_handle c = fit->first; + Cell_handle ch = fit->first; int s = fit->second; - Cell_handle nc = c->neighbor(s); - if(only_boundary_faces && (c->is_outside() == nc->is_outside())) + Cell_handle nh = ch->neighbor(s); + if(only_boundary_faces && (ch->is_outside() == nh->is_outside())) continue; std::array ids; for(std::size_t pos=0; pos<3; ++pos) { - Vertex_handle v = c->vertex((s+pos+1)&3); + Vertex_handle v = ch->vertex((s+pos+1)&3); auto insertion_res = vertex_to_id.emplace(v, nv); if(insertion_res.second) { diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index f017f9be8cf4..9c29ac9e7226 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -74,8 +74,8 @@ struct Less_gate // // The permissive facet are given highest priority because they need to be treated // regardless of their circumradius. Treating them first allow the part that depends - // on alpha to be treated uniformly in a way: whatever the alpha, we'll do the same - // first treatmen + // on alpha to be treated uniformly in a way: whatever the alpha, all scaffolding faces + // will first be treated if(a.is_permissive_facet() != b.is_permissive_facet()) return a.is_permissive_facet(); From 48d2057f40309e576a31a28564def43fee81e183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 10 Oct 2023 12:58:14 +0200 Subject: [PATCH 041/133] Add a third type of cell label to distinguish relabeling for manifoldness --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 139 +++++++++++------- .../Alpha_wrap_triangulation_cell_base_3.h | 19 ++- 2 files changed, 102 insertions(+), 56 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 2764546c3181..f22fbfaa1f31 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -438,6 +438,20 @@ class Alpha_wrap_3 return bbox; } +private: + // The distinction between inside boundary and outside boundary is the presence of cells + // being flagged for manifoldness: inside boundary considers those outside, and outside + // boundary considers them inside. + bool is_on_inside_boundary(Cell_handle ch, Cell_handle nh) const + { + return (ch->is_inside() != nh->is_inside()); // one is INSIDE, the other is not + } + + bool is_on_outside_boundary(Cell_handle ch, Cell_handle nh) const + { + return (ch->is_outside() != nh->is_outside()); // one is OUTSIDE, the other is not + } + private: // Adjust the bbox & insert its corners to construct the starting triangulation void insert_bbox_corners() @@ -465,20 +479,20 @@ class Alpha_wrap_3 // - Cells whose circumcenter is in the offset volume are inside: this is because // we need to have outside cell circumcenters outside of the volume to ensure // that the refinement point is separated from the existing point set. - bool cavity_cell_outside_tag(const Cell_handle ch) + Cell_label cavity_cell_label(const Cell_handle ch) { CGAL_precondition(!m_tr.is_infinite(ch)); const Tetrahedron_with_outside_info tet(ch, geom_traits()); if(m_oracle.do_intersect(tet)) - return false; + return Cell_label::INSIDE; const Point_3& ch_cc = circumcenter(ch); typename Geom_traits::Construct_ball_3 ball = geom_traits().construct_ball_3_object(); const Ball_3 ch_cc_offset_ball = ball(ch_cc, m_sq_offset); const bool is_cc_in_offset = m_oracle.do_intersect(ch_cc_offset_ball); - return !is_cc_in_offset; + return is_cc_in_offset ? Cell_label::INSIDE : Cell_label::OUTSIDE; } // Create a cavity using seeds rather than starting from the infinity. @@ -631,16 +645,17 @@ class Alpha_wrap_3 m_tr.incident_cells(seed_v, std::back_inserter(inc_cells)); for(Cell_handle ch : inc_cells) - ch->is_outside() = cavity_cell_outside_tag(ch); + ch->label() = cavity_cell_label(ch); } // Should be cheap enough to go through the full triangulation as only seeds have been inserted for(Cell_handle ch : m_tr.all_cell_handles()) { - if(!ch->is_outside()) + if(ch->is_inside()) continue; - // When the algorithm starts from a manually dug hole, infinite cells are tagged "inside" + // When the algorithm starts from a manually dug hole, infinite cells are initialized + // as INSIDE such that they do not appear on the boundary CGAL_assertion(!m_tr.is_infinite(ch)); for(int i=0; i<4; ++i) @@ -666,19 +681,26 @@ class Alpha_wrap_3 { if(m_tr.is_infinite(ch)) { - ch->is_outside() = true; + ch->label() = Cell_label::OUTSIDE; const int inf_index = ch->index(m_tr.infinite_vertex()); push_facet(std::make_pair(ch, inf_index)); } else { - ch->is_outside() = false; + ch->label() = Cell_label::INSIDE; } } return true; } + void reset_manifold_labels() + { + for(Cell_handle ch : m_tr.all_cell_handles()) + if(ch->label() == Cell_label::MANIFOLD) + ch->label() = Cell_label::OUTSIDE; + } + // This function is used in the case of resumption of a previous run: m_tr is not cleared, // and we fill the queue with the new parameters. bool initialize_from_existing_triangulation() @@ -692,7 +714,7 @@ class Alpha_wrap_3 for(Cell_handle ch : m_tr.all_cell_handles()) { - if(!ch->is_outside()) + if(ch->is_inside()) continue; for(int i=0; i<4; ++i) @@ -711,9 +733,24 @@ class Alpha_wrap_3 } private: - void extract_boundary(std::vector& points, - std::vector >& faces) const + template + void extract_manifold_surface(OutputMesh& output_mesh, + OVPM ovpm) const { + namespace PMP = Polygon_mesh_processing; + +#ifdef CGAL_AW3_DEBUG + std::cout << "> Extract manifold wrap... ()" << std::endl; +#endif + + CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) + CGAL_assertion(!is_non_manifold(v)); + + clear(output_mesh); + + std::vector points; + std::vector > faces; + std::unordered_map vertex_to_id; for(auto fit=m_tr.all_facets_begin(), fend=m_tr.all_facets_end(); fit!=fend; ++fit) @@ -725,7 +762,7 @@ class Alpha_wrap_3 const Cell_handle ch = f.first; const int s = f.second; const Cell_handle nh = ch->neighbor(s); - if(ch->is_outside() == nh->is_outside()) + if(!is_on_outside_boundary(ch, nh)) continue; std::array ids; @@ -741,27 +778,12 @@ class Alpha_wrap_3 faces.emplace_back(std::array{ids[0], ids[1], ids[2]}); } - } - - template - void extract_manifold_surface(OutputMesh& output_mesh, - OVPM ovpm) const - { - namespace PMP = Polygon_mesh_processing; #ifdef CGAL_AW3_DEBUG - std::cout << "> Extract manifold wrap... ()" << std::endl; + std::cout << "\t" << points.size() << " points" << std::endl; + std::cout << "\t" << faces.size() << " faces" << std::endl; #endif - CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) - CGAL_assertion(!is_non_manifold(v)); - - clear(output_mesh); - - std::vector points; - std::vector > faces; - extract_boundary(points, faces); - if(faces.empty()) { #ifdef CGAL_AW3_DEBUG @@ -787,8 +809,8 @@ class Alpha_wrap_3 } template - void extract_possibly_non_manifold_surface(OutputMesh& output_mesh, - OVPM ovpm) const + void extract_inside_boundary(OutputMesh& output_mesh, + OVPM ovpm) const { namespace PMP = Polygon_mesh_processing; @@ -810,16 +832,20 @@ class Alpha_wrap_3 std::map facet_ids; std::size_t idx = 0; + // Looks identical to the block in extract_manifold_surface(), but there are + // two significant differences: + // - Boundary considers MANIFOLD outside here + // - There is no attempt to re-use the same vertex in multiple faces for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) { Facet f = *fit; - if(!f.first->is_outside()) + if(f.first->is_inside()) // need f.first to be OUTSIDE or MANIFOLD f = m_tr.mirror_facet(f); const Cell_handle ch = f.first; const int s = f.second; const Cell_handle nh = ch->neighbor(s); - if(ch->is_outside() == nh->is_outside()) + if(!is_on_inside_boundary(ch, nh)) // MANIFOLD here is outside continue; facet_ids[f] = idx / 3; @@ -858,13 +884,13 @@ class Alpha_wrap_3 for(auto fit=m_tr.all_facets_begin(), fend=m_tr.all_facets_end(); fit!=fend; ++fit) { Facet f = *fit; - if(!f.first->is_outside()) + if(f.first->is_inside()) // f.first must be MANIFOLD or OUTSIDE f = m_tr.mirror_facet(f); const Cell_handle ch = f.first; const int s = f.second; const Cell_handle nh = ch->neighbor(s); - if(ch->is_outside() == nh->is_outside()) + if(!is_on_inside_boundary(ch, nh)) // MANIFOLD here is outside continue; put(face_to_facet, i2f[idx++], f); @@ -877,7 +903,7 @@ class Alpha_wrap_3 { const Facet& tr_f = get(face_to_facet, f); const Cell_handle ch = tr_f.first; - CGAL_assertion(ch->is_outside()); + CGAL_assertion(!ch->is_inside()); // OUTSIDE or MANIFOLD for(halfedge_descriptor h : halfedges_around_face(halfedge(f, output_mesh), output_mesh)) { @@ -922,18 +948,18 @@ class Alpha_wrap_3 third_vh = curr_ch->vertex(facet_third_id); curr_ch = curr_ch->neighbor(Triangulation::next_around_edge(i,j)); - if(!curr_ch->is_outside()) + if(curr_ch->is_inside()) break; } while(curr_ch != start_ch); CGAL_assertion(curr_ch != start_ch); - CGAL_assertion(!curr_ch->is_outside()); + CGAL_assertion(curr_ch->is_inside()); const int opp_id = 6 - (curr_ch->index(s_vh) + curr_ch->index(t_vh) + curr_ch->index(third_vh)); const Facet tr_f2 = m_tr.mirror_facet(Facet(curr_ch, opp_id)); CGAL_assertion(facet_ids.count(Facet(curr_ch, opp_id)) == 0); - CGAL_assertion(tr_f2.first->is_outside()); + CGAL_assertion(!tr_f2.first->is_inside()); CGAL_assertion(tr_f2.first->neighbor(tr_f2.second) == curr_ch); CGAL_assertion(tr_f2.first->has_vertex(s_vh) && tr_f2.first->has_vertex(t_vh)); @@ -972,7 +998,7 @@ class Alpha_wrap_3 const bool tolerate_non_manifoldness = false) const { if(tolerate_non_manifoldness) - extract_possibly_non_manifold_surface(output_mesh, ovpm); + extract_inside_boundary(output_mesh, ovpm); else extract_manifold_surface(output_mesh, ovpm); } @@ -1115,8 +1141,9 @@ class Alpha_wrap_3 // skip if neighbor is OUTSIDE or infinite const Cell_handle ch = f.first; const int id = f.second; + CGAL_precondition(ch->label() == Cell_label::INSIDE || ch->label() == Cell_label::OUTSIDE); - if(!ch->is_outside()) + if(!ch->is_outside()) // INSIDE or MANIFOLD { #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "Facet is inside" << std::endl; @@ -1125,6 +1152,8 @@ class Alpha_wrap_3 } const Cell_handle nh = ch->neighbor(id); + CGAL_precondition(ch->label() == Cell_label::INSIDE || ch->label() == Cell_label::OUTSIDE); + if(m_tr.is_infinite(nh)) return HAS_INFINITE_NEIGHBOR; @@ -1301,6 +1330,7 @@ class Alpha_wrap_3 CGAL_precondition(ch->is_outside()); const Cell_handle nh = ch->neighbor(s); + CGAL_precondition(nh->label() == Cell_label::INSIDE || nh->label() == Cell_label::OUTSIDE); #ifdef CGAL_AW3_DEBUG_QUEUE static int fid = 0; @@ -1338,7 +1368,7 @@ class Alpha_wrap_3 if(m_tr.is_infinite(nh)) { - nh->is_outside() = true; + nh->label() = Cell_label::OUTSIDE; continue; } @@ -1402,7 +1432,7 @@ class Alpha_wrap_3 for(const Cell_handle& new_ch : new_cells) { // std::cout << "new cell has time stamp " << new_ch->time_stamp() << std::endl; - new_ch->is_outside() = m_tr.is_infinite(new_ch); + new_ch->label() = m_tr.is_infinite(new_ch) ? Cell_label::OUTSIDE : Cell_label::INSIDE; } // Push all new boundary facets to the queue. @@ -1418,7 +1448,7 @@ class Alpha_wrap_3 continue; const Cell_handle new_nh = new_ch->neighbor(i); - if(new_nh->is_outside() == new_ch->is_outside()) // not on the boundary + if(new_nh->label() == new_ch->label()) // not on a boundary continue; const Facet boundary_f = std::make_pair(new_ch, i); @@ -1431,7 +1461,7 @@ class Alpha_wrap_3 } else // no need for a Steiner point, carve through and continue { - nh->is_outside() = true; + nh->label() = Cell_label::OUTSIDE; // for each finite facet of neighbor, push it to the queue const int mi = m_tr.mirror_index(ch, s); @@ -1447,9 +1477,10 @@ class Alpha_wrap_3 // Check that no useful facet has been ignored CGAL_postcondition_code(for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) {) - CGAL_postcondition_code( if(fit->first->is_outside() == fit->first->neighbor(fit->second)->is_outside()) continue;) + CGAL_postcondition_code( Cell_handle ch = fit->first; Cell_handle nh = fit->first->neighbor(fit->second); ) + CGAL_postcondition_code( if(ch->label() == nh->label()) continue;) CGAL_postcondition_code( Facet f = *fit;) - CGAL_postcondition_code( if(!fit->first->is_outside()) f = m_tr.mirror_facet(f);) + CGAL_postcondition_code( if(ch->is_inside()) f = m_tr.mirror_facet(f);) CGAL_postcondition( facet_status(f) == IRRELEVANT); CGAL_postcondition_code(}) @@ -1481,7 +1512,7 @@ class Alpha_wrap_3 if(ic->is_outside()) outside_start = ic; else if(inside_start == Cell_handle()) - inside_start = ic; + inside_start = ic; // can be INSIDE or MANIFOLD } // fully inside / outside @@ -1513,8 +1544,10 @@ class Alpha_wrap_3 CGAL_assertion(neigh_c->has_vertex(v)); if(neigh_c->tds_data().processed() || - neigh_c->is_outside() != curr_c->is_outside()) // do not cross the boundary + is_on_outside_boundary(neigh_c, curr_c)) // do not cross the boundary + { continue; + } cells_to_visit.push(neigh_c); } @@ -1640,9 +1673,9 @@ class Alpha_wrap_3 return false; }; - auto is_on_boundary = [](Cell_handle c, int i) -> bool + auto is_on_boundary = [&](Cell_handle c, int i) -> bool { - return (c->is_outside() != c->neighbor(i)->is_outside()); + return is_on_outside_boundary(c, c->neighbor(i)); }; auto count_boundary_facets = [&](Cell_handle c, Vertex_handle v) -> int @@ -1736,7 +1769,7 @@ class Alpha_wrap_3 CGAL_assertion(!m_tr.is_infinite(ic)); // This is where new material is added - ic->is_outside() = false; + ic->label() = Cell_label::MANIFOLD; #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP static int i = 0; @@ -1829,7 +1862,7 @@ class Alpha_wrap_3 int s = fit->second; Cell_handle nh = ch->neighbor(s); - if(only_boundary_faces && (ch->is_outside() == nh->is_outside())) + if(only_boundary_faces && ch->label() == nh->label()) continue; std::array ids; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h index b586d495f0d3..f5636b798795 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h @@ -20,6 +20,16 @@ namespace CGAL { namespace Alpha_wraps_3 { namespace internal { +enum class Cell_label +{ + // Cells that have been carved + OUTSIDE, + // Cells that have not yet been carved + INSIDE, + // OUTSIDE cells that have been labeled "inside" again as to make the result manifold + MANIFOLD +}; + template < typename GT, typename Cb = CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3 > class Alpha_wrap_triangulation_cell_base_3 @@ -29,6 +39,7 @@ class Alpha_wrap_triangulation_cell_base_3 typedef typename Cb::Vertex_handle Vertex_handle; typedef typename Cb::Cell_handle Cell_handle; +public: template < typename TDS2 > struct Rebind_TDS { @@ -37,7 +48,7 @@ class Alpha_wrap_triangulation_cell_base_3 }; private: - bool outside = false; + Cell_label m_label = Cell_label::INSIDE; #ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE unsigned int m_erase_counter; @@ -61,8 +72,10 @@ class Alpha_wrap_triangulation_cell_base_3 {} public: - bool is_outside() const { return outside; } - bool& is_outside() { return outside; } + Cell_label label() const { return m_label; } + Cell_label& label() { return m_label; } + bool is_inside() const { return m_label == Cell_label::INSIDE; } + bool is_outside() const { return m_label == Cell_label::OUTSIDE; } #ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE unsigned int erase_counter() const From 49f26abd65fae1e9248bdbc7d22c91eb2c6137c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 10 Oct 2023 13:15:01 +0200 Subject: [PATCH 042/133] enum > enum class --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index f22fbfaa1f31..a6244eef2edd 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1098,7 +1098,7 @@ class Alpha_wrap_3 private: // A permissive gate is a gate that we can traverse without checking its circumradius - enum Facet_queue_status + enum class Facet_status { IRRELEVANT = 0, HAS_INFINITE_NEIGHBOR, // the cell incident to the mirrored facet is infinite (permissive) @@ -1106,7 +1106,7 @@ class Alpha_wrap_3 TRAVERSABLE }; - inline const char* get_status_message(const Facet_queue_status status) + inline const char* get_status_message(const Facet_status status) { constexpr std::size_t status_count = 4; @@ -1127,7 +1127,7 @@ class Alpha_wrap_3 public: // @speed some decent time may be spent constructing Facet (pairs) for no reason as it's always // just to grab the .first and .second as soon as it's constructed, and not due to API requirements - Facet_queue_status facet_status(const Facet& f) const + Facet_status facet_status(const Facet& f) const { CGAL_precondition(!m_tr.is_infinite(f)); @@ -1148,21 +1148,21 @@ class Alpha_wrap_3 #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "Facet is inside" << std::endl; #endif - return IRRELEVANT; + return Facet_status::IRRELEVANT; } const Cell_handle nh = ch->neighbor(id); CGAL_precondition(ch->label() == Cell_label::INSIDE || ch->label() == Cell_label::OUTSIDE); if(m_tr.is_infinite(nh)) - return HAS_INFINITE_NEIGHBOR; + return Facet_status::HAS_INFINITE_NEIGHBOR; if(nh->is_outside()) { #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "Neighbor already outside" << std::endl; #endif - return IRRELEVANT; + return Facet_status::IRRELEVANT; } // push if facet is connected to scaffolding vertices @@ -1175,7 +1175,7 @@ class Alpha_wrap_3 #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "Scaffolding facet due to vertex #" << i << std::endl; #endif - return SCAFFOLDING; + return Facet_status::SCAFFOLDING; } } @@ -1185,13 +1185,13 @@ class Alpha_wrap_3 #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "traversable" << std::endl; #endif - return TRAVERSABLE; + return Facet_status::TRAVERSABLE; } #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "not traversable" << std::endl; #endif - return IRRELEVANT; + return Facet_status::IRRELEVANT; } private: @@ -1205,13 +1205,14 @@ class Alpha_wrap_3 return false; #endif - const Facet_queue_status status = facet_status(f); - if(status == IRRELEVANT) + const Facet_status status = facet_status(f); + if(status == Facet_status::IRRELEVANT) return false; #ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE const FT sqr = smallest_squared_radius_3(f, m_tr); - const bool is_permissive = (status == HAS_INFINITE_NEIGHBOR || status == SCAFFOLDING); + const bool is_permissive = (status == Facet_status::HAS_INFINITE_NEIGHBOR || + status == Facet_status::SCAFFOLDING); m_queue.resize_and_push(Gate(f, sqr, is_permissive)); #else m_queue.push(Gate(f, m_tr)); @@ -1481,7 +1482,7 @@ class Alpha_wrap_3 CGAL_postcondition_code( if(ch->label() == nh->label()) continue;) CGAL_postcondition_code( Facet f = *fit;) CGAL_postcondition_code( if(ch->is_inside()) f = m_tr.mirror_facet(f);) - CGAL_postcondition( facet_status(f) == IRRELEVANT); + CGAL_postcondition( facet_status(f) == Facet_status::IRRELEVANT); CGAL_postcondition_code(}) return true; From 67e1b32c21d6c98320af26e2319fa09d94ac1539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 10 Oct 2023 13:22:20 +0200 Subject: [PATCH 043/133] Do not recompute the queue when resuming --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index a6244eef2edd..beb2bc7708cf 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -281,18 +281,16 @@ class Alpha_wrap_3 const bool do_enforce_manifoldness = choose_parameter(get_parameter(in_np, internal_np::do_enforce_manifoldness), true); // This parameter enables avoiding recomputing the triangulation from scratch when wrapping - // the same meshes for multiple values of alpha (and typically the same offset values). - // + // the same input for multiple values of alpha (and typically the same offset values). // /!\ Warning /!\ // - // If this is enabled, the 3D triangulation will NEVER be cleared and re-initialized - // at launch. This means that the triangulation is NOT cleared, even when: - // - the triangulation is empty; you will get nothing. + // If this is enabled, the 3D triangulation will NOT be re-initialized + // at launch. This means that the triangulation is NOT cleared, even if: // - you use an alpha value that is greater than what was used in a previous run; you will - // obtain a denser result than what you might expect. + // obtain the same result as the last run. // - you use a different offset value between runs, you might then get points that are not - // on the offset surface corresponding to your latter offset value. - const bool resuming = choose_parameter(get_parameter(in_np, internal_np::refine_triangulation), false); + // on the offset surface corresponding to that corresponding to the latter offset value. + const bool refining = choose_parameter(get_parameter(in_np, internal_np::refine_triangulation), false); #ifdef CGAL_AW3_TIMER CGAL::Real_timer t; @@ -301,7 +299,7 @@ class Alpha_wrap_3 visitor.on_alpha_wrapping_begin(*this); - if(!initialize(alpha, offset, seeds, resuming)) + if(!initialize(alpha, offset, seeds, refining)) return; #ifdef CGAL_AW3_TIMER @@ -368,13 +366,14 @@ class Alpha_wrap_3 if(ratio > 1.1) // more than 10% extra volume std::cerr << "Warning: large increase of volume after manifoldness resolution" << std::endl; } -#endif - } // do_enforce_manifoldness -#ifdef CGAL_AW3_TIMER - t.reset(); - t.start(); + std::size_t nm_cells_counter = 0; + for(Cell_handle ch : m_tr.all_cell_handles()) + if(ch->label() == Cell_label::MANIFOLD) + ++nm_cells_counter; + std::cout << "Number of added cells: " << nm_cells_counter << std::endl; #endif + } extract_surface(output_mesh, ovpm, !do_enforce_manifoldness); @@ -1246,12 +1245,19 @@ class Alpha_wrap_3 bool initialize(const double alpha, const double offset, const SeedRange& seeds, - const bool resuming = false) + const bool refining) { #ifdef CGAL_AW3_DEBUG std::cout << "> Initialize..." << std::endl; - std::cout << "Alpha: " << alpha << std::endl; - std::cout << "Offset: " << offset << std::endl; +#endif + + const bool resuming = refining && (alpha == m_alpha) && (offset == m_offset); + +#ifdef CGAL_AW3_DEBUG + std::cout << "\tAlpha: " << alpha << std::endl; + std::cout << "\tOffset: " << offset << std::endl; + std::cout << "\tRefining? " << refining << std::endl; + std::cout << "\tResuming? " << resuming << std::endl; #endif if(!is_positive(alpha) || !is_positive(offset)) @@ -1262,31 +1268,44 @@ class Alpha_wrap_3 return false; } - if(resuming && alpha > m_alpha) - std::cerr << "Warning: resuming with an alpha greater than last iteration!" << std::endl; - - if(resuming && offset != m_offset) - std::cerr << "Warning: resuming with a different offset!" << std::endl; + if(refining && alpha > m_alpha) + std::cerr << "Warning: refining with an alpha greater than the last iteration's!" << std::endl; + if(refining && offset != m_offset) + std::cerr << "Warning: refining with a different offset value!" << std::endl; m_alpha = FT(alpha); m_sq_alpha = square(m_alpha); m_offset = FT(offset); m_sq_offset = square(m_offset); + // Resuming means that we do not need to re-initialize the queue: either we have finished + // and there is nothing to do, or the interruption was due to a user callback in the visitor, + // and we can resume with the current queue + if(resuming) + { + reset_manifold_labels(); + return true; + } + #ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE m_queue.clear(); #else m_queue = { }; #endif - if(resuming) + if(refining) { + // If we are re-using the triangulation, change the label of the extra elements + // that we have added to ensure a manifold result back to external (MANIFOLD -> OUTSIDE) + reset_manifold_labels(); + return initialize_from_existing_triangulation(); } else { m_tr.clear(); + insert_bbox_corners(); if(seeds.empty()) From c19799aa59ae4e1cab686b5b00b9a245c9cb8e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 10 Oct 2023 13:23:05 +0200 Subject: [PATCH 044/133] Move "go_further()" check up So it doesn't purge zombies or print gate info that would not be refined --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index beb2bc7708cf..d61ca129ae21 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1327,6 +1327,9 @@ class Alpha_wrap_3 // Explore all finite cells that are reachable from one of the initial outside cells. while(!m_queue.empty()) { + if(!visitor.go_further(*this)) + return false; + #ifdef CGAL_AW3_DEBUG_QUEUE_PP check_queue_sanity(); #endif @@ -1379,9 +1382,6 @@ class Alpha_wrap_3 face_out.close(); #endif - if(!visitor.go_further(*this)) - return false; - visitor.before_facet_treatment(*this, gate); m_queue.pop(); From e03116953432a8b0376060ce0ea189926f87155b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 11 Oct 2023 16:50:48 +0200 Subject: [PATCH 045/133] Fix merge issue --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index c851ef559bcf..646ec7951e87 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1765,7 +1765,7 @@ class Alpha_wrap_3 // one would need to sort again after each modification of is_outside() statuses. auto comparer = [&](Cell_handle l, Cell_handle r) -> bool { - CGAL_precondition(!m_dt.is_infinite(l) && !m_dt.is_infinite(r)); + CGAL_precondition(!m_tr.is_infinite(l) && !m_tr.is_infinite(r)); if(has_scaffolding_vertex(l) != has_scaffolding_vertex(r)) return has_scaffolding_vertex(r); From 1066a9622f8595982b26475d0d75427f583af193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 11 Oct 2023 16:51:09 +0200 Subject: [PATCH 046/133] Only flag outside cells during manifold enforcement Otherwise, it creates holes if we reset manifold flags... --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 646ec7951e87..4543277de725 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1777,15 +1777,19 @@ class Alpha_wrap_3 inc_cells.reserve(64); m_tr.finite_incident_cells(v, std::back_inserter(inc_cells)); + std::vector finite_outside_inc_cells; + finite_outside_inc_cells.reserve(64); + std::copy_if(inc_cells.begin(), inc_cells.end(), std::back_inserter(finite_outside_inc_cells), + [&](Cell_handle c) -> bool { return !m_tr.is_infinite(c) && c->is_outside(); }); + // 'std::stable_sort' to have determinism without having to write something like: // if(longest_edge(l) == longest_edge(r)) return ... // in the comparer. It's a small range, so the cost does not matter. - std::stable_sort(inc_cells.begin(), inc_cells.end(), comparer); + std::stable_sort(finite_outside_inc_cells.begin(), finite_outside_inc_cells.end(), comparer); - for(auto cit=inc_cells.begin(), cend=inc_cells.end(); cit!=cend; ++cit) + for(Cell_handle ic : finite_outside_inc_cells) { - Cell_handle ic = *cit; - CGAL_assertion(!m_tr.is_infinite(ic)); + CGAL_assertion(!m_tr.is_infinite(ic) && ic->is_outside()); // This is where new material is added ic->label() = Cell_label::MANIFOLD; From 318258963fd8dd71179aedd8ad9d3c7a403d1c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 13 Oct 2023 10:53:11 +0200 Subject: [PATCH 047/133] Add a generic, empty collect_garbage(Graph) --- BGL/include/CGAL/boost/graph/helpers.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 76135fd82a7c..43016f9889fb 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -953,6 +953,11 @@ void swap_edges(const typename boost::graph_traits::halfedge_descript if (fo2 != nf && halfedge(fo2, g)==oh2) set_halfedge(fo2, oh1, g); } +template +void collect_garbage(Graph&) +{ + // nothing by default +} } //end of internal namespace From 205fcff14156cb097c1c515e49c81cf53883eb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 13 Oct 2023 10:53:56 +0200 Subject: [PATCH 048/133] Make seeds a member of the wrapper --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 4543277de725..c781319c07e5 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -167,6 +167,8 @@ class Alpha_wrap_3 using SC_Iso_cuboid_3 = SC::Iso_cuboid_3; using SC2GT = Cartesian_converter; + using Seeds = std::vector; + protected: Oracle m_oracle; SC_Iso_cuboid_3 m_bbox; @@ -174,6 +176,8 @@ class Alpha_wrap_3 FT m_alpha = FT(-1), m_sq_alpha = FT(-1); FT m_offset = FT(-1), m_sq_offset = FT(-1); + Seeds m_seeds; + Triangulation m_tr; Alpha_PQ m_queue; @@ -267,13 +271,7 @@ class Alpha_wrap_3 Visitor visitor = choose_parameter(get_parameter_reference(in_np, internal_np::visitor), default_visitor); // - using Seeds = typename internal_np::Lookup_named_param_def< - internal_np::seed_points_t, - InputNamedParameters, - std::vector >::reference; - - std::vector no_seeds; - Seeds seeds = choose_parameter(get_parameter_reference(in_np, internal_np::seed_points), no_seeds); + m_seeds = choose_parameter(get_parameter_reference(in_np, internal_np::seed_points), Seeds()); // Whether or not some cells should be reflagged as "inside" after the refinement+carving loop // as ended, as to ensure that the result is not only combinatorially manifold, but also @@ -299,7 +297,7 @@ class Alpha_wrap_3 visitor.on_alpha_wrapping_begin(*this); - if(!initialize(alpha, offset, seeds, refining)) + if(!initialize(alpha, offset, refining)) return; #ifdef CGAL_AW3_TIMER @@ -530,15 +528,14 @@ class Alpha_wrap_3 // // Another way is to simply make faces incident to the seed always traversable, and then // we only have to ensure faces opposite of the seed are traversable (i.e., radius ~= 1.65 * alpha) - template - bool initialize_with_cavities(const SeedRange& seeds) + bool initialize_with_cavities() { #ifdef CGAL_AW3_DEBUG_INITIALIZATION std::cout << "> Dig cavities" << std::endl; - std::cout << seeds.size() << " seed(s)" << std::endl; + std::cout << m_seeds.size() << " seed(s)" << std::endl; #endif - CGAL_precondition(!seeds.empty()); + CGAL_precondition(!m_seeds.empty()); // Get a double value approximating the scaling factors // std::cout << sqrt(3) * sin(2pi / 5) << std::endl; @@ -547,7 +544,7 @@ class Alpha_wrap_3 Iso_cuboid_3 bbox = SC2GT()(m_bbox); std::vector seed_vs; - for(const Point_3& seed_p : seeds) + for(const Point_3& seed_p : m_seeds) { #ifdef CGAL_AW3_DEBUG_INITIALIZATION std::cout << "Initialize from seed " << seed_p << std::endl; @@ -1241,10 +1238,8 @@ class Alpha_wrap_3 } private: - template bool initialize(const double alpha, const double offset, - const SeedRange& seeds, const bool refining) { #ifdef CGAL_AW3_DEBUG @@ -1308,10 +1303,10 @@ class Alpha_wrap_3 insert_bbox_corners(); - if(seeds.empty()) + if(m_seeds.empty()) return initialize_from_infinity(); else - return initialize_with_cavities(seeds); + return initialize_with_cavities(); } } From 91c679234bef76e6c3bcbbd7e9224a5456fcecbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 13 Oct 2023 10:56:58 +0200 Subject: [PATCH 049/133] Rename the builder class --- .../benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp | 2 +- Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp | 2 +- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 6 +++--- Alpha_wrap_3/include/CGAL/alpha_wrap_3.h | 6 +++--- .../test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp | 4 ++-- Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp | 2 +- .../Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp index 4565cca641a1..f8e54c488a49 100644 --- a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Quality/quality_benchmark.cpp @@ -21,7 +21,7 @@ using Mesh = CGAL::Surface_mesh; using face_descriptor = boost::graph_traits::face_descriptor; using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle; -using Dt = CGAL::Alpha_wraps_3::internal::Alpha_wrap_3::Triangulation; +using Dt = CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3::Triangulation; namespace PMP = CGAL::Polygon_mesh_processing; diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp index fdba4de5f514..90b488e0407c 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp @@ -103,7 +103,7 @@ int main(int argc, char** argv) oracle.add_segment_soup(segments, CGAL::parameters::default_values()); oracle.add_point_set(ps_points, CGAL::parameters::default_values()); - CGAL::Alpha_wraps_3::internal::Alpha_wrap_3 aw3(oracle); + CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3 aw3(oracle); Mesh wrap; aw3(alpha, offset, wrap); diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp index f9b35f88b1f7..f8533fb9cda9 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp @@ -110,7 +110,7 @@ int main(int argc, char** argv) t.reset(); using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle; - using Wrapper = CGAL::Alpha_wraps_3::internal::Alpha_wrap_3; + using Wrapper = CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3; Wrapper wrapper; // contains the triangulation that is being refined iteratively for(std::size_t i=0; i aw3(oracle); + CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3 aw3(oracle); Mesh wrap; aw3(alpha, offset, wrap); diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index c781319c07e5..1f7a9fdcbebb 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -115,7 +115,7 @@ struct Wrapping_default_visitor template -class Alpha_wrap_3 +class Alpha_wrapper_3 { using Oracle = Oracle_; @@ -183,7 +183,7 @@ class Alpha_wrap_3 Alpha_PQ m_queue; public: - Alpha_wrap_3() + Alpha_wrapper_3() #ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE // '4096' is an arbitrary, not-too-small value for the largest ID in queue initialization : m_queue(4096) @@ -194,7 +194,7 @@ class Alpha_wrap_3 static_assert(std::is_floating_point::value); } - Alpha_wrap_3(const Oracle& oracle) + Alpha_wrapper_3(const Oracle& oracle) : #ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE m_queue(4096), diff --git a/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h index 638c5fb9fa17..8be78675422e 100644 --- a/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h @@ -105,7 +105,7 @@ void alpha_wrap_3(const PointRange& points, using NP_helper = Point_set_processing_3_np_helper; using Geom_traits = typename NP_helper::Geom_traits; using Oracle = Alpha_wraps_3::internal::Triangle_soup_oracle; - using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3; + using AW3 = Alpha_wraps_3::internal::Alpha_wrapper_3; Geom_traits gt = choose_parameter(get_parameter(in_np, internal_np::geom_traits)); @@ -254,7 +254,7 @@ void alpha_wrap_3(const TriangleMesh& tmesh, using Geom_traits = typename GetGeomTraits::type; using Oracle = Alpha_wraps_3::internal::Triangle_mesh_oracle; - using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3; + using AW3 = Alpha_wraps_3::internal::Alpha_wrapper_3; Geom_traits gt = choose_parameter(get_parameter(in_np, internal_np::geom_traits)); @@ -350,7 +350,7 @@ void alpha_wrap_3(const PointRange& points, using NP_helper = Point_set_processing_3_np_helper; using Geom_traits = typename NP_helper::Geom_traits; using Oracle = Alpha_wraps_3::internal::Point_set_oracle; - using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3; + using AW3 = Alpha_wraps_3::internal::Alpha_wrapper_3; Geom_traits gt = choose_parameter(get_parameter(in_np, internal_np::geom_traits)); diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp index 847799522f2a..af94eecd25ae 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp @@ -28,7 +28,7 @@ void generate_random_seeds(const Oracle& oracle, Seeds& seeds, CGAL::Random& r) { - const auto bbox = CGAL::Alpha_wraps_3::internal::Alpha_wrap_3(oracle).construct_bbox(offset); + const auto bbox = CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3(oracle).construct_bbox(offset); const double sq_offset = CGAL::square(offset); while(seeds.size() < 3) @@ -70,7 +70,7 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh, Oracle oracle; oracle.add_triangle_mesh(input_mesh); - AW3::internal::Alpha_wrap_3 aw3(oracle); + AW3::internal::Alpha_wrapper_3 aw3(oracle); if(seeds.empty()) generate_random_seeds(oracle, offset, seeds, r); diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp index 739d131189cf..35a954f17b20 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp @@ -53,7 +53,7 @@ void alpha_wrap_triangle_soup(Points& pr, // AW3 Oracle oracle; oracle.add_triangle_soup(pr, fr); - AW3::internal::Alpha_wrap_3 aw3(oracle); + AW3::internal::Alpha_wrapper_3 aw3(oracle); Mesh wrap; aw3(alpha, offset, wrap, CGAL::parameters::do_enforce_manifoldness(false)); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index e66d6c83dd3f..0ff34cc54ec3 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -35,7 +35,7 @@ using TS_Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; using SS_Oracle = CGAL::Alpha_wraps_3::internal::Segment_soup_oracle; using Oracle = CGAL::Alpha_wraps_3::internal::Point_set_oracle; -using Wrapper = CGAL::Alpha_wraps_3::internal::Alpha_wrap_3; +using Wrapper = CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3; // Here is the pipeline for the interruption box: // - The main window is connected to a wrapping thread, which performs the wrapping. From 76aeec9805e66f163a1216f48bfca1b439ea0817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 13 Oct 2023 10:59:29 +0200 Subject: [PATCH 050/133] Replace try-catch with go_further() --- .../Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index 0ff34cc54ec3..f40130dedb12 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -40,8 +40,8 @@ using Wrapper = CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3; // Here is the pipeline for the interruption box: // - The main window is connected to a wrapping thread, which performs the wrapping. // - The wrapping has a visitor, AW3_interrupter_visitor, which has a shared_ptr to a Boolean -// - When the user clicks the box, the Boolean is switched to *false*, and the visitor throws -// - The wrapping thread catches the exception, and creates the wip mesh +// - When the user clicks the box, the Boolean is switched to *false* +// - The wrapping thread creates the wip mesh // Here is the pipeline for the iterative visualization: // - The main window is connected to a wrapping thread, which performs the wrapping. @@ -201,9 +201,6 @@ struct Iterative_AW3_visualization_visitor } }; -// Use a throw to get out of the AW3 refinement loop -class Out_of_patience_exception : public std::exception { }; - template struct AW3_interrupter_visitor : BaseVisitor @@ -215,15 +212,10 @@ struct AW3_interrupter_visitor : BaseVisitor(base) { } - // Only overload this one because it gives a better state of the wrap (for other visitor calls, - // we often get tetrahedral spikes because there are scaffolding gates in the queue) - template - void before_Steiner_point_insertion(const Wrapper& wrapper, const Point& p) + template + constexpr bool go_further(const Wrapper& wrapper) { - if(*should_stop) - throw Out_of_patience_exception(); - - return BaseVisitor::before_Steiner_point_insertion(wrapper, p); + return !(*should_stop); } }; @@ -273,25 +265,14 @@ struct Wrapper_thread QElapsedTimer elapsed_timer; elapsed_timer.start(); - // try-catch because the stop visitor currently uses a throw - try - { - wrapper(alpha, offset, wrap, - CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness) - .visitor(visitor)); + wrapper(alpha, offset, wrap, + CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness) + .visitor(visitor)); + if(wrapper.queue().empty()) Q_EMIT done(this); - } - catch(const Out_of_patience_exception&) - { - if(enforce_manifoldness) - wrapper.make_manifold(); - - // extract the wrap in its current state - wrapper.extract_surface(wrap, CGAL::get(CGAL::vertex_point, wrap), !enforce_manifoldness); - + else Q_EMIT interrupted(this); - } std::cout << "Wrapping took " << elapsed_timer.elapsed() / 1000. << "s" << std::endl; } @@ -761,10 +742,6 @@ public Q_SLOTS: return; } - // Switch from 'wait' to 'busy' - QApplication::restoreOverrideCursor(); - QApplication::setOverrideCursor(Qt::BusyCursor); - Q_FOREACH(int index, this->scene->selectionIndices()) { Scene_surface_mesh_item* sm_item = qobject_cast(this->scene->item(index)); @@ -824,6 +801,10 @@ public Q_SLOTS: // Create message box with stop button if(use_message_box) { + // Switch from 'wait' to 'busy' + QApplication::restoreOverrideCursor(); + QApplication::setOverrideCursor(Qt::BusyCursor); + m_message_box = new QMessageBox(QMessageBox::NoIcon, "Wrapping", "Wrapping in progress...", @@ -841,6 +822,8 @@ public Q_SLOTS: } // Actual start + QApplication::setOverrideCursor(Qt::WaitCursor); + wrapper_thread->start(); CGAL::Three::Three::getMutex()->lock(); From 8f3cc5c86bc4367ad0975585f40c8a7c017b0d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 10:18:01 +0200 Subject: [PATCH 051/133] Simplify volume check in make_manifold() --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 1f7a9fdcbebb..a3976a7ab55c 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -324,53 +324,18 @@ class Alpha_wrapper_3 if(do_enforce_manifoldness) { -#ifdef CGAL_AW3_DEBUG - extract_surface(output_mesh, ovpm, true /*tolerate non manifoldness*/); - - #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP - dump_triangulation_faces("carved_tr.off", false /*only_boundary_faces*/); - IO::write_polygon_mesh("carved_wrap.off", output_mesh, - CGAL::parameters::vertex_point_map(ovpm).stream_precision(17)); - #endif + make_manifold(); - FT base_vol = 0; - if(is_closed(output_mesh)) // might not be due to manifoldness - base_vol = PMP::volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); - else - std::cerr << "Warning: couldn't compute volume before manifoldness fixes (mesh is not closed)" << std::endl; +#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + dump_triangulation_faces("manifold_wrap.off", true /*only_boundary_faces*/); #endif - make_manifold(); - #ifdef CGAL_AW3_TIMER t.stop(); std::cout << "Manifoldness post-processing took: " << t.time() << " s." << std::endl; t.reset(); t.start(); #endif - -#ifdef CGAL_AW3_DEBUG - if(!is_zero(base_vol)) - { - extract_surface(output_mesh, ovpm, false /*do not tolerate non-manifoldness*/); - - const FT manifold_vol = PMP::volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); - const FT ratio = manifold_vol / base_vol; - - std::cout << "Volumes post-manifoldness fix:\n" - << "before: " << base_vol << "\n" - << "after: " << manifold_vol << "\n" - << "ratio: " << ratio << std::endl; - if(ratio > 1.1) // more than 10% extra volume - std::cerr << "Warning: large increase of volume after manifoldness resolution" << std::endl; - } - - std::size_t nm_cells_counter = 0; - for(Cell_handle ch : m_tr.all_cell_handles()) - if(ch->label() == Cell_label::MANIFOLD) - ++nm_cells_counter; - std::cout << "Number of added cells: " << nm_cells_counter << std::endl; -#endif } extract_surface(output_mesh, ovpm, !do_enforce_manifoldness); @@ -1655,10 +1620,26 @@ class Alpha_wrapper_3 // Not the best complexity, but it's very cheap compared to the rest of the algorithm. void make_manifold() { - namespace PMP = Polygon_mesh_processing; - #ifdef CGAL_AW3_DEBUG std::cout << "> Make manifold..." << std::endl; + + auto wrap_volume = [&]() + { + FT vol = 0; + for(Cell_handle ch : m_tr.all_cell_handles()) + if(!ch->is_outside()) + vol += volume(m_tr.point(ch, 0), m_tr.point(ch, 1), m_tr.point(ch, 2), m_tr.point(ch, 3)); + + return vol; + }; + + #ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + dump_triangulation_faces("carved_tr.off", true /*only_boundary_faces*/); + #endif + + FT base_vol = wrap_volume(); + if(!is_positive(base_vol)) + std::cerr << "Warning: empty wrap?" << std::endl; #endif // This seems more harmful than useful after the priority queue has been introduced since @@ -1813,6 +1794,27 @@ class Alpha_wrapper_3 CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) CGAL_assertion(!is_non_manifold(v)); + +#ifdef CGAL_AW3_DEBUG + std::size_t nm_cells_counter = 0; + for(Cell_handle ch : m_tr.all_cell_handles()) + if(ch->label() == Cell_label::MANIFOLD) + ++nm_cells_counter; + std::cout << "Number of added cells: " << nm_cells_counter << std::endl; + + if(!is_zero(base_vol)) + { + const FT manifold_vol = wrap_volume(); + const FT ratio = manifold_vol / base_vol; + + std::cout << "Volumes post-manifoldness fix:\n" + << "before: " << base_vol << "\n" + << "after: " << manifold_vol << "\n" + << "ratio: " << ratio << std::endl; + if(ratio > 1.1) // more than 10% extra volume + std::cerr << "Warning: large increase of volume after manifoldness resolution" << std::endl; + } +#endif } private: From f43c4ec58abeb6d05afc642bc53684ed3669381a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 11:05:48 +0200 Subject: [PATCH 052/133] Minor example fix --- Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp index 9422e4d969be..970bb583484f 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp @@ -33,7 +33,7 @@ int main(int argc, char** argv) std::cout << "Input: " << num_vertices(input) << " vertices, " << num_faces(input) << " faces" << std::endl; - const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : 30.; + const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : 40.; const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 600.; // Compute the alpha and offset values @@ -66,7 +66,11 @@ int main(int argc, char** argv) std::cout << "Took " << t.time() << " s." << std::endl; // Save the result - const std::string output_name = generate_output_name(filename, relative_alpha, relative_offset); + std::string input_name = std::string(filename); + input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); + input_name = input_name.substr(0, input_name.find_last_of(".")); + std::string output_name = input_name + "_cavity_" + std::to_string(static_cast(relative_alpha)) + + "_" + std::to_string(static_cast(relative_offset)) + ".off"; std::cout << "Writing to " << output_name << std::endl; CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); From da6b202869a0a80b3f312d92e51d3b07e712b7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 11:06:11 +0200 Subject: [PATCH 053/133] Add a function to purge inner (useless) CCs --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 102 ++++++++++++++++-- 1 file changed, 96 insertions(+), 6 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index a3976a7ab55c..a1f82e6e3bd4 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -307,14 +307,22 @@ class Alpha_wrapper_3 t.start(); #endif -#ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP - extract_surface(output_mesh, ovpm, true /*tolerate non manifoldness*/); - CGAL::IO::write_polygon_mesh("starting_wrap.off", output_mesh, - CGAL::parameters::vertex_point_map(ovpm).stream_precision(17)); +#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + dump_triangulation_faces("starting_wrap.off", true /*only_boundary_faces*/); #endif alpha_flood_fill(visitor); +#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + dump_triangulation_faces("flood_filled_wrap.off", true /*only_boundary_faces*/); +#endif + + purge_inner_islands(); + +#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + dump_triangulation_faces("purged_wrap.off", true /*only_boundary_faces*/); +#endif + #ifdef CGAL_AW3_TIMER t.stop(); std::cout << "Flood filling took: " << t.time() << " s." << std::endl; @@ -330,6 +338,12 @@ class Alpha_wrapper_3 dump_triangulation_faces("manifold_wrap.off", true /*only_boundary_faces*/); #endif + purge_inner_islands(); + +#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + dump_triangulation_faces("purged_manifold_wrap.off", true /*only_boundary_faces*/); +#endif + #ifdef CGAL_AW3_TIMER t.stop(); std::cout << "Manifoldness post-processing took: " << t.time() << " s." << std::endl; @@ -349,8 +363,8 @@ class Alpha_wrapper_3 std::cout << "Alpha wrap vertices: " << vertices(output_mesh).size() << std::endl; std::cout << "Alpha wrap faces: " << faces(output_mesh).size() << std::endl; - #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP - IO::write_polygon_mesh("final.off", output_mesh, CGAL::parameters::stream_precision(17)); + #ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + IO::write_polygon_mesh("final_wrap.off", output_mesh, CGAL::parameters::stream_precision(17)); dump_triangulation_faces("final_tr.off", false /*only_boundary_faces*/); #endif #endif @@ -1467,6 +1481,82 @@ class Alpha_wrapper_3 return true; } + // Any outside cell that isn't reachable from infinity is a cavity that can + // be discarded. This also removes some difficult non-manifoldness onfigurations + std::size_t purge_inner_islands() + { +#ifdef CGAL_AW3_DEBUG + std::cout << "> Purge inner islands..." << std::endl; +#endif + + std::size_t label_change_counter = 0; + + std::stack cells_to_visit; + + if(!m_seeds.empty()) + { + for(const Point_3& seed : m_seeds) + { + Locate_type lt; + int li, lj; + Cell_handle ch = m_tr.locate(seed, lt, li, lj); + + if(!ch->is_outside()) + { + std::cerr << "Warning: cell containing seed is not outside?!" << std::endl; + continue; + } + + cells_to_visit.push(ch); + } + } + else // typical flooding from outside + { + std::stack cells_to_visit; + cells_to_visit.push(m_tr.infinite_vertex()->cell()); + } + + while(!cells_to_visit.empty()) + { + Cell_handle curr_c = cells_to_visit.top(); + cells_to_visit.pop(); + + CGAL_assertion(curr_c->is_outside()); + + if(curr_c->tds_data().processed()) + continue; + curr_c->tds_data().mark_processed(); + + for(int j=0; j<4; ++j) + { + Cell_handle neigh_c = curr_c->neighbor(j); + if(neigh_c->tds_data().processed() || !neigh_c->is_outside()) + continue; + + cells_to_visit.push(neigh_c); + } + } + + for(Cell_handle ch : m_tr.all_cell_handles()) + { + if(ch->tds_data().is_clear() && ch->is_outside()) + { + ch->label() = Cell_label::INSIDE; + ++label_change_counter; + } + } + + // reset the conflict flags + for(Cell_handle ch : m_tr.all_cell_handles()) + ch->tds_data().clear(); + +#ifdef CGAL_AW3_DEBUG + std::cout << label_change_counter << " label changes" << std::endl; +#endif + + return label_change_counter; + } + private: bool is_non_manifold(Vertex_handle v) const { From c19975bef7190e6b6940a7faf89dfcad6bdc17f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 11:06:36 +0200 Subject: [PATCH 054/133] Revert to the previous non-manifold extraction code Neither are able to produce a closed, combinatorial manifold surface 100% of the time, so minimize the diff. --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 270 ++++++------------ 1 file changed, 87 insertions(+), 183 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index a1f82e6e3bd4..8192dd063d36 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -708,6 +708,91 @@ class Alpha_wrapper_3 } private: + // Manifoldness is tolerated while debugging and extracting at intermediate states + // Not the preferred way because it uses 3*nv storage + template + void extract_possibly_non_manifold_surface(OutputMesh& output_mesh, + OVPM ovpm) const + { + namespace PMP = Polygon_mesh_processing; + +#ifdef CGAL_AW3_DEBUG + std::cout << "> Extract possibly non-manifold wrap... ()" << std::endl; +#endif + + clear(output_mesh); + + CGAL_assertion_code(for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit)) + CGAL_assertion(cit->tds_data().is_clear()); + + for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit) + { + Cell_handle seed = cit; + if(seed->is_outside() || seed->tds_data().processed()) + continue; + + std::queue to_visit; + to_visit.push(seed); + + std::vector points; + std::vector > faces; + std::size_t idx = 0; + + while(!to_visit.empty()) + { + const Cell_handle cell = to_visit.front(); + CGAL_assertion(!cell->is_outside() && !m_tr.is_infinite(cell)); + + to_visit.pop(); + + if(cell->tds_data().processed()) + continue; + + cell->tds_data().mark_processed(); + + for(int fid=0; fid<4; ++fid) + { + const Cell_handle neighbor = cell->neighbor(fid); + if(neighbor->is_outside()) + { + // There shouldn't be any artificial vertex on the inside/outside boundary + // (past initialization) +// CGAL_assertion(cell->vertex((fid + 1)&3)->type() == AW3i::Vertex_type:: DEFAULT); +// CGAL_assertion(cell->vertex((fid + 2)&3)->type() == AW3i::Vertex_type:: DEFAULT); +// CGAL_assertion(cell->vertex((fid + 3)&3)->type() == AW3i::Vertex_type:: DEFAULT); + + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 0))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 1))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 2))); + faces.push_back({idx, idx + 1, idx + 2}); + idx += 3; + } + else + { + to_visit.push(neighbor); + } + } + } + + CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(faces)); + PMP::polygon_soup_to_polygon_mesh(points, faces, output_mesh, + CGAL::parameters::default_values(), + CGAL::parameters::vertex_point_map(ovpm)); + + PMP::stitch_borders(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); + CGAL_assertion(is_closed(output_mesh)); + } + + for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit) + cit->tds_data().clear(); + + CGAL_postcondition(!is_empty(output_mesh)); + CGAL_postcondition(is_valid_polygon_mesh(output_mesh)); + CGAL_postcondition(is_closed(output_mesh)); + + PMP::orient_to_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); + } + template void extract_manifold_surface(OutputMesh& output_mesh, OVPM ovpm) const @@ -781,189 +866,8 @@ class Alpha_wrapper_3 CGAL_postcondition(is_valid_polygon_mesh(output_mesh)); CGAL_postcondition(is_closed(output_mesh)); CGAL_postcondition(PMP::does_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm))); - } - - template - void extract_inside_boundary(OutputMesh& output_mesh, - OVPM ovpm) const - { - namespace PMP = Polygon_mesh_processing; - - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; - using face_descriptor = typename boost::graph_traits::face_descriptor; - -#ifdef CGAL_AW3_DEBUG - std::cout << "> Extract possibly non-manifold wrap... ()" << std::endl; -#endif - - clear(output_mesh); - - std::vector points; - std::vector > polygons; - - // Explode the polygon soup into indepent triangles, and stitch it back - // edge by edge by walking along the exterior - std::map facet_ids; - std::size_t idx = 0; - - // Looks identical to the block in extract_manifold_surface(), but there are - // two significant differences: - // - Boundary considers MANIFOLD outside here - // - There is no attempt to re-use the same vertex in multiple faces - for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) - { - Facet f = *fit; - if(f.first->is_inside()) // need f.first to be OUTSIDE or MANIFOLD - f = m_tr.mirror_facet(f); - - const Cell_handle ch = f.first; - const int s = f.second; - const Cell_handle nh = ch->neighbor(s); - if(!is_on_inside_boundary(ch, nh)) // MANIFOLD here is outside - continue; - facet_ids[f] = idx / 3; - - points.push_back(m_tr.point(ch, Triangulation::vertex_triple_index(s, 0))); - points.push_back(m_tr.point(ch, Triangulation::vertex_triple_index(s, 1))); - points.push_back(m_tr.point(ch, Triangulation::vertex_triple_index(s, 2))); - polygons.push_back({idx, idx + 1, idx + 2}); - - idx += 3; - } - -#ifdef CGAL_AW3_DEBUG - std::cout << "\t" << points.size() << " points" << std::endl; - std::cout << "\t" << polygons.size() << " polygons" << std::endl; -#endif - - if(polygons.empty()) - { -#ifdef CGAL_AW3_DEBUG - std::cerr << "Warning: empty wrap?..." << std::endl; -#endif - return; - } - - CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(polygons)); - - std::unordered_map i2f; - PMP::polygon_soup_to_polygon_mesh(points, polygons, output_mesh, - CGAL::parameters::polygon_to_face_output_iterator(std::inserter(i2f, i2f.end())), - CGAL::parameters::vertex_point_map(ovpm)); - - auto face_to_facet = get(CGAL::dynamic_face_property_t(), output_mesh); - - idx = 0; - for(auto fit=m_tr.all_facets_begin(), fend=m_tr.all_facets_end(); fit!=fend; ++fit) - { - Facet f = *fit; - if(f.first->is_inside()) // f.first must be MANIFOLD or OUTSIDE - f = m_tr.mirror_facet(f); - - const Cell_handle ch = f.first; - const int s = f.second; - const Cell_handle nh = ch->neighbor(s); - if(!is_on_inside_boundary(ch, nh)) // MANIFOLD here is outside - continue; - - put(face_to_facet, i2f[idx++], f); - } - - // grab the stitchable halfedges - std::vector > to_stitch; - - for(face_descriptor f : faces(output_mesh)) - { - const Facet& tr_f = get(face_to_facet, f); - const Cell_handle ch = tr_f.first; - CGAL_assertion(!ch->is_inside()); // OUTSIDE or MANIFOLD - - for(halfedge_descriptor h : halfedges_around_face(halfedge(f, output_mesh), output_mesh)) - { - const vertex_descriptor sv = source(h, output_mesh); - const vertex_descriptor tv = target(h, output_mesh); - - // only need the pair of halfedges once - if(get(ovpm, sv) > get(ovpm, tv)) - continue; - - // One could avoid these point comparisons by using the fact that we know that the graph - // has faces built in a specific order (through BGL::add_face()), but it's better to make - // this code more generic (and it is not very costly). - auto graph_descriptor_to_triangulation_handle = [&](const vertex_descriptor v) - { - const Point_3& p = get(ovpm, v); - for(int i=0; i<4; ++i) - if(ch->vertex(i)->point() == p) - return ch->vertex(i); - - CGAL_assertion(false); - return Vertex_handle(); - }; - - const Vertex_handle s_vh = graph_descriptor_to_triangulation_handle(sv); - const Vertex_handle t_vh = graph_descriptor_to_triangulation_handle(tv); - CGAL_assertion(get(ovpm, sv) == m_tr.point(s_vh)); - CGAL_assertion(get(ovpm, tv) == m_tr.point(t_vh)); - - const int facet_third_id = 6 - (ch->index(s_vh) + ch->index(t_vh) + tr_f.second); // 0 + 1 + 2 + 3 = 6 - Vertex_handle third_vh = ch->vertex(facet_third_id); - - // walk around the edge (in the exterior of the wrap) till meeting an inside cell - Cell_handle start_ch = ch, curr_ch = ch; - do - { - const int i = curr_ch->index(s_vh); - const int j = curr_ch->index(t_vh); - - // the facet is incident to the outside cell, and we walk in the exterior - const int facet_third_id = 6 - (curr_ch->index(s_vh) + curr_ch->index(t_vh) + curr_ch->index(third_vh)); - third_vh = curr_ch->vertex(facet_third_id); - curr_ch = curr_ch->neighbor(Triangulation::next_around_edge(i,j)); - - if(curr_ch->is_inside()) - break; - } - while(curr_ch != start_ch); - - CGAL_assertion(curr_ch != start_ch); - CGAL_assertion(curr_ch->is_inside()); - - const int opp_id = 6 - (curr_ch->index(s_vh) + curr_ch->index(t_vh) + curr_ch->index(third_vh)); - const Facet tr_f2 = m_tr.mirror_facet(Facet(curr_ch, opp_id)); - CGAL_assertion(facet_ids.count(Facet(curr_ch, opp_id)) == 0); - CGAL_assertion(!tr_f2.first->is_inside()); - CGAL_assertion(tr_f2.first->neighbor(tr_f2.second) == curr_ch); - CGAL_assertion(tr_f2.first->has_vertex(s_vh) && tr_f2.first->has_vertex(t_vh)); - - const face_descriptor f2 = i2f[facet_ids.at(tr_f2)]; - halfedge_descriptor h2 = halfedge(f2, output_mesh), done = h2; - while(get(ovpm, target(h2, output_mesh)) != get(ovpm, source(h, output_mesh))) - { - h2 = next(h2, output_mesh); - CGAL_assertion(h2 != done); - if(h2 == done) - break; - } - - CGAL_assertion(get(ovpm, source(h, output_mesh)) == get(ovpm, target(h2, output_mesh))); - CGAL_assertion(get(ovpm, target(h, output_mesh)) == get(ovpm, source(h2, output_mesh))); - CGAL_assertion(get(ovpm, target(next(h2, output_mesh), output_mesh)) == m_tr.point(third_vh)); - - to_stitch.emplace_back(opposite(h, output_mesh), opposite(h2, output_mesh)); - } - } - - PMP::internal::stitch_halfedge_range(to_stitch, output_mesh, ovpm); - - collect_garbage(output_mesh); - - CGAL_postcondition(!is_empty(output_mesh)); - CGAL_postcondition(is_valid_polygon_mesh(output_mesh)); - CGAL_postcondition(is_closed(output_mesh)); - CGAL_postcondition(PMP::does_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm))); + PMP::orient_to_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); } public: @@ -973,7 +877,7 @@ class Alpha_wrapper_3 const bool tolerate_non_manifoldness = false) const { if(tolerate_non_manifoldness) - extract_inside_boundary(output_mesh, ovpm); + extract_possibly_non_manifold_surface(output_mesh, ovpm); else extract_manifold_surface(output_mesh, ovpm); } From 29846572e3fcd3eb7b59b19c7e78d07d879456b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 16:56:46 +0200 Subject: [PATCH 055/133] Increment erase counter for cells changing labels during flooding Makes it easier to detect faces that no longer need to be treated (zombies). --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 28 +++++++++++++------ .../Alpha_wrap_triangulation_cell_base_3.h | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 8192dd063d36..b4be5907d1cb 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -620,7 +620,7 @@ class Alpha_wrapper_3 m_tr.incident_cells(seed_v, std::back_inserter(inc_cells)); for(Cell_handle ch : inc_cells) - ch->label() = cavity_cell_label(ch); + ch->set_label(cavity_cell_label(ch)); } // Should be cheap enough to go through the full triangulation as only seeds have been inserted @@ -656,13 +656,13 @@ class Alpha_wrapper_3 { if(m_tr.is_infinite(ch)) { - ch->label() = Cell_label::OUTSIDE; + ch->set_label(Cell_label::OUTSIDE); const int inf_index = ch->index(m_tr.infinite_vertex()); push_facet(std::make_pair(ch, inf_index)); } else { - ch->label() = Cell_label::INSIDE; + ch->set_label(Cell_label::INSIDE); } } @@ -671,9 +671,10 @@ class Alpha_wrapper_3 void reset_manifold_labels() { + // No erase counter increment, or it will mess up with a possibly non-empty queue. for(Cell_handle ch : m_tr.all_cell_handles()) if(ch->label() == Cell_label::MANIFOLD) - ch->label() = Cell_label::OUTSIDE; + ch->set_label(Cell_label::OUTSIDE); } // This function is used in the case of resumption of a previous run: m_tr is not cleared, @@ -1266,7 +1267,10 @@ class Alpha_wrapper_3 if(m_tr.is_infinite(nh)) { - nh->label() = Cell_label::OUTSIDE; + nh->set_label(Cell_label::OUTSIDE); +#ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + nh->increment_erase_counter(); +#endif continue; } @@ -1330,7 +1334,7 @@ class Alpha_wrapper_3 for(const Cell_handle& new_ch : new_cells) { // std::cout << "new cell has time stamp " << new_ch->time_stamp() << std::endl; - new_ch->label() = m_tr.is_infinite(new_ch) ? Cell_label::OUTSIDE : Cell_label::INSIDE; + new_ch->set_label(m_tr.is_infinite(new_ch) ? Cell_label::OUTSIDE : Cell_label::INSIDE); } // Push all new boundary facets to the queue. @@ -1359,7 +1363,10 @@ class Alpha_wrapper_3 } else // no need for a Steiner point, carve through and continue { - nh->label() = Cell_label::OUTSIDE; + nh->set_label(Cell_label::OUTSIDE); +#ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + nh->increment_erase_counter(); +#endif // for each finite facet of neighbor, push it to the queue const int mi = m_tr.mirror_index(ch, s); @@ -1445,7 +1452,10 @@ class Alpha_wrapper_3 { if(ch->tds_data().is_clear() && ch->is_outside()) { - ch->label() = Cell_label::INSIDE; + ch->set_label(Cell_label::INSIDE); +#ifndef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + ch->increment_erase_counter(); +#endif ++label_change_counter; } } @@ -1762,7 +1772,7 @@ class Alpha_wrapper_3 CGAL_assertion(!m_tr.is_infinite(ic) && ic->is_outside()); // This is where new material is added - ic->label() = Cell_label::MANIFOLD; + ic->set_label(Cell_label::MANIFOLD); #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP static int i = 0; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h index f5636b798795..efaeb82d330f 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h @@ -73,7 +73,7 @@ class Alpha_wrap_triangulation_cell_base_3 public: Cell_label label() const { return m_label; } - Cell_label& label() { return m_label; } + void set_label(const Cell_label label) { m_label = label; } bool is_inside() const { return m_label == Cell_label::INSIDE; } bool is_outside() const { return m_label == Cell_label::OUTSIDE; } From 8f409f03ffc856393e7d6d0b2d04b4ee570fce96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 16:57:45 +0200 Subject: [PATCH 056/133] Avoid producing a mesh with garbage in the non-manifold case --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index b4be5907d1cb..a986e5c6a38a 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -792,6 +792,8 @@ class Alpha_wrapper_3 CGAL_postcondition(is_closed(output_mesh)); PMP::orient_to_bound_a_volume(output_mesh, CGAL::parameters::vertex_point_map(ovpm)); + + collect_garbage(output_mesh); } template From 00acf4f75203ea95dd628b8e65018b599b5f7d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 16:58:17 +0200 Subject: [PATCH 057/133] Fix compilation after change of Facet_status to strong enum --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index a986e5c6a38a..fc580aa561ce 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1000,10 +1000,11 @@ class Alpha_wrapper_3 "Traversable facet" }; - if(status > status_count || status < 0) + const std::size_t status_id = static_cast(status); + if(status_id > status_count || status_id < 0) return "Unknown status"; else - return message[status]; + return message[status_id]; } public: From 116bb2beb9a6fda4e055779fde54b9730a77bf43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 17:00:57 +0200 Subject: [PATCH 058/133] Fix shadowing variable --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index fc580aa561ce..675e6e303944 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1426,7 +1426,6 @@ class Alpha_wrapper_3 } else // typical flooding from outside { - std::stack cells_to_visit; cells_to_visit.push(m_tr.infinite_vertex()->cell()); } From 18154a758b5ad165d96b83ddb25717f4b093c7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 17:02:05 +0200 Subject: [PATCH 059/133] Loop only finite faces in the volume computation For outward wrapping --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 675e6e303944..31870dd01470 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1632,7 +1632,7 @@ class Alpha_wrapper_3 auto wrap_volume = [&]() { FT vol = 0; - for(Cell_handle ch : m_tr.all_cell_handles()) + for(Cell_handle ch : m_tr.finite_cell_handles()) if(!ch->is_outside()) vol += volume(m_tr.point(ch, 0), m_tr.point(ch, 1), m_tr.point(ch, 2), m_tr.point(ch, 3)); From b1ffdb00e1196675950864a2a21f90f49c35fbc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 17:04:00 +0200 Subject: [PATCH 060/133] Add an example of pausing and restarting a wrapping process --- .../examples/Alpha_wrap_3/CMakeLists.txt | 3 +- .../pause_and_resume_wrapping.cpp | 164 ++++++++++++++++++ 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt index 34674777b401..40187ca194cb 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt @@ -12,5 +12,6 @@ create_single_source_cgal_program("triangle_soup_wrap.cpp") create_single_source_cgal_program("point_set_wrap.cpp") create_single_source_cgal_program("wrap_from_cavity.cpp") create_single_source_cgal_program("mixed_inputs_wrap.cpp") -create_single_source_cgal_program("successive_wraps.cpp") create_single_source_cgal_program("volumetric_wrap.cpp") +create_single_source_cgal_program("successive_wraps.cpp") +create_single_source_cgal_program("pause_and_resume_wrapping.cpp") diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp new file mode 100644 index 000000000000..5663bce16847 --- /dev/null +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp @@ -0,0 +1,164 @@ +// This example demonstrates how to interrupt the wrapping process before it has terminated, +// and how to resume afterwards. +// +// -------------------------------- !! Warning !! -------------------------------------------------- +// By default, the wrap uses an unsorted LIFO queue of faces to refine. This means that +// the intermediate result is not very useful because the algorithm carves deep and not wide +// (somewhat like a DFS vs a BFS). +// +// The sorted queue option is enabled with the macro below to make the refinement algorithm +// more uniform. The downside is that it is slower. +// ------------------------------------------------------------------------------------------------- +#define CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + +#include "output_helper.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace AW3 = CGAL::Alpha_wraps_3; +namespace PMP = CGAL::Polygon_mesh_processing; + +using K = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = K::Point_3; + +using Points = std::vector; +using Polygon = std::array; +using Polygons = std::vector; + +using Mesh = CGAL::Surface_mesh; +using face_descriptor = boost::graph_traits::face_descriptor; + +struct Interrupter_visitor + : public AW3::internal::Wrapping_default_visitor +{ + using Base = AW3::internal::Wrapping_default_visitor; + + CGAL::Real_timer timer; + double max_time = -1; // in seconds + +public: + void set_max_time(double t) { max_time = t; } + +public: + template + void on_flood_fill_begin(const AlphaWrapper&) + { + std::cout << "Starting timer..." << std::endl; + timer.start(); + } + + template + bool go_further(const Wrapper&) + { + if(timer.time() > max_time) + { + timer.stop(); + std::cout << "Paused after " << timer.time() << " s." << std::endl; + return false; + } + + return true; + } +}; + +int main(int argc, char** argv) +{ + std::cout.precision(17); + std::cerr.precision(17); + + CGAL::Random rng; + std::cout << "Random seed = " << rng.get_seed() << std::endl; + + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/armadillo.off"); + + // = read the soup + Points points; + Polygons polygons; + if(!CGAL::IO::read_polygon_soup(filename, points, polygons) || polygons.empty()) + { + std::cerr << "Invalid soup input: " << filename << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Input: " << points.size() << " points, " << polygons.size() << " faces" << std::endl; + + // Compute the alpha and offset values + const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : rng.get_double(150., 200.); + const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 600.; + std::cout << "relative_alpha = " << relative_alpha << std::endl; + + CGAL::Bbox_3 bbox; + for(const Point_3& p : points) + bbox += p.bbox(); + + const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) + + CGAL::square(bbox.ymax() - bbox.ymin()) + + CGAL::square(bbox.zmax() - bbox.zmin())); + + const double alpha = diag_length / relative_alpha; + const double offset = diag_length / relative_offset; + + // Build the wrapper + using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; + Oracle oracle(alpha); + oracle.add_triangle_soup(points, polygons, CGAL::parameters::default_values()); + CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3 aw3(oracle); + + // --- Launch the wrapping, and pause when the algorithm has spent 1s flooding + Interrupter_visitor interrupter; + interrupter.set_max_time(1.); + + Mesh wrap; + aw3(alpha, offset, wrap, CGAL::parameters::visitor(interrupter)); + std::cout << ">>> The current wrap has " << num_vertices(wrap) << " vertices" << std::endl; + CGAL::IO::write_polygon_mesh("stopped_1.off", wrap, CGAL::parameters::stream_precision(17)); + + // --- Restart from the previous state, and pause a bit further + interrupter.set_max_time(2.); + aw3(alpha, offset, wrap, CGAL::parameters::visitor(interrupter) + .refine_triangulation(true)); + std::cout << ">>> The current wrap has " << num_vertices(wrap) << " vertices" << std::endl; + CGAL::IO::write_polygon_mesh("stopped_2.off", wrap, CGAL::parameters::stream_precision(17)); + + // --- Restart from the previous state, and let it finish + aw3(alpha, offset, wrap, CGAL::parameters::refine_triangulation(true)); + std::cout << ">>> The final (resumed) wrap has " << num_vertices(wrap) << " vertices" << std::endl; + std::string output_name = generate_output_name(filename, relative_alpha, relative_offset); + std::cout << "Writing to " << "resumed_" + output_name << std::endl; + CGAL::IO::write_polygon_mesh("resumed_" + output_name, wrap, CGAL::parameters::stream_precision(17)); + + // --- Get the final wrap, in one go: + Mesh single_pass_wrap; + CGAL::alpha_wrap_3(points, polygons, alpha, offset, single_pass_wrap); + std::cout << ">>> The final (from scratch) wrap has " << num_vertices(single_pass_wrap) << " vertices" << std::endl; + + output_name = generate_output_name(filename, relative_alpha, relative_offset); + std::cout << "Writing to " << output_name << std::endl; + CGAL::IO::write_polygon_mesh(output_name, single_pass_wrap, CGAL::parameters::stream_precision(17)); + + // --- Compare the results to ensure both approaches yield identical meshes + std::vector > common; + std::vector m1_only; + std::vector m2_only; + PMP::match_faces(wrap, single_pass_wrap, + std::back_inserter(common), + std::back_inserter(m1_only), + std::back_inserter(m2_only)); + if(!m1_only.empty() || !m2_only.empty()) + { + std::cerr << "Error: The two wraps should have been identical!" << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} From 021d1fe8bdec6ac00268d8726094c3c58ac10e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 16 Oct 2023 17:05:38 +0200 Subject: [PATCH 061/133] Use the sorted priority queue in the plugin --- .../Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index f40130dedb12..f9eba756bf83 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -9,6 +9,10 @@ #include "Scene_polylines_item.h" #include "Scene_points_with_normal_item.h" +// Since we want to do visualization and interruption, it's better to use the sorted priority queue, +// even if it is slower +#define CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + #include #include From 847795ec00214884ec7c04ef6f6ad947d5ae937f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 17 Oct 2023 13:01:18 +0200 Subject: [PATCH 062/133] Hide cavity behind a named parameter --- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 44 ++++++++++++------- .../internal/parameters_interface.h | 1 + 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 31870dd01470..98313249efda 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -278,6 +278,10 @@ class Alpha_wrapper_3 // geometrically manifold. const bool do_enforce_manifoldness = choose_parameter(get_parameter(in_np, internal_np::do_enforce_manifoldness), true); + // Whether to keep pockets of OUTSIDE cells that are not connected to the exterior (or to the + // initial cavities, if used). + const bool keep_inner_ccs = choose_parameter(get_parameter(in_np, internal_np::keep_inner_connected_components), true); + // This parameter enables avoiding recomputing the triangulation from scratch when wrapping // the same input for multiple values of alpha (and typically the same offset values). // /!\ Warning /!\ @@ -317,12 +321,6 @@ class Alpha_wrapper_3 dump_triangulation_faces("flood_filled_wrap.off", true /*only_boundary_faces*/); #endif - purge_inner_islands(); - -#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS - dump_triangulation_faces("purged_wrap.off", true /*only_boundary_faces*/); -#endif - #ifdef CGAL_AW3_TIMER t.stop(); std::cout << "Flood filling took: " << t.time() << " s." << std::endl; @@ -338,12 +336,6 @@ class Alpha_wrapper_3 dump_triangulation_faces("manifold_wrap.off", true /*only_boundary_faces*/); #endif - purge_inner_islands(); - -#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS - dump_triangulation_faces("purged_manifold_wrap.off", true /*only_boundary_faces*/); -#endif - #ifdef CGAL_AW3_TIMER t.stop(); std::cout << "Manifoldness post-processing took: " << t.time() << " s." << std::endl; @@ -352,6 +344,17 @@ class Alpha_wrapper_3 #endif } + if(!keep_inner_ccs) + { + // We could purge *before* manifold enforcement, but making the mesh manifold is + // very cheap in most cases, so it is better to keep the code simpler. + purge_inner_connected_components(); + +#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS + dump_triangulation_faces("purged_wrap.off", true /*only_boundary_faces*/); +#endif + } + extract_surface(output_mesh, ovpm, !do_enforce_manifoldness); #ifdef CGAL_AW3_TIMER @@ -1395,12 +1398,17 @@ class Alpha_wrapper_3 return true; } - // Any outside cell that isn't reachable from infinity is a cavity that can - // be discarded. This also removes some difficult non-manifoldness onfigurations - std::size_t purge_inner_islands() + // Any outside cell that isn't reachable from infinity is a cavity that can be discarded. + std::size_t purge_inner_connected_components() { #ifdef CGAL_AW3_DEBUG std::cout << "> Purge inner islands..." << std::endl; + + std::size_t pre_counter = 0; + for(Cell_handle ch : m_tr.all_cell_handles()) + if(ch->is_outside()) + ++pre_counter; + std::cout << pre_counter << " / " << m_tr.all_cell_handles().size() << " (pre purge)" << std::endl; #endif std::size_t label_change_counter = 0; @@ -1467,6 +1475,12 @@ class Alpha_wrapper_3 ch->tds_data().clear(); #ifdef CGAL_AW3_DEBUG + std::size_t post_counter = 0; + for(Cell_handle ch : m_tr.all_cell_handles()) + if(ch->is_outside()) + ++post_counter; + std::cout << post_counter << " / " << m_tr.all_cell_handles().size() << " (pre purge)" << std::endl; + std::cout << label_change_counter << " label changes" << std::endl; #endif diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 435075df6e2a..a164053aabbc 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -238,6 +238,7 @@ CGAL_add_named_parameter(smooth_constrained_edges_t, smooth_constrained_edges, s CGAL_add_named_parameter(do_enforce_manifoldness_t, do_enforce_manifoldness, do_enforce_manifoldness) CGAL_add_named_parameter(seed_points_t, seed_points, seed_points) CGAL_add_named_parameter(refine_triangulation_t, refine_triangulation, refine_triangulation) +CGAL_add_named_parameter(keep_inner_connected_components_t, keep_inner_connected_components, keep_inner_connected_components) // SMDS_3 parameters CGAL_add_named_parameter(surface_facets_t, surface_facets, surface_facets) From d51d71a563f12269e7dbcf6835d1295a66d3bc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 17 Oct 2023 13:12:24 +0200 Subject: [PATCH 063/133] Misc minor improvements --- .../examples/Alpha_wrap_3/output_helper.h | 2 +- .../pause_and_resume_wrapping.cpp | 2 +- .../Alpha_wrap_3/successive_wraps.cpp | 63 ++++++-------- .../CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 82 +++++++++---------- .../internal/gate_priority_queue.h | 6 +- 5 files changed, 70 insertions(+), 85 deletions(-) diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h b/Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h index 3ce1155f4ef5..581ac82bff02 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/output_helper.h @@ -16,4 +16,4 @@ std::string generate_output_name(std::string input_name, return output_name; } -#endif // CGAL_ALPHA_WRAP_3_EXAMPLES_OUTPUT_HELPER_H \ No newline at end of file +#endif // CGAL_ALPHA_WRAP_3_EXAMPLES_OUTPUT_HELPER_H diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp index 5663bce16847..b22b21d817bc 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp @@ -2,7 +2,7 @@ // and how to resume afterwards. // // -------------------------------- !! Warning !! -------------------------------------------------- -// By default, the wrap uses an unsorted LIFO queue of faces to refine. This means that +// By default, the wrapper uses an unsorted LIFO queue of faces to refine. This means that // the intermediate result is not very useful because the algorithm carves deep and not wide // (somewhat like a DFS vs a BFS). // diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp index f8533fb9cda9..301aec46e2d5 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/successive_wraps.cpp @@ -1,4 +1,21 @@ -#define CGAL_AW3_TIMER +// In this example, we reuse the underlying triangulation of the previous state, and carve using +// a new (smaller) alpha value. This enables considerable speed-up: the cumulated time taken +// to run `n` successive instances of `{alpha_wrap(alpha_i)}_(i=1...n)` will be roughly equal +// to the time taken to the single instance of alpha_wrap(alpha_n) from scratch. +// +// The speed-up increases with the number of intermediate results, and on the gap between +// alpha values: if alpha_2 is close to alpha_1, practically no new computation are required, +// and the speed-up is almost 100%. +// +// -------------------------------- !! Warning !! -------------------------------------------------- +// The result of: +// > alpha_wrap(alpha_1, ...) +// > alpha_wrap(alpha_2, ..., reuse) +// is not exactly identical to calling directly: +// > alpha_wrap(alpha_2, ..., do_not_reuse) +// because the queues are sorted slightly differently and the AABB tree is rebuilt differently +// to optimize the runtime. +// ------------------------------------------------------------------------------------------------- #include "output_helper.h" @@ -21,10 +38,6 @@ using Point_3 = K::Point_3; using Mesh = CGAL::Surface_mesh; -// We want decreasing alphas, and these are relative ratios, so they need to be increasing -const std::vector relative_alphas = { 1, 2/*50, 100, 150, 200, 250*/ }; -const FT relative_offset = 600; - int main(int argc, char** argv) { std::cout.precision(17); @@ -48,6 +61,10 @@ int main(int argc, char** argv) CGAL::square(bbox.ymax() - bbox.ymin()) + CGAL::square(bbox.zmax() - bbox.zmin())); + // We want decreasing alphas, and these are relative ratios, so they need to be increasing + const std::vector relative_alphas = { 1, 50, 100, 150, 200, 250 }; + const FT relative_offset = 600; + // =============================================================================================== // Naive approach: @@ -64,17 +81,12 @@ int main(int argc, char** argv) std::cout << ">>> [" << i << "] alpha: " << alpha << " offset: " << offset << std::endl; Mesh wrap; - CGAL::alpha_wrap_3(mesh, alpha, offset, wrap, - CGAL::parameters::do_enforce_manifoldness(false)); + CGAL::alpha_wrap_3(mesh, alpha, offset, wrap); t.stop(); std::cout << " Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl; std::cout << " Elapsed time: " << t.time() << " s." << std::endl; - const std::string output_name = generate_output_name(filename, relative_alphas[i], relative_offset); - std::cout << "Writing to " << output_name << std::endl; - CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); - total_time += t.time(); } @@ -82,29 +94,6 @@ int main(int argc, char** argv) // =============================================================================================== // Re-use approach - // - // Here, we restart from the triangulation of the previous state, and carve according - // to a (smaller) alpha value. This enables considerable speed-up: the cumulated time taken - // to run `n` successive instances of `{alpha_wrap(alpha_i)}_(i=1...n)` will be equal to the - // time taken to run alpha_wrap(alpha_n) from scratch. - // - // For example: - // naive: - // alpha_wrap(alpha_1, ...) ---> 2s - // alpha_wrap(alpha_2, ...) ---> 4s - // alpha_wrap(alpha_3, ...) ---> 8s - // will become with reusability: - // alpha_wrap(alpha_1, ..., reuse) ---> 2s - // alpha_wrap(alpha_2, ..., reuse) ---> 2s // 2+2 = 4s = naive alpha_2 - // alpha_wrap(alpha_3, ..., reuse) ---> 4s // 2+2+4 = 8s = naive alpha_3 - // Thus, if we care about the intermediate results, we save 6s (8s instead of 14s). - // The speed-up increases with the number of intermediate results, and if the alpha values - // are close. - // - // !! Warning !! - // The result of alpha_wrap(alpha_1, ...) followed by alpha_wrap(alpha_2, ...) with alpha_2 - // smaller than alpha_1 is going to be close but NOT exactly equal to that produced by calling - // alpha_wrap(alpha_2, ...) directly. total_time = 0.; t.reset(); @@ -122,7 +111,7 @@ int main(int argc, char** argv) const double offset = diag_length / relative_offset; std::cout << ">>> [" << i << "] alpha: " << alpha << " offset: " << offset << std::endl; - // The triangle mesh oracle can be initialized with alpha to internally perform a split + // The triangle mesh oracle should be initialized with alpha to internally perform a split // of too-big facets while building the AABB Tree. This split in fact yields a significant // speed-up for meshes with elements that are large compared to alpha. This speed-up makes it // faster to re-build the AABB tree for every value of alpha than to use a non-optimized tree. @@ -131,9 +120,7 @@ int main(int argc, char** argv) wrapper.oracle() = oracle; Mesh wrap; - wrapper(alpha, offset, wrap, - CGAL::parameters::do_enforce_manifoldness(false) - .refine_triangulation((i != 0))); + wrapper(alpha, offset, wrap, CGAL::parameters::refine_triangulation((i != 0))); t.stop(); std::cout << " Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 98313249efda..45834cd6b61f 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -125,7 +125,7 @@ class Alpha_wrapper_3 using Default_Vb = Alpha_wrap_triangulation_vertex_base_3; using Default_Cb = Alpha_wrap_triangulation_cell_base_3; - using Default_Cbt = Cell_base_with_timestamp; // determinism + using Default_Cbt = Cell_base_with_timestamp; // for determinism using Default_Tds = CGAL::Triangulation_data_structure_3; using Default_Triangulation = CGAL::Delaunay_triangulation_3; @@ -143,12 +143,13 @@ class Alpha_wrapper_3 using Gate = internal::Gate; - // A sorted queue is a priority queue sorted by circumradius, and is experimentally much slower, - // but intermediate results are visually nice: somewhat uniform meshes. + // A sorted queue is a priority queue sorted by circumradius, and is experimentally significantly + // slower. However, intermediate results are usable: at each point of the algorithm, the wrap + // has a somewhat uniform mesh element size. // // An unsorted queue is a LIFO queue, and is experimentally much faster (~35%), - // but intermediate results are not useful: a LIFO will mean carving is done very deep - // before than wide + // but intermediate results are not useful: a LIFO carves deep before than wide, + // and can thus for example leave scaffolding faces till almost the end of the refinement. #ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; #else @@ -270,7 +271,7 @@ class Alpha_wrapper_3 Wrapping_default_visitor default_visitor; Visitor visitor = choose_parameter(get_parameter_reference(in_np, internal_np::visitor), default_visitor); - // + // Points used to create initial cavities m_seeds = choose_parameter(get_parameter_reference(in_np, internal_np::seed_points), Seeds()); // Whether or not some cells should be reflagged as "inside" after the refinement+carving loop @@ -278,16 +279,16 @@ class Alpha_wrapper_3 // geometrically manifold. const bool do_enforce_manifoldness = choose_parameter(get_parameter(in_np, internal_np::do_enforce_manifoldness), true); - // Whether to keep pockets of OUTSIDE cells that are not connected to the exterior (or to the + // Whether to keep pockets of "outside" cells that are not connected to the exterior (or to the // initial cavities, if used). const bool keep_inner_ccs = choose_parameter(get_parameter(in_np, internal_np::keep_inner_connected_components), true); // This parameter enables avoiding recomputing the triangulation from scratch when wrapping // the same input for multiple values of alpha (and typically the same offset values). - // /!\ Warning /!\ // - // If this is enabled, the 3D triangulation will NOT be re-initialized - // at launch. This means that the triangulation is NOT cleared, even if: + // /!\ Warning /!\ + // If this is enabled, the 3D triangulation will NOT be re-initialized at launch. + // This means that the triangulation is NOT cleared, even if: // - you use an alpha value that is greater than what was used in a previous run; you will // obtain the same result as the last run. // - you use a different offset value between runs, you might then get points that are not @@ -423,12 +424,12 @@ class Alpha_wrapper_3 // boundary considers them inside. bool is_on_inside_boundary(Cell_handle ch, Cell_handle nh) const { - return (ch->is_inside() != nh->is_inside()); // one is INSIDE, the other is not + return (ch->is_inside() != nh->is_inside()); // one is "inside", the other is not } bool is_on_outside_boundary(Cell_handle ch, Cell_handle nh) const { - return (ch->is_outside() != nh->is_outside()); // one is OUTSIDE, the other is not + return (ch->is_outside() != nh->is_outside()); // one is "outside", the other is not } private: @@ -552,7 +553,7 @@ class Alpha_wrapper_3 continue; } - // Mark the seeds and icosahedron vertices as "scaffolding vertices" such that the facets + // Mark the seeds and icosahedron vertices as "scaffolding" vertices such that the facets // incident to these vertices are always traversable regardless of their circumcenter. // This is done because otherwise some cavities can appear on the mesh: non-traversable facets // with two vertices on the offset, and the third being a deeper inside seed / ico_seed. @@ -633,7 +634,7 @@ class Alpha_wrapper_3 continue; // When the algorithm starts from a manually dug hole, infinite cells are initialized - // as INSIDE such that they do not appear on the boundary + // as "inside" such that they do not appear on the boundary CGAL_assertion(!m_tr.is_infinite(ch)); for(int i=0; i<4; ++i) @@ -651,7 +652,7 @@ class Alpha_wrapper_3 return true; } - // tag all infinite cells OUTSIDE and all finite cells INSIDE + // tag all infinite cells "outside" and all finite cells "inside" // init queue with all convex hull facets bool initialize_from_infinity() { @@ -688,9 +689,6 @@ class Alpha_wrapper_3 std::cout << "Restart from a DT of " << m_tr.number_of_cells() << " cells" << std::endl; #endif - Real_timer t; - t.start(); - for(Cell_handle ch : m_tr.all_cell_handles()) { if(ch->is_inside()) @@ -698,16 +696,12 @@ class Alpha_wrapper_3 for(int i=0; i<4; ++i) { - if(ch->neighbor(i)->is_outside()) - continue; + if(ch->neighbor(i)->is_inside()) + push_facet(std::make_pair(ch, i)); - push_facet(std::make_pair(ch, i)); } } - t.stop(); - std::cout << t.time() << " for scanning a queue of size " << m_queue.size() << std::endl; - return true; } @@ -751,7 +745,6 @@ class Alpha_wrapper_3 if(cell->tds_data().processed()) continue; - cell->tds_data().mark_processed(); for(int fid=0; fid<4; ++fid) @@ -1024,12 +1017,12 @@ class Alpha_wrapper_3 << m_tr.point(f.first, Triangulation::vertex_triple_index(f.second, 2)) << std::endl; #endif - // skip if neighbor is OUTSIDE or infinite + // skip if neighbor is "outside" or infinite const Cell_handle ch = f.first; const int id = f.second; CGAL_precondition(ch->label() == Cell_label::INSIDE || ch->label() == Cell_label::OUTSIDE); - if(!ch->is_outside()) // INSIDE or MANIFOLD + if(!ch->is_outside()) // "inside" or "manifold" { #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "Facet is inside" << std::endl; @@ -1168,6 +1161,10 @@ class Alpha_wrapper_3 // and we can resume with the current queue if(resuming) { +#ifdef CGAL_AW3_DEBUG + std::cout << "Resuming with a queue of size: " << m_queue.size() << std::endl; +#endif + reset_manifold_labels(); return true; } @@ -1181,7 +1178,7 @@ class Alpha_wrapper_3 if(refining) { // If we are re-using the triangulation, change the label of the extra elements - // that we have added to ensure a manifold result back to external (MANIFOLD -> OUTSIDE) + // that we have added to ensure a manifold result back to external ("manifold" -> "outside") reset_manifold_labels(); return initialize_from_existing_triangulation(); @@ -1190,7 +1187,6 @@ class Alpha_wrapper_3 { m_tr.clear(); - insert_bbox_corners(); if(m_seeds.empty()) @@ -1512,7 +1508,7 @@ class Alpha_wrapper_3 if(ic->is_outside()) outside_start = ic; else if(inside_start == Cell_handle()) - inside_start = ic; // can be INSIDE or MANIFOLD + inside_start = ic; // can be "inside" or "manifold" } // fully inside / outside @@ -1659,12 +1655,12 @@ class Alpha_wrapper_3 FT base_vol = wrap_volume(); if(!is_positive(base_vol)) - std::cerr << "Warning: empty wrap?" << std::endl; + std::cerr << "Warning: wrap with non-positive volume?" << std::endl; #endif - // This seems more harmful than useful after the priority queue has been introduced since - // it adds a lot of flat cells into the triangulation, which then get added to the mesh - // during manifoldness fixing. + // This ends up more harmful than useful after the priority queue has been introduced since + // it usually results in a lot of flat cells into the triangulation, which then get added + // to the mesh during manifoldness fixing. // remove_bbox_vertices(); std::stack non_manifold_vertices; // @todo sort somehow? @@ -1694,8 +1690,8 @@ class Alpha_wrapper_3 return false; }; - // This seemed like a good idea, but in the end it can have strong cascading issues, - // whereas some cells with much lower volume would have solved the non-manifoldness. + // This originally seemed like a good idea, but in the end it can have strong cascading issues, + // whereas some cells with much smaller volume could have solved the non-manifoldness. // auto is_on_boundary = [](Cell_handle c, int i) -> bool // { // return is_on_outside_boundary(c, c->neighbor(i)); @@ -1716,14 +1712,14 @@ class Alpha_wrapper_3 // return boundary_facets; // }; - // longest edge works better + // Experimentally, longest edge works better // auto sq_circumradius = [&](Cell_handle c) -> FT // { // const Point_3& cc = circumcenter(c); // return geom_traits().compute_squared_distance_3_object()(m_tr.point(c, 0), cc); // }; - // the reasoning behind using longest edge rather than volume is that we want to avoid + // The reasoning behind using longest edge rather than volume is that we want to avoid // spikes (which would have a small volume), and can often happen since we do not spend // any care on the quality of tetrahedra. auto sq_longest_edge = [&](Cell_handle c) -> FT @@ -1756,9 +1752,9 @@ class Alpha_wrapper_3 // - cells without bbox vertices // - small cells when equal number of boundary facets // - // Note that these are properties that do not depend on where the surface is, so we can - // sort once. However, if a criterion such as the number of inside cells were added, - // one would need to sort again after each modification of is_outside() statuses. + // Note that these are properties that do not depend on the cell labels, and so we only need + // to sort once. However, if a criterion such as the number of incident inside cells were added, + // we would need to sort after each modification of "inside"/"outside" labels. auto comparer = [&](Cell_handle l, Cell_handle r) -> bool { CGAL_precondition(!m_tr.is_infinite(l) && !m_tr.is_infinite(r)); @@ -1780,7 +1776,7 @@ class Alpha_wrapper_3 // 'std::stable_sort' to have determinism without having to write something like: // if(longest_edge(l) == longest_edge(r)) return ... - // in the comparer. It's a small range, so the cost does not matter. + // in the comparer. It's almost always a small range, so the extra cost does not matter. std::stable_sort(finite_outside_inc_cells.begin(), finite_outside_inc_cells.end(), comparer); for(Cell_handle ic : finite_outside_inc_cells) @@ -1803,6 +1799,8 @@ class Alpha_wrapper_3 CGAL_assertion(!is_non_manifold(v)); + // Check if the new material has not created a non-manifold configuration. + // @speed this could be done on only the vertices of cells whose labels have changed. std::vector adj_vertices; adj_vertices.reserve(64); m_tr.finite_adjacent_vertices(v, std::back_inserter(adj_vertices)); diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index 9c29ac9e7226..f7947f246a4b 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -70,12 +70,12 @@ struct Less_gate template bool operator()(const Gate& a, const Gate& b) const { - // If one is permissive and the other is not, give priority to the permissive facet + // If one is permissive and the other is not, give priority to the permissive facet. // // The permissive facet are given highest priority because they need to be treated // regardless of their circumradius. Treating them first allow the part that depends - // on alpha to be treated uniformly in a way: whatever the alpha, all scaffolding faces - // will first be treated + // on alpha to be treated uniformly in a way: whatever the alpha, all permissive faces + // will first be treated. if(a.is_permissive_facet() != b.is_permissive_facet()) return a.is_permissive_facet(); From f753c8928c2608f13d1e21d632a7cccd03338bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 17 Oct 2023 17:15:13 +0200 Subject: [PATCH 064/133] Minor compilation fix --- .../include/CGAL/Alpha_wrap_3/internal/validation.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/validation.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/validation.h index c9445c9e9c50..6d9a9191d5f4 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/validation.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/validation.h @@ -117,7 +117,7 @@ bool has_expected_Hausdorff_distance(const TriangleMesh& wrap, template bool is_valid_wrap(const TriangleMesh& wrap, - const bool check_manifoldness = true, + const bool check_manifoldness, const NamedParameters& np = parameters::default_values()) { namespace PMP = CGAL::Polygon_mesh_processing; @@ -203,6 +203,13 @@ bool is_valid_wrap(const TriangleMesh& wrap, return true; } +template +bool is_valid_wrap(const TriangleMesh& wrap, + const NamedParameters& np = parameters::default_values()) +{ + return is_valid_wrap(wrap, true /*consider manifoldness*/, np); +} + template From c7af977fd24d499ac28e1624ae28b166c3b0f51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 18 Oct 2023 09:43:20 +0200 Subject: [PATCH 065/133] Add code in benchmarks to enable ignoring inputs that have degeneracies --- .../compute_robustness_benchmark_data.py | 25 ++++++++--------- .../generate_robustness_benchmark_charts.py | 26 +++++++++--------- .../Robustness/robustness_benchmark.cpp | 27 +++++++++++-------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py index 9e5fead9f864..9def2bb6cc16 100755 --- a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py @@ -23,18 +23,19 @@ def compute_robustness_benchmark_data(execname, filename, alpha, max_time): exit_codes = { 0 : "VALID_SOLID_OUTPUT", - 1 : "OUTPUT_IS_NOT_TRIANGLE_MESH", - 2 : "OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD", - 3 : "OUTPUT_HAS_BORDERS", - 4 : "OUTPUT_HAS_DEGENERATED_FACES", - 5 : "OUTPUT_HAS_GEOMETRIC_SELF_INTERSECTIONS", - 6 : "OUTPUT_DOES_NOT_BOUND_VOLUME", - 7 : "OUTPUT_DOES_NOT_CONTAIN_INPUT", - 8 : "OUTPUT_DISTANCE_IS_TOO_LARGE", - 9 : "SIGSEGV", - 10 : "SIGABRT", - 11 : "SIGFPE", - 12 : "TIMEOUT" + 1 : "INPUT_IS_INVALID", + 2 : "OUTPUT_IS_NOT_TRIANGLE_MESH", + 3 : "OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD", + 4 : "OUTPUT_HAS_BORDERS", + 5 : "OUTPUT_HAS_DEGENERATED_FACES", + 6 : "OUTPUT_HAS_GEOMETRIC_SELF_INTERSECTIONS", + 7 : "OUTPUT_DOES_NOT_BOUND_VOLUME", + 8 : "OUTPUT_DOES_NOT_CONTAIN_INPUT", + 9 : "OUTPUT_DISTANCE_IS_TOO_LARGE", + 10 : "SIGSEGV", + 11 : "SIGABRT", + 12 : "SIGFPE", + 13 : "TIMEOUT" } exit_code = 0 diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/generate_robustness_benchmark_charts.py b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/generate_robustness_benchmark_charts.py index da313069594f..f9938d4fc7b6 100644 --- a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/generate_robustness_benchmark_charts.py +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/generate_robustness_benchmark_charts.py @@ -40,22 +40,24 @@ def main(argv): exit_codes = { 0 : "VALID_SOLID_OUTPUT", - 1 : "OUTPUT_IS_NOT_TRIANGLE_MESH", - 2 : "OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD", - 3 : "OUTPUT_HAS_BORDERS", - 4 : "OUTPUT_HAS_DEGENERATED_FACES", - 5 : "OUTPUT_HAS_GEOMETRIC_SELF_INTERSECTIONS", - 6 : "OUTPUT_DOES_NOT_BOUND_VOLUME", - 7 : "OUTPUT_DOES_NOT_CONTAIN_INPUT", - 8 : "OUTPUT_DISTANCE_IS_TOO_LARGE", - 9 : "SIGSEGV", - 10 : "SIGABRT", - 11 : "SIGFPE", - 12 : "TIMEOUT" + 1 : "INPUT_IS_INVALID", + 2 : "OUTPUT_IS_NOT_TRIANGLE_MESH", + 3 : "OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD", + 4 : "OUTPUT_HAS_BORDERS", + 5 : "OUTPUT_HAS_DEGENERATED_FACES", + 6 : "OUTPUT_HAS_GEOMETRIC_SELF_INTERSECTIONS", + 7 : "OUTPUT_DOES_NOT_BOUND_VOLUME", + 8 : "OUTPUT_DOES_NOT_CONTAIN_INPUT", + 9 : "OUTPUT_DISTANCE_IS_TOO_LARGE", + 10 : "SIGSEGV", + 11 : "SIGABRT", + 12 : "SIGFPE", + 13 : "TIMEOUT" } current_run_data = { "VALID_SOLID_OUTPUT" : 0, + "INPUT_IS_INVALID" : 0, "OUTPUT_IS_NOT_TRIANGLE_MESH" : 0, "OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD" : 0, "OUTPUT_HAS_BORDERS" : 0, diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp index 57f58b342bd5..353e5569d1f9 100644 --- a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp @@ -21,14 +21,15 @@ enum Robustness_benchmark_exit_code VALID_SOLID_OUTPUT = 0, // Failure - OUTPUT_IS_NOT_TRIANGLE_MESH = 1, - OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD = 2, - OUTPUT_HAS_BORDERS = 3, - OUTPUT_HAS_DEGENERATED_FACES = 4, - OUTPUT_HAS_GEOMETRIC_SELF_INTERSECTIONS = 5, - OUTPUT_DOES_NOT_BOUND_VOLUME = 6, - OUTPUT_DOES_NOT_CONTAIN_INPUT = 7, - OUTPUT_DISTANCE_IS_TOO_LARGE = 8, + INTPUT_IS_INVALID = 1, + OUTPUT_IS_NOT_TRIANGLE_MESH = 2, + OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD = 3, + OUTPUT_HAS_BORDERS = 4, + OUTPUT_HAS_DEGENERATED_FACES = 5, + OUTPUT_HAS_GEOMETRIC_SELF_INTERSECTIONS = 6, + OUTPUT_DOES_NOT_BOUND_VOLUME = 7, + OUTPUT_DOES_NOT_CONTAIN_INPUT = 8, + OUTPUT_DISTANCE_IS_TOO_LARGE = 9, }; } // namespace @@ -58,14 +59,18 @@ int main(int argc, char** argv) } if(argc < 3 || relative_alpha_ratio <= 0.) - return AW3i::VALID_SOLID_OUTPUT; + return AW3i::INTPUT_IS_INVALID; Mesh input_mesh; if(!PMP::IO::read_polygon_mesh(entry_name_ptr, input_mesh) || is_empty(input_mesh) || - !is_triangle_mesh(input_mesh)) + !is_triangle_mesh(input_mesh) +#ifndef CGAL_ALPHA_WRAP_3_TOLERATE_DEGENERACIES + || AW3i::has_degenerated_faces(input_mesh) +#endif + ) { - return AW3i::VALID_SOLID_OUTPUT; + return AW3i::INTPUT_IS_INVALID; } const CGAL::Bbox_3 bbox = PMP::bbox(input_mesh); From e6b84d48513ab52a4b0b6d973509d03d22f251b3 Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Wed, 18 Oct 2023 10:19:23 +0200 Subject: [PATCH 066/133] typo Co-authored-by: Jane Tournois --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index 4e9082996e49..8cd6dc4f6ccc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -41,7 +41,7 @@ namespace Polygon_mesh_processing { * * @param pm the polygon mesh to be refined. * @param value_map the property map containing a value at each vertex for a given function defined over the mesh. - * @param isovalue the value used to defined + * @param isovalue the value used to refine * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin From 2c19ffcd8bce9eef3a5a6a35189dfc5bc2358c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 18 Oct 2023 10:29:28 +0200 Subject: [PATCH 067/133] Add a warning --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 45834cd6b61f..94694034cdd1 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -281,6 +281,9 @@ class Alpha_wrapper_3 // Whether to keep pockets of "outside" cells that are not connected to the exterior (or to the // initial cavities, if used). + // + // /!\ Warning /!\ + // If you refine or pause while removing pockets, you will get valid but different wraps. const bool keep_inner_ccs = choose_parameter(get_parameter(in_np, internal_np::keep_inner_connected_components), true); // This parameter enables avoiding recomputing the triangulation from scratch when wrapping From 08fa9f8a58fb24ae9119e06e1d188b3a21b1c568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 20 Oct 2023 08:57:07 +0200 Subject: [PATCH 068/133] fix wording --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index 8cd6dc4f6ccc..f1ceb6e59d33 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -46,7 +46,8 @@ namespace Polygon_mesh_processing { * * \cgalNamedParamsBegin * \cgalParamNBegin{edge_is_constrained_map} - * \cgalParamDescription{an output property map associating `true` to all new edges added by the cut, and `false` to input edges.} + * \cgalParamDescription{an output property map associating `true` to all new edges connecting vertices on the isolevel, + * and `false` for all other edges.} * \cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits::%edge_descriptor` * as key type and `bool` as value type} * \cgalParamDefault{No marks on edges will be put} From fe28c0d64acd1fc151a7792a934f05155350a520 Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Fri, 20 Oct 2023 11:46:39 +0200 Subject: [PATCH 069/133] doc bugs Co-authored-by: Andreas Fabri --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index f1ceb6e59d33..293d791a47cd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -46,7 +46,7 @@ namespace Polygon_mesh_processing { * * \cgalNamedParamsBegin * \cgalParamNBegin{edge_is_constrained_map} - * \cgalParamDescription{an output property map associating `true` to all new edges connecting vertices on the isolevel, + * \cgalParamDescription{an output property map associating `true` to all edges connecting vertices on the isolevel, * and `false` for all other edges.} * \cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits::%edge_descriptor` * as key type and `bool` as value type} @@ -55,7 +55,7 @@ namespace Polygon_mesh_processing { * * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `pm`} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `%Point_3` as value type} * \cgalParamDefault{`boost::get(CGAL::vertex_point, pm)`} * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` From 21fddd1c13fc1bf57d701246891e5df894fa6e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 30 Oct 2023 23:40:12 +0100 Subject: [PATCH 070/133] Fix default values' bbox not being computed for point set items --- .../Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index f9eba756bf83..86a879835623 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -547,8 +547,6 @@ public Q_SLOTS: triangles.emplace_back(get(vpm, target(h, *pMesh)), get(vpm, target(next(h, *pMesh), *pMesh)), get(vpm, source(h, *pMesh))); - - m_wrap_bbox += triangles.back().bbox(); } continue; @@ -571,8 +569,6 @@ public Q_SLOTS: triangles.emplace_back(soup_item->points()[p[0]], soup_item->points()[p[1]], soup_item->points()[p[2]]); - - m_wrap_bbox += triangles.back().bbox(); } continue; @@ -599,8 +595,6 @@ public Q_SLOTS: triangles.emplace_back(get(vpm, target(h, *pMesh)), get(vpm, target(next(h, *pMesh), *pMesh)), get(vpm, source(h, *pMesh))); - - m_wrap_bbox += triangles.back().bbox(); } segments.reserve(segments.size() + selection_item->selected_edges.size()); @@ -608,16 +602,12 @@ public Q_SLOTS: { segments.emplace_back(get(vpm, target(halfedge(e, *pMesh), *pMesh)), get(vpm, target(opposite(halfedge(e, *pMesh), *pMesh), *pMesh))); - - m_wrap_bbox += segments.back().bbox(); } points.reserve(points.size() + selection_item->selected_vertices.size()); for(const auto& v : selection_item->selected_vertices) { points.push_back(get(vpm, v)); - - m_wrap_bbox += points.back().bbox(); } continue; @@ -656,6 +646,15 @@ public Q_SLOTS: std::cout << segments.size() << " edges" << std::endl; std::cout << points.size() << " points" << std::endl; + for(const Kernel::Triangle_3& tr : triangles) + m_wrap_bbox += tr.bbox(); + for(const Kernel::Segment_3& sg : segments) + m_wrap_bbox += sg.bbox(); + for(const Kernel::Point_3& pt : points) + m_wrap_bbox += pt.bbox(); + + std::cout << "Bbox:\n" << m_wrap_bbox << std::endl; + // The relative value uses the bbox of the full scene and not that of selected items to wrap // This is intentional, both because it's tedious to make it otherwise, and because it seems // to be simpler to compare between "all wrapped" / "some wrapped" From fb682fe9eb7a24339a6e4004da6a07bffbdfe639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 30 Oct 2023 23:43:54 +0100 Subject: [PATCH 071/133] Fix memory issues in PS/SS oracles after no longer taking oracles by const& --- .../Alpha_wrap_3/internal/Point_set_oracle.h | 27 +++++++++++-------- .../internal/Segment_soup_oracle.h | 27 +++++++++++-------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h index 8ccbf049a33e..37ff14955604 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace CGAL { @@ -41,6 +42,7 @@ struct PS_oracle_traits using Geom_traits = Alpha_wrap_AABB_geom_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 using Points = std::vector; + using Points_ptr = std::shared_ptr; using PR_iterator = typename Points::const_iterator; using Primitive = AABB_primitive; private: - Points m_points; + Points_ptr m_points_ptr; public: // Constructors - Point_set_oracle() - : Oracle_base(BaseOracle(), Base_GT()) - { } - Point_set_oracle(const BaseOracle& base_oracle, const Base_GT& gt = Base_GT()) : Oracle_base(base_oracle, gt) - { } + { + m_points_ptr = std::make_shared(); + } Point_set_oracle(const Base_GT& gt, const BaseOracle& base_oracle = BaseOracle()) - : Oracle_base(base_oracle, gt) + : Point_set_oracle(gt, base_oracle) + { } + + Point_set_oracle() + : Point_set_oracle(BaseOracle(), Base_GT()) { } public: @@ -106,14 +111,14 @@ class Point_set_oracle return; } - const std::size_t old_size = m_points.size(); - m_points.insert(std::cend(m_points), std::cbegin(points), std::cend(points)); + const std::size_t old_size = m_points_ptr->size(); + m_points_ptr->insert(std::cend(*m_points_ptr), std::cbegin(points), std::cend(points)); #ifdef CGAL_AW3_DEBUG std::cout << "Insert into AABB tree (points)..." << std::endl; #endif - this->tree().insert(std::next(std::cbegin(m_points), old_size), std::cend(m_points)); + this->tree().insert(std::next(std::cbegin(*m_points_ptr), old_size), std::cend(*m_points_ptr)); // Manually constructing it here purely for profiling reasons: if we keep the lazy approach, // it will be done at the first treatment of a facet that needs a Steiner point. @@ -121,7 +126,7 @@ class Point_set_oracle // to accelerate the tree. this->tree().accelerate_distance_queries(); - CGAL_postcondition(this->tree().size() == m_points.size()); + CGAL_postcondition(this->tree().size() == m_points_ptr->size()); } }; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h index 63f3532cf67e..f4d1c338b62f 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace CGAL { @@ -42,6 +43,7 @@ struct SS_oracle_traits using Segment = typename GT_::Segment_3; using Segments = std::vector; + using Segments_ptr = std::shared_ptr; using SR_iterator = typename Segments::const_iterator; using Primitive = AABB_primitive; private: - Segments m_segments; + Segments_ptr m_segments_ptr; public: // Constructors - Segment_soup_oracle() - : Oracle_base(BaseOracle(), Base_GT()) - { } - Segment_soup_oracle(const BaseOracle& base_oracle, const Base_GT& gt = Base_GT()) : Oracle_base(base_oracle, gt) - { } + { + m_segments_ptr = std::make_shared(); + } Segment_soup_oracle(const Base_GT& gt, const BaseOracle& base_oracle = BaseOracle()) - : Oracle_base(base_oracle, gt) + : Segment_soup_oracle(base_oracle, gt) + { } + + Segment_soup_oracle() + : Segment_soup_oracle(BaseOracle(), Base_GT()) { } public: @@ -109,7 +114,7 @@ class Segment_soup_oracle typename Geom_traits::Is_degenerate_3 is_degenerate = this->geom_traits().is_degenerate_3_object(); - const std::size_t old_size = m_segments.size(); + const std::size_t old_size = m_segments_ptr->size(); for(const Segment& s : segments) { @@ -121,13 +126,13 @@ class Segment_soup_oracle continue; } - m_segments.push_back(s); + m_segments_ptr->push_back(s); } #ifdef CGAL_AW3_DEBUG std::cout << "Insert into AABB tree (segments)..." << std::endl; #endif - this->tree().insert(std::next(std::cbegin(m_segments), old_size), std::cend(m_segments)); + this->tree().insert(std::next(std::cbegin(*m_segments_ptr), old_size), std::cend(*m_segments_ptr)); // Manually constructing it here purely for profiling reasons: if we keep the lazy approach, // it will be done at the first treatment of a facet that needs a Steiner point. @@ -135,7 +140,7 @@ class Segment_soup_oracle // to accelerate the tree. this->tree().accelerate_distance_queries(); - CGAL_postcondition(this->tree().size() == m_segments.size()); + CGAL_postcondition(this->tree().size() == m_segments_ptr->size()); } }; From 3879b13c0ed8b4f4677065b8b7ae6e5d0d4e93a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 30 Oct 2023 23:46:46 +0100 Subject: [PATCH 072/133] Misc minor improvements --- .../CGAL/Alpha_wrap_3/internal/Oracle_base.h | 1 - .../Alpha_wrap_3/internal/Point_set_oracle.h | 2 +- .../Alpha_wrap_3/internal/Segment_soup_oracle.h | 2 +- .../Alpha_wrap_3/internal/Triangle_mesh_oracle.h | 2 +- .../Alpha_wrap_3/internal/Triangle_soup_oracle.h | 16 +++++++++++++++- .../Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 4 ++-- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h index 85bd11c00b6c..7f3534a484cf 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h @@ -321,7 +321,6 @@ class AABB_tree_oracle typename AABB_tree::Bounding_box bbox() const { CGAL_precondition(!empty()); - return tree().bbox(); } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h index 37ff14955604..ad04a43f720e 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h @@ -106,7 +106,7 @@ class Point_set_oracle if(points.empty()) { #ifdef CGAL_AW3_DEBUG - std::cout << "Warning: Input is empty " << std::endl; + std::cout << "Warning: Input is empty (PS)" << std::endl; #endif return; } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h index f4d1c338b62f..349cd012ef7a 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h @@ -107,7 +107,7 @@ class Segment_soup_oracle if(segments.empty()) { #ifdef CGAL_AW3_DEBUG - std::cout << "Warning: Input is empty " << std::endl; + std::cout << "Warning: Input is empty (SS)" << std::endl; #endif return; } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h index ffd8326a44f6..d7f325e1428f 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h @@ -135,7 +135,7 @@ class Triangle_mesh_oracle if(is_empty(tmesh)) { #ifdef CGAL_AW3_DEBUG - std::cout << "Warning: Input is empty " << std::endl; + std::cout << "Warning: Input is empty (TM)" << std::endl; #endif return; } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h index 27322a554e36..dadfb5d8be10 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h @@ -133,7 +133,7 @@ class Triangle_soup_oracle if(points.empty() || faces.empty()) { #ifdef CGAL_AW3_DEBUG - std::cout << "Warning: Input is empty " << std::endl; + std::cout << "Warning: Input is empty (TS)" << std::endl; #endif return; } @@ -190,8 +190,22 @@ class Triangle_soup_oracle void add_triangle_soup(const TriangleRange& triangles, const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values()) { + if(triangles.empty()) + { +#ifdef CGAL_AW3_DEBUG + std::cout << "Warning: Input is empty (TS)" << std::endl; +#endif + return; + } + +#ifdef CGAL_AW3_DEBUG + std::cout << "Insert into AABB Tree (triangles)..." << std::endl; +#endif + typename Geom_traits::Is_degenerate_3 is_degenerate = this->geom_traits().is_degenerate_3_object(); + Splitter_base::reserve(triangles.size()); + for(const Triangle_3& tr : triangles) { if(is_degenerate(tr)) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index 86a879835623..383d1103778f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -687,8 +687,8 @@ public Q_SLOTS: const bool use_message_box = ui.enableMessageBox->isChecked(); - std::cout << "Wrapping edges? " << std::boolalpha << wrap_segments << std::endl; std::cout << "Wrapping faces? " << std::boolalpha << wrap_triangles << std::endl; + std::cout << "Wrapping edges? " << std::boolalpha << wrap_segments << std::endl; if(!wrap_triangles) { @@ -740,7 +740,7 @@ public Q_SLOTS: if(alpha <= 0. || offset <= 0.) { - print_message("Warning: alpha/offset must be strictly positive - nothing to wrap"); + print_message("Warning: alpha/offset must be strictly positive"); QApplication::restoreOverrideCursor(); return; } From 4444fdf2d43f55eee71e16c111502ac742772904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 31 Oct 2023 10:59:05 +0100 Subject: [PATCH 073/133] Fix compilation --- .../include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h index ad04a43f720e..33f8a52b178b 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h @@ -89,7 +89,7 @@ class Point_set_oracle Point_set_oracle(const Base_GT& gt, const BaseOracle& base_oracle = BaseOracle()) - : Point_set_oracle(gt, base_oracle) + : Point_set_oracle(base_oracle, gt) { } Point_set_oracle() From 361c5c50094a36bda8d09ba8a2aedd7d2cf4c42d Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 2 Nov 2023 14:13:07 +0100 Subject: [PATCH 074/133] remove all the _sizing_field parameters that have never been used they were removed from the documentation before being merged in the master branch see SVN commit https://github.com/CGAL/cgal-attic/commit/1614a89e32693a9f33394083d75ed11f06209947 --- Mesh_3/include/CGAL/Mesh_criteria_3.h | 12 +++--------- .../STL_Extension/internal/parameters_interface.h | 4 ---- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Mesh_3/include/CGAL/Mesh_criteria_3.h b/Mesh_3/include/CGAL/Mesh_criteria_3.h index 96511da5520c..d950cfb6d828 100644 --- a/Mesh_3/include/CGAL/Mesh_criteria_3.h +++ b/Mesh_3/include/CGAL/Mesh_criteria_3.h @@ -70,22 +70,16 @@ class Mesh_criteria_3_impl // is not a problem template Mesh_criteria_3_impl(const CGAL_NP_CLASS& np) - :edge_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::edge_size_param), - parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::edge_sizing_field_param), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::sizing_field_param), FT(DBL_MAX)))), + :edge_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::edge_size_param), FT(DBL_MAX)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::edge_min_size_param), FT(0))), facet_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_angle_param), FT(0)), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_size_param), - parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::facet_sizing_field_param), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::sizing_field_param), FT(0)))), + parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_size_param), FT(0)), parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::facet_distance_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_topology_param), CGAL::FACET_VERTICES_ON_SURFACE), parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_min_size_param), FT(0))), cell_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_radius_edge_ratio_param), parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_radius_edge_param), FT(0))), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_size_param), - parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::cell_sizing_field_param), - parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::sizing_field_param), FT(0)))), + parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_size_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_min_size_param), FT(0))) { } diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 7792ad5cdb60..621e551c40f4 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -337,19 +337,15 @@ CGAL_add_named_parameter_with_compatibility(features_detector_param_t, features_ CGAL_add_named_parameter_with_compatibility(input_features_param_t, input_features_param, input_features) CGAL_add_named_parameter_with_compatibility(edge_size_param_t, edge_size_param, edge_size) -CGAL_add_named_parameter_with_compatibility_cref_only(edge_sizing_field_param_t, edge_sizing_field_param, edge_sizing_field) CGAL_add_named_parameter_with_compatibility(edge_min_size_param_t, edge_min_size_param, edge_min_size) CGAL_add_named_parameter_with_compatibility(facet_angle_param_t, facet_angle_param, facet_angle) CGAL_add_named_parameter_with_compatibility(facet_size_param_t, facet_size_param, facet_size) -CGAL_add_named_parameter_with_compatibility_cref_only(facet_sizing_field_param_t, facet_sizing_field_param, facet_sizing_field) CGAL_add_named_parameter_with_compatibility_cref_only(facet_distance_param_t, facet_distance_param, facet_distance) CGAL_add_named_parameter_with_compatibility(facet_min_size_param_t, facet_min_size_param, facet_min_size) CGAL_add_named_parameter_with_compatibility(facet_topology_param_t, facet_topology_param, facet_topology) CGAL_add_named_parameter_with_compatibility(cell_radius_edge_param_t, cell_radius_edge_param, cell_radius_edge) CGAL_add_named_parameter_with_compatibility(cell_radius_edge_ratio_param_t, cell_radius_edge_ratio_param, cell_radius_edge_ratio) CGAL_add_named_parameter_with_compatibility(cell_size_param_t, cell_size_param, cell_size) -CGAL_add_named_parameter_with_compatibility_cref_only(cell_sizing_field_param_t, cell_sizing_field_param, cell_sizing_field) -CGAL_add_named_parameter_with_compatibility_cref_only(sizing_field_param_t, sizing_field_param, sizing_field) CGAL_add_named_parameter_with_compatibility(cell_min_size_param_t, cell_min_size_param, cell_min_size) CGAL_add_named_parameter_with_compatibility(function_param_t, function_param, function) From 093660ce4343e3a3b8ca65fe8e2a860907e7d69f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 2 Nov 2023 14:27:31 +0100 Subject: [PATCH 075/133] remove unused and undocumented criterion cell_radius_edge --- Mesh_3/include/CGAL/Mesh_criteria_3.h | 3 +-- .../include/CGAL/STL_Extension/internal/parameters_interface.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Mesh_3/include/CGAL/Mesh_criteria_3.h b/Mesh_3/include/CGAL/Mesh_criteria_3.h index d950cfb6d828..12e0e4222075 100644 --- a/Mesh_3/include/CGAL/Mesh_criteria_3.h +++ b/Mesh_3/include/CGAL/Mesh_criteria_3.h @@ -77,8 +77,7 @@ class Mesh_criteria_3_impl parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::facet_distance_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_topology_param), CGAL::FACET_VERTICES_ON_SURFACE), parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_min_size_param), FT(0))), - cell_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_radius_edge_ratio_param), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_radius_edge_param), FT(0))), + cell_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_radius_edge_ratio_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_size_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_min_size_param), FT(0))) { } diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 621e551c40f4..d656b63a0069 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -343,7 +343,6 @@ CGAL_add_named_parameter_with_compatibility(facet_size_param_t, facet_size_param CGAL_add_named_parameter_with_compatibility_cref_only(facet_distance_param_t, facet_distance_param, facet_distance) CGAL_add_named_parameter_with_compatibility(facet_min_size_param_t, facet_min_size_param, facet_min_size) CGAL_add_named_parameter_with_compatibility(facet_topology_param_t, facet_topology_param, facet_topology) -CGAL_add_named_parameter_with_compatibility(cell_radius_edge_param_t, cell_radius_edge_param, cell_radius_edge) CGAL_add_named_parameter_with_compatibility(cell_radius_edge_ratio_param_t, cell_radius_edge_ratio_param, cell_radius_edge_ratio) CGAL_add_named_parameter_with_compatibility(cell_size_param_t, cell_size_param, cell_size) CGAL_add_named_parameter_with_compatibility(cell_min_size_param_t, cell_min_size_param, cell_min_size) From 5b6bf127457be9335b79ef73d0443fa6c9612e4c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 2 Nov 2023 14:39:34 +0100 Subject: [PATCH 076/133] use get_parameter_reference for all the possibly-field parameters --- Mesh_3/include/CGAL/Mesh_criteria_3.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mesh_3/include/CGAL/Mesh_criteria_3.h b/Mesh_3/include/CGAL/Mesh_criteria_3.h index 12e0e4222075..c2d5d3d9b139 100644 --- a/Mesh_3/include/CGAL/Mesh_criteria_3.h +++ b/Mesh_3/include/CGAL/Mesh_criteria_3.h @@ -70,15 +70,15 @@ class Mesh_criteria_3_impl // is not a problem template Mesh_criteria_3_impl(const CGAL_NP_CLASS& np) - :edge_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::edge_size_param), FT(DBL_MAX)), + :edge_criteria_(parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::edge_size_param), FT(DBL_MAX)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::edge_min_size_param), FT(0))), facet_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_angle_param), FT(0)), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_size_param), FT(0)), + parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::facet_size_param), FT(0)), parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::facet_distance_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_topology_param), CGAL::FACET_VERTICES_ON_SURFACE), parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_min_size_param), FT(0))), cell_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_radius_edge_ratio_param), FT(0)), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_size_param), FT(0)), + parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::cell_size_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::cell_min_size_param), FT(0))) { } From 710ef72e27fe0b4315f9301d1d64e3885e767e05 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 14 Nov 2023 13:26:08 +0000 Subject: [PATCH 077/133] Move code to initializer list --- Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h b/Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h index e6ff36dd0ce7..a526ec5085d5 100644 --- a/Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h +++ b/Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h @@ -33,7 +33,10 @@ template class Sphere_segment_rep typedef Sphere_segment_rep Rep; friend class Sphere_segment; public: -Sphere_segment_rep() { ps_ = pt_ = Point(); c_ = Circle(); } + +Sphere_segment_rep() : + ps_(), pt_(), c_() +{} Sphere_segment_rep(const Point& p1, const Point& p2, bool shorter_arc=true) : From 73bd84ddd1ab845643705d63f94e5eac33d162af Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 17 Nov 2023 11:25:44 +0100 Subject: [PATCH 078/133] Improve add_toc_to_github_wiki_page.py - reformat using `black` - add an option `--max-level` - quote anchors (for accentuated character) - fix linter errors --- .../add_toc_to_github_wiki_page.py | 191 +++++++++--------- 1 file changed, 98 insertions(+), 93 deletions(-) diff --git a/Scripts/developer_scripts/add_toc_to_github_wiki_page.py b/Scripts/developer_scripts/add_toc_to_github_wiki_page.py index ce61f49db7e1..494878cca738 100644 --- a/Scripts/developer_scripts/add_toc_to_github_wiki_page.py +++ b/Scripts/developer_scripts/add_toc_to_github_wiki_page.py @@ -1,125 +1,130 @@ -from sys import argv -from sys import exit import codecs import re import argparse +import sys +from urllib.parse import quote parser = argparse.ArgumentParser() -parser.add_argument("filename", - help="the Mardown file to process") -parser.add_argument("--codebase", - help="for a Markdown file of Codebase instead of Github", - action="store_true") -parser.add_argument("--h1", - help="support level one sections (h1)", - action="store_true") +parser.add_argument("filename", help="the Mardown file to process") +parser.add_argument( + "--codebase", + help="for a Markdown file of Codebase instead of Github", + action="store_true", +) +parser.add_argument("--h1", help="support level one sections (h1)", action="store_true") +parser.add_argument("--max-level", help="maximum level of sections", type=int, default = 5) args = parser.parse_args() + # a probably incomplete version to generate an anchor from a section name def get_anchor(s): - s = s.replace("`","") - s = s.replace("(","") - s = s.replace(")","") - s = s.replace(".","") - s = s.replace("#","") - s = s.replace(":","") - s = s.replace(",","") - s = s.replace(";","") - if args.codebase: - s = s.replace("/","-") - else: - s = s.replace("/","") - s = s.replace("<","") - s = s.replace(">","") - s = s.replace("+","") - s = s.replace("=","") - s = s.replace("?","") - s = s.replace("@","") - s = s.lstrip(" ") - s = s.rstrip("\n") - s = s.rstrip(" ") - s = re.sub(r'\s+','-',s) - if not args.codebase: - s = s.lower() - if args.codebase: - s = s.replace("'","-and-39-") - return "#"+s + s = s.replace("`", "") + s = s.replace("(", "") + s = s.replace(")", "") + s = s.replace(".", "") + s = s.replace("#", "") + s = s.replace(":", "") + s = s.replace(",", "") + s = s.replace(";", "") + if args.codebase: + s = s.replace("/", "-") + else: + s = s.replace("/", "") + s = s.replace("<", "") + s = s.replace(">", "") + s = s.replace("+", "") + s = s.replace("=", "") + s = s.replace("?", "") + s = s.replace("@", "") + s = s.lstrip(" ") + s = s.rstrip("\n") + s = s.rstrip(" ") + s = re.sub(r"\s+", "-", s) + if not args.codebase: + s = s.lower() + if args.codebase: + s = s.replace("'", "-and-39-") + return "#" + quote(s) + # indices the nesting level (first level allowed is ##) def get_level(s): - m = re.search('^(#+)\s', s) - if m: - return len(m.group(1)) - else: - return 0 + m = re.search(r"^(#+)\s", s) + if m: + return len(m.group(1)) + else: + return 0 + def get_name(s): - m = re.search('^#+\s+(.*)\s*$', s) - if m: - return m.group(1) - else: - return "ERROR: Section name extraction" + m = re.search(r"^#+\s+(.*)\s*$", s) + if m: + return m.group(1) + else: + return "ERROR: Section name extraction" + -#generate the entry for one section +# generate the entry for one section def get_toc_entry(s): - name = get_name(s) - if args.h1: - level = get_level(s)-1 - else: - level = get_level(s)-2 - anchor = get_anchor(s) + name = get_name(s) + if args.h1: + level = get_level(s) - 1 + else: + level = get_level(s) - 2 + anchor = get_anchor(s) + + if level < 0: + return "ERROR: h1 sections are not allowed" - if level<0: - return "ERROR: h1 sections are not allowed" + res = "* [" + name + "](" + anchor + ")" + for _ in range(0, level): + res = " " + res + return res - res="* ["+name+"]("+anchor+")" - for i in range(0,level): - res=" "+res - return res -#now the main -input = args.filename +# now the main +filename = args.filename -f = codecs.open(input, 'r', encoding='utf-8') +f = codecs.open(filename, "r", encoding="utf-8") if not f: - print("Cannot open "+input+"\n") - exit() + print("Cannot open " + input + "\n") + sys.exit() -#look for the begin of the file -line=f.readline() -if line.find("")==-1: - exit() +# look for the begin of the file +line = f.readline() +if line.find("") == -1: + sys.exit() -#skip current TOC -line=f.readline() -while line and line.find("")==-1: - line=f.readline() +# skip current TOC +line = f.readline() +while line and line.find("") == -1: + line = f.readline() if not line: - exit() + sys.exit() -buffer="" -TOC="\n\n# Table of Contents\n" +buffer = "" +TOC = "\n\n# Table of Contents\n" -verbatim_mode=False # to ignore verbatim mode while looking for sections -TOC_empty=True +verbatim_mode = False # to ignore verbatim mode while looking for sections +TOC_empty = True for line in f.readlines(): - buffer+=line - if verbatim_mode: - if line[:3]=="```": - verbatim_mode=False - else: - if line[:3]=="```": - verbatim_mode=True + buffer += line + if verbatim_mode: + if line[:3] == "```": + verbatim_mode = False else: - if line[0]=="#": - TOC+=(get_toc_entry(line)+"\n") - TOC_empty=False -TOC+="\n\n" + if line[:3] == "```": + verbatim_mode = True + else: + if line[0] == "#" and get_level(line) <= args.max_level: + TOC += get_toc_entry(line) + "\n" + TOC_empty = False +TOC += "\n\n" if not TOC_empty: - f.close() - f = codecs.open(input, 'w', encoding='utf-8') - f.write(TOC) - f.write(buffer) + f.close() + f = codecs.open(filename, "w", encoding="utf-8") + f.write(TOC) + f.write(buffer) From fa96bf86232add30f1896390a9a82af76180498e Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 17 Nov 2023 17:11:46 +0100 Subject: [PATCH 079/133] fix other linter warnings --- .../add_toc_to_github_wiki_page.py | 84 ++++++++++--------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/Scripts/developer_scripts/add_toc_to_github_wiki_page.py b/Scripts/developer_scripts/add_toc_to_github_wiki_page.py index 494878cca738..928703c502e8 100644 --- a/Scripts/developer_scripts/add_toc_to_github_wiki_page.py +++ b/Scripts/developer_scripts/add_toc_to_github_wiki_page.py @@ -5,7 +5,7 @@ from urllib.parse import quote parser = argparse.ArgumentParser() -parser.add_argument("filename", help="the Mardown file to process") +parser.add_argument("filename", help="the Markdown file to process") parser.add_argument( "--codebase", help="for a Markdown file of Codebase instead of Github", @@ -83,48 +83,52 @@ def get_toc_entry(s): # now the main -filename = args.filename +def main(): + filename = args.filename -f = codecs.open(filename, "r", encoding="utf-8") + f = codecs.open(filename, "r", encoding="utf-8") -if not f: - print("Cannot open " + input + "\n") - sys.exit() + if not f: + print("Cannot open " + input + "\n") + sys.exit() -# look for the begin of the file -line = f.readline() -if line.find("") == -1: - sys.exit() - -# skip current TOC -line = f.readline() -while line and line.find("") == -1: + # look for the begin of the file line = f.readline() + if line.find("") == -1: + sys.exit() -if not line: - sys.exit() - -buffer = "" -TOC = "\n\n# Table of Contents\n" - -verbatim_mode = False # to ignore verbatim mode while looking for sections -TOC_empty = True -for line in f.readlines(): - buffer += line - if verbatim_mode: - if line[:3] == "```": - verbatim_mode = False - else: - if line[:3] == "```": - verbatim_mode = True + # skip current TOC + line = f.readline() + while line and line.find("") == -1: + line = f.readline() + + if not line: + sys.exit() + + buffer = "" + toc = "\n\n# Table of Contents\n" + + verbatim_mode = False # to ignore verbatim mode while looking for sections + toc_empty = True + for line in f.readlines(): + buffer += line + if verbatim_mode: + if line[:3] == "```": + verbatim_mode = False else: - if line[0] == "#" and get_level(line) <= args.max_level: - TOC += get_toc_entry(line) + "\n" - TOC_empty = False -TOC += "\n\n" - -if not TOC_empty: - f.close() - f = codecs.open(filename, "w", encoding="utf-8") - f.write(TOC) - f.write(buffer) + if line[:3] == "```": + verbatim_mode = True + else: + if line[0] == "#" and get_level(line) <= args.max_level: + toc += get_toc_entry(line) + "\n" + toc_empty = False + toc += "\n\n" + + if not toc_empty: + f.close() + f = codecs.open(filename, "w", encoding="utf-8") + f.write(toc) + f.write(buffer) + +if __name__ == "__main__": + main() From 730bbba98bbce3c9983644e02a66fb45c508cdf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 20 Nov 2023 10:03:16 +0100 Subject: [PATCH 080/133] add an example with a dummy custom sizing field --- .../Polygon_mesh_processing/CMakeLists.txt | 1 + ...c_remeshing_with_custom_sizing_example.cpp | 102 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 590305c0c8ad..38d1bce078b0 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -51,6 +51,7 @@ create_single_source_cgal_program("match_faces.cpp") create_single_source_cgal_program("cc_compatible_orientations.cpp") create_single_source_cgal_program("hausdorff_distance_remeshing_example.cpp") create_single_source_cgal_program("hausdorff_bounded_error_distance_example.cpp") +create_single_source_cgal_program("isotropic_remeshing_with_custom_sizing_example.cpp") find_package(Eigen3 3.2.0 QUIET) #(requires 3.2.0 or greater) include(CGAL_Eigen3_support) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp new file mode 100644 index 000000000000..1fc70906f7d7 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + +namespace PMP = CGAL::Polygon_mesh_processing; + +// a sizing fied that is increasing the size of edge along the y-axis +// starting at a minimum size at y-max and ending at a maximum size at +// y-min, with a linear interpolation of sizes in between the two extreme +// sizing values +struct My_sizing_field +{ + double min_size, max_size; + double ymin, ymax; + const Mesh& mesh; + + My_sizing_field(double min_size, double max_size, double ymin, double ymax, const Mesh& mesh) + : min_size(min_size) + , max_size(max_size) + , ymin(ymin) + , ymax(ymax) + , mesh(mesh) + {} + + double at(K::Point_3 p) const + { + double y=p.y(); + return CGAL::square( (y-ymin)/(ymax-ymin) * (min_size - max_size) + max_size ); + } + double at(const Mesh::Vertex_index v) const { return at(mesh.point(v)); } + + std::optional is_too_long(const Mesh::Vertex_index va, + const Mesh::Vertex_index vb) const + { + // TODO: no mesh as parameters? + K::Point_3 mp = CGAL::midpoint(mesh.point(va), mesh.point(vb)); + double sql_at = at(mp); + double sql = CGAL::squared_distance(mesh.point(va), mesh.point(vb)); + if (sql > sql_at) + return sql / sql_at; + return std::nullopt; + } + + std::optional is_too_short(const Mesh::Halfedge_index h, + const Mesh&) const + { + K::Point_3 mp = CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh))); + double sql_at = at(mp); + double sql = CGAL::squared_distance(mesh.point(source(h, mesh)), mesh.point(target(h, mesh))); + if (sql < sql_at) + return sql / sql_at; + return std::nullopt; + } + + K::Point_3 split_placement(const Mesh::Halfedge_index h, + const Mesh&) const + { + return CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh))); + } + + void update(const Mesh::Vertex_index, const Mesh&) {} +}; + + +int main(int argc, char* argv[]) +{ + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/elk.off"); + + Mesh mesh; + if (!PMP::IO::read_polygon_mesh(filename, mesh) || !CGAL::is_triangle_mesh(mesh)) { + std::cerr << "Not a valid input file." << std::endl; + return 1; + } + + std::cout << "Start remeshing of " << filename + << " (" << num_faces(mesh) << " faces)..." << std::endl; + + CGAL::Bbox_3 bb = PMP::bbox(mesh); + My_sizing_field sizing_field(0.1, 30, bb.ymin(), bb.ymax(), mesh); + unsigned int nb_iter = 5; + + PMP::isotropic_remeshing( + faces(mesh), + sizing_field, + mesh, + CGAL::parameters::number_of_iterations(nb_iter) + .number_of_relaxation_steps(3) + ); + + CGAL::IO::write_polygon_mesh("custom_remesh_out.off", mesh, CGAL::parameters::stream_precision(17)); + + std::cout << "Remeshing done." << std::endl; + + return 0; +} From 37fb95b5cd7619848b829677de5dd64d6f97a6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 20 Nov 2023 11:28:50 +0100 Subject: [PATCH 081/133] improve concept --- .../Concepts/PMPSizingField.h | 27 ++++++++++--------- ...c_remeshing_with_custom_sizing_example.cpp | 17 ++++++------ .../Adaptive_sizing_field.h | 6 ++--- .../Uniform_sizing_field.h | 6 ++--- .../Isotropic_remeshing/remesh_impl.h | 24 ++++++++--------- .../internal/Sizing_field_base.h | 7 ++--- .../tangential_relaxation.h | 6 ++--- 7 files changed, 48 insertions(+), 45 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h index 8641c30c6caf..02822cea9e70 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h @@ -16,6 +16,7 @@ class PMPSizingField{ public: /// @name Types +/// These types are used for the documentation of the functions of the concept and not needed implementation wise. /// @{ /// Vertex descriptor type @@ -38,27 +39,29 @@ typedef unspecified_type FT; /// @name Functions /// @{ -/// a function that returns the sizing value at `v`. -FT at(const vertex_descriptor v) const; +/// returns the sizing value at `v` (used during tangential relaxation). +FT at(const vertex_descriptor v, const PolygonMesh& pmesh) const; -/// a function controlling edge split and edge collapse, -/// returning the ratio of the current edge length and the local target edge length between -/// the points of `va` and `vb` in case the current edge is too long, and `std::nullopt` otherwise. +/// returns the ratio of the current edge squared length and the local target edge squared length between +/// the points of `va` and `vb` in case the current edge is too long, and `std::nullopt` otherwise +/// (used for triggering edge splits and preventing some edge collapses). std::optional is_too_long(const vertex_descriptor va, - const vertex_descriptor vb) const; + const vertex_descriptor vb, + const PolygonMesh& pmesh) const; -/// a function controlling edge collapse by returning the ratio of the squared length of `h` and the -/// local target edge length if it is too short, and `std::nullopt` otherwise. +/// returns the ratio of the squared length of `h` and the +/// local target edge squared length if it is too short, and `std::nullopt` otherwise +/// (used for triggering edge collapses). std::optional is_too_short(const halfedge_descriptor h, const PolygonMesh& pmesh) const; -/// a function returning the location of the split point of the edge of `h`. +/// returns the position of the new vertex created when splitting the edge of `h`. Point_3 split_placement(const halfedge_descriptor h, const PolygonMesh& pmesh) const; -/// a function that updates the sizing field value at the vertex `v`. -void update(const vertex_descriptor v, - const PolygonMesh& pmesh); +/// function called after the addition of the split vertex `v` in `pmesh`. +void register_split_vertex(const vertex_descriptor v, + const PolygonMesh& pmesh); /// @} }; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp index 1fc70906f7d7..53d70af603ff 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_with_custom_sizing_example.cpp @@ -19,14 +19,12 @@ struct My_sizing_field { double min_size, max_size; double ymin, ymax; - const Mesh& mesh; - My_sizing_field(double min_size, double max_size, double ymin, double ymax, const Mesh& mesh) + My_sizing_field(double min_size, double max_size, double ymin, double ymax) : min_size(min_size) , max_size(max_size) , ymin(ymin) , ymax(ymax) - , mesh(mesh) {} double at(K::Point_3 p) const @@ -34,10 +32,11 @@ struct My_sizing_field double y=p.y(); return CGAL::square( (y-ymin)/(ymax-ymin) * (min_size - max_size) + max_size ); } - double at(const Mesh::Vertex_index v) const { return at(mesh.point(v)); } + double at(const Mesh::Vertex_index v, const Mesh& mesh) const { return at(mesh.point(v)); } std::optional is_too_long(const Mesh::Vertex_index va, - const Mesh::Vertex_index vb) const + const Mesh::Vertex_index vb, + const Mesh& mesh) const { // TODO: no mesh as parameters? K::Point_3 mp = CGAL::midpoint(mesh.point(va), mesh.point(vb)); @@ -49,7 +48,7 @@ struct My_sizing_field } std::optional is_too_short(const Mesh::Halfedge_index h, - const Mesh&) const + const Mesh& mesh) const { K::Point_3 mp = CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh))); double sql_at = at(mp); @@ -60,12 +59,12 @@ struct My_sizing_field } K::Point_3 split_placement(const Mesh::Halfedge_index h, - const Mesh&) const + const Mesh& mesh) const { return CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh))); } - void update(const Mesh::Vertex_index, const Mesh&) {} + void register_split_vertex(const Mesh::Vertex_index, const Mesh&) {} }; @@ -83,7 +82,7 @@ int main(int argc, char* argv[]) << " (" << num_faces(mesh) << " faces)..." << std::endl; CGAL::Bbox_3 bb = PMP::bbox(mesh); - My_sizing_field sizing_field(0.1, 30, bb.ymin(), bb.ymax(), mesh); + My_sizing_field sizing_field(0.1, 30, bb.ymin(), bb.ymax()); unsigned int nb_iter = 5; PMP::isotropic_remeshing( diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h index a61edc699d06..d576df0e447b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h @@ -213,13 +213,13 @@ class Adaptive_sizing_field } public: - FT at(const vertex_descriptor v) const + FT at(const vertex_descriptor v, const PolygonMesh& /* pmesh */) const { CGAL_assertion(get(m_vertex_sizing_map, v)); return get(m_vertex_sizing_map, v); } - std::optional is_too_long(const vertex_descriptor va, const vertex_descriptor vb) const + std::optional is_too_long(const vertex_descriptor va, const vertex_descriptor vb, const PolygonMesh& /* pmesh */) const { const FT sqlen = sqlength(va, vb); FT sqtarg_len = CGAL::square(4./3. * (CGAL::min)(get(m_vertex_sizing_map, va), @@ -251,7 +251,7 @@ class Adaptive_sizing_field get(m_vpmap, source(h, pmesh))); } - void update(const vertex_descriptor v, const PolygonMesh& pmesh) + void register_split_vertex(const vertex_descriptor v, const PolygonMesh& pmesh) { // calculating it as the average of two vertices on other ends // of halfedges as updating is done during an edge split diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Uniform_sizing_field.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Uniform_sizing_field.h index a4144ceee650..d14f4be9666d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Uniform_sizing_field.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Uniform_sizing_field.h @@ -102,12 +102,12 @@ class Uniform_sizing_field } public: - FT at(const vertex_descriptor /* v */) const + FT at(const vertex_descriptor /* v */, const PolygonMesh& /* pmesh */) const { return m_size; } - std::optional is_too_long(const vertex_descriptor va, const vertex_descriptor vb) const + std::optional is_too_long(const vertex_descriptor va, const vertex_descriptor vb, const PolygonMesh& /* pmesh */) const { const FT sqlen = sqlength(va, vb); if (sqlen > m_sq_long) @@ -133,7 +133,7 @@ class Uniform_sizing_field get(m_vpmap, source(h, pmesh))); } - void update(const vertex_descriptor /* v */, const PolygonMesh& /* pmesh */) + void register_split_vertex(const vertex_descriptor /* v */, const PolygonMesh& /* pmesh */) {} private: diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h index c1696428d756..30d201d1ef51 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h @@ -246,7 +246,7 @@ namespace internal { get(ecmap, e) || get(fpm, face(h,pmesh))!=get(fpm, face(opposite(h,pmesh),pmesh)) ) { - if (sizing.is_too_long(source(h, pmesh), target(h, pmesh))) + if (sizing.is_too_long(source(h, pmesh), target(h, pmesh), pmesh)) { return false; } @@ -400,7 +400,7 @@ namespace internal { for(edge_descriptor e : edge_range) { const halfedge_descriptor he = halfedge(e, mesh_); - std::optional sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_)); + std::optional sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_), mesh_); if(sqlen != std::nullopt) long_edges.emplace(he, sqlen.value()); } @@ -433,16 +433,16 @@ namespace internal { std::cout << " refinement point : " << refinement_point << std::endl; #endif //update sizing field with the new point - sizing.update(vnew, mesh_); + sizing.register_split_vertex(vnew, mesh_); //check sub-edges //if it was more than twice the "long" threshold, insert them - std::optional sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_)); + std::optional sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_), mesh_); if(sqlen_new != std::nullopt) long_edges.emplace(hnew, sqlen_new.value()); const halfedge_descriptor hnext = next(hnew, mesh_); - sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_)); + sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_), mesh_); if (sqlen_new != std::nullopt) long_edges.emplace(hnext, sqlen_new.value()); @@ -500,7 +500,7 @@ namespace internal { if (!is_split_allowed(e)) continue; const halfedge_descriptor he = halfedge(e, mesh_); - std::optional sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_)); + std::optional sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_), mesh_); if(sqlen != std::nullopt) long_edges.emplace(halfedge(e, mesh_), sqlen.value()); } @@ -550,16 +550,16 @@ namespace internal { halfedge_added(hnew_opp, status(opposite(he, mesh_))); //update sizing field with the new point - sizing.update(vnew, mesh_); + sizing.register_split_vertex(vnew, mesh_); //check sub-edges //if it was more than twice the "long" threshold, insert them - std::optional sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_)); + std::optional sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_), mesh_); if(sqlen_new != std::nullopt) long_edges.emplace(hnew, sqlen_new.value()); const halfedge_descriptor hnext = next(hnew, mesh_); - sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_)); + sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_), mesh_); if (sqlen_new != std::nullopt) long_edges.emplace(hnext, sqlen_new.value()); @@ -580,7 +580,7 @@ namespace internal { if (snew == PATCH) { - std::optional sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_)); + std::optional sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_), mesh_); if(sql != std::nullopt) long_edges.emplace(hnew2, sql.value()); } @@ -603,7 +603,7 @@ namespace internal { if (snew == PATCH) { - std::optional sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_)); + std::optional sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_), mesh_); if (sql != std::nullopt) long_edges.emplace(hnew2, sql.value()); } @@ -747,7 +747,7 @@ namespace internal { for(halfedge_descriptor ha : halfedges_around_target(va, mesh_)) { vertex_descriptor va_i = source(ha, mesh_); - std::optional sqha = sizing.is_too_long(vb, va_i); + std::optional sqha = sizing.is_too_long(vb, va_i, mesh_); if (sqha != std::nullopt) { collapse_ok = false; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Sizing_field_base.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Sizing_field_base.h index f13135cd873e..c06f0568e681 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Sizing_field_base.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Sizing_field_base.h @@ -60,13 +60,14 @@ class Sizing_field_base typedef typename K::FT FT; public: - virtual FT at(const vertex_descriptor v) const = 0; + virtual FT at(const vertex_descriptor v, const PolygonMesh&) const = 0; virtual std::optional is_too_long(const vertex_descriptor va, - const vertex_descriptor vb) const = 0; + const vertex_descriptor vb, + const PolygonMesh&) const = 0; virtual std::optional is_too_short(const halfedge_descriptor h, const PolygonMesh& pmesh) const = 0; virtual Point_3 split_placement(const halfedge_descriptor h, const PolygonMesh& pmesh) const = 0; - virtual void update(const vertex_descriptor v, const PolygonMesh& pmesh) = 0; + virtual void register_split_vertex(const vertex_descriptor v, const PolygonMesh& pmesh) = 0; }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/tangential_relaxation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/tangential_relaxation.h index 6693524324a9..145d5a24135f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/tangential_relaxation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/tangential_relaxation.h @@ -288,9 +288,9 @@ void tangential_relaxation(const VertexRange& vertices, const double tri_area = gt_area(get(vpm, v), get(vpm, v1), get(vpm, v2)); const double face_weight = tri_area - / (1. / 3. * (sizing.at(v) - + sizing.at(v1) - + sizing.at(v2))); + / (1. / 3. * (sizing.at(v, tm) + + sizing.at(v1, tm) + + sizing.at(v2, tm))); weight += face_weight; const Point_3 centroid = gt_centroid(get(vpm, v), get(vpm, v1), get(vpm, v2)); From fe32ee586e5ee817cc32fa81421745ed2092fe3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 20 Nov 2023 11:36:06 +0100 Subject: [PATCH 082/133] at Eigen dependency --- .../CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h index d576df0e447b..5c3a99efef5b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h @@ -38,6 +38,8 @@ namespace Polygon_mesh_processing * Edges too long with respect to the local target edge length are split in two, while * edges that are too short are collapsed. * +* This class depends on the Eigen library. +* * \cgalModels{PMPSizingField} * * \sa `isotropic_remeshing()` From 2363e94f7db77ff0a0c8afb5c4a8f4e089e0f774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 22 Nov 2023 13:30:28 +0100 Subject: [PATCH 083/133] Do not use "Polygon" typedef --- .../Alpha_wrap_3/pause_and_resume_wrapping.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp index b22b21d817bc..cee169048c32 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/pause_and_resume_wrapping.cpp @@ -32,8 +32,8 @@ using K = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_3 = K::Point_3; using Points = std::vector; -using Polygon = std::array; -using Polygons = std::vector; +using Face = std::array; +using Faces = std::vector; using Mesh = CGAL::Surface_mesh; using face_descriptor = boost::graph_traits::face_descriptor; @@ -83,14 +83,14 @@ int main(int argc, char** argv) // = read the soup Points points; - Polygons polygons; - if(!CGAL::IO::read_polygon_soup(filename, points, polygons) || polygons.empty()) + Faces faces; + if(!CGAL::IO::read_polygon_soup(filename, points, faces) || faces.empty()) { std::cerr << "Invalid soup input: " << filename << std::endl; return EXIT_FAILURE; } - std::cout << "Input: " << points.size() << " points, " << polygons.size() << " faces" << std::endl; + std::cout << "Input: " << points.size() << " points, " << faces.size() << " faces" << std::endl; // Compute the alpha and offset values const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : rng.get_double(150., 200.); @@ -111,7 +111,7 @@ int main(int argc, char** argv) // Build the wrapper using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; Oracle oracle(alpha); - oracle.add_triangle_soup(points, polygons, CGAL::parameters::default_values()); + oracle.add_triangle_soup(points, faces, CGAL::parameters::default_values()); CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3 aw3(oracle); // --- Launch the wrapping, and pause when the algorithm has spent 1s flooding @@ -139,7 +139,7 @@ int main(int argc, char** argv) // --- Get the final wrap, in one go: Mesh single_pass_wrap; - CGAL::alpha_wrap_3(points, polygons, alpha, offset, single_pass_wrap); + CGAL::alpha_wrap_3(points, faces, alpha, offset, single_pass_wrap); std::cout << ">>> The final (from scratch) wrap has " << num_vertices(single_pass_wrap) << " vertices" << std::endl; output_name = generate_output_name(filename, relative_alpha, relative_offset); From e4f669561890ae46c61ed238ca8bc1df8ef06a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 22 Nov 2023 13:30:37 +0100 Subject: [PATCH 084/133] Avoid /!\ in comments --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 94694034cdd1..2bfae11f3b72 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -282,14 +282,14 @@ class Alpha_wrapper_3 // Whether to keep pockets of "outside" cells that are not connected to the exterior (or to the // initial cavities, if used). // - // /!\ Warning /!\ + // -- Warning -- // If you refine or pause while removing pockets, you will get valid but different wraps. const bool keep_inner_ccs = choose_parameter(get_parameter(in_np, internal_np::keep_inner_connected_components), true); // This parameter enables avoiding recomputing the triangulation from scratch when wrapping // the same input for multiple values of alpha (and typically the same offset values). // - // /!\ Warning /!\ + // -- Warning -- // If this is enabled, the 3D triangulation will NOT be re-initialized at launch. // This means that the triangulation is NOT cleared, even if: // - you use an alpha value that is greater than what was used in a previous run; you will From 22c2318a55d1589bc581b6110b39f6a527b3a4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 22 Nov 2023 13:30:48 +0100 Subject: [PATCH 085/133] Add a todo --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 2bfae11f3b72..8529af0b0f22 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1087,6 +1087,9 @@ class Alpha_wrapper_3 return false; #endif + // @todo could avoid useless facet_status() calls by doing it after the zombie check + // for the unsorted priority queue, but AFAIR, it doesn't save noticeable time (and that + // increases the queue size). const Facet_status status = facet_status(f); if(status == Facet_status::IRRELEVANT) return false; From 2bc087a139d19802686da58ff434b38fef85792f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 22 Nov 2023 13:33:45 +0100 Subject: [PATCH 086/133] Fix warnings --- Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 2 +- .../include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 8529af0b0f22..d3d2beb6c6e4 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -95,7 +95,7 @@ struct Wrapping_default_visitor void on_flood_fill_begin(const AlphaWrapper&) { } template - constexpr bool go_further(const Wrapper& wrapper) { return true; } + constexpr bool go_further(const Wrapper&) { return true; } template void before_facet_treatment(const AlphaWrapper&, const Gate&) { } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h index f7947f246a4b..ec48b4f458b6 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/gate_priority_queue.h @@ -121,7 +121,7 @@ class Gate public: const Facet& facet() const { return m_facet; } - const bool is_zombie() const + bool is_zombie() const { return (m_facet.first->erase_counter() != m_erase_counter_mem) || (m_mirror_facet.first->erase_counter() != m_mirror_erase_counter_mem); From dac83a571769dfc7313e278866eb1720512a1e42 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 22 Nov 2023 15:11:11 +0000 Subject: [PATCH 087/133] PMP examples: unify type names --- .../compute_normals_example.cpp | 14 +++++++------- .../compute_normals_example_Polyhedron.cpp | 8 ++++---- .../Polygon_mesh_processing/corefinement_LCC.cpp | 4 ++-- .../examples/Polygon_mesh_processing/extrude.cpp | 14 +++++++------- .../hole_filling_example.cpp | 10 +++++----- .../hole_filling_example_LCC.cpp | 10 +++++----- .../interpolated_corrected_curvatures_PH.cpp | 12 ++++++------ .../interpolated_corrected_curvatures_SM.cpp | 11 ++++++----- .../interpolated_corrected_curvatures_vertex.cpp | 8 +++++--- .../orient_polygon_soup_example.cpp | 6 +++--- .../point_inside_example.cpp | 10 +++++----- .../polyhedral_envelope.cpp | 6 +++--- .../polyhedral_envelope_mesh_containment.cpp | 10 +++++----- .../random_perturbation_SM_example.cpp | 8 ++++---- .../refine_fair_example.cpp | 12 ++++++------ .../remesh_almost_planar_patches.cpp | 6 +++--- .../remesh_planar_patches.cpp | 10 +++++----- .../stitch_borders_example.cpp | 4 ++-- .../stitch_borders_example_OM.cpp | 2 +- .../triangulate_faces_example.cpp | 6 +++--- .../triangulate_faces_split_visitor_example.cpp | 13 ++++++------- .../volume_connected_components.cpp | 13 +++++++------ 22 files changed, 100 insertions(+), 97 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example.cpp index c7e1fbdb21c4..949fcc8dd649 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example.cpp @@ -7,14 +7,14 @@ #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef K::Point_3 Point; -typedef K::Vector_3 Vector; +typedef K::Point_3 Point; +typedef K::Vector_3 Vector; -typedef CGAL::Surface_mesh Surface_mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; @@ -22,7 +22,7 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/eight.off"); - Surface_mesh mesh; + Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh)) { std::cerr << "Invalid input." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example_Polyhedron.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example_Polyhedron.cpp index d21d675eb2b8..4418c6096d1b 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example_Polyhedron.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example_Polyhedron.cpp @@ -16,9 +16,9 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; typedef K::Vector_3 Vector; -typedef CGAL::Polyhedron_3 Polyhedron; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef CGAL::Polyhedron_3 Mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; @@ -26,7 +26,7 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/eight.off"); - Polyhedron mesh; + Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh)) { std::cerr << "Invalid input." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp index 232164a1b957..d4d774d1105f 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp @@ -12,7 +12,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point; typedef CGAL::Linear_cell_complex_traits<3, Kernel> MyTraits; -typedef CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper<2, 3, MyTraits>::type LCC; +typedef CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper<2, 3, MyTraits>::type Mesh; namespace PMP = CGAL::Polygon_mesh_processing; @@ -21,7 +21,7 @@ int main(int argc, char* argv[]) const std::string filename1 = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/blobby.off"); const std::string filename2 = (argc > 2) ? argv[2] : CGAL::data_file_path("meshes/eight.off"); - LCC mesh1, mesh2; + Mesh mesh1, mesh2; if(!PMP::IO::read_polygon_mesh(filename1, mesh1) || !PMP::IO::read_polygon_mesh(filename2, mesh2)) { std::cerr << "Invalid input." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/extrude.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/extrude.cpp index aa7c2bd40eab..baaa0612452d 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/extrude.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/extrude.cpp @@ -8,13 +8,13 @@ #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Surface_mesh SM; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef Kernel::Vector_3 Vector; -typedef boost::property_map::type VPMap; -typedef SM::template Property_map VNMap; +typedef Kernel::Vector_3 Vector; +typedef boost::property_map::type VPMap; +typedef Mesh::template Property_map VNMap; struct Bottom { @@ -52,7 +52,7 @@ struct Top int main(int argc, char* argv[]) { - SM in, out; + Mesh in, out; std::string filename = (argc > 1) ? std::string(argv[1]) : CGAL::data_file_path("meshes/cube-ouvert.off"); double vlen = (argc > 2) ? std::stod(argv[2]) : 0.1; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example.cpp index 8c7d009461be..194db942db7c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example.cpp @@ -12,11 +12,11 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Polyhedron_3 Mesh; -typedef Polyhedron::Vertex_handle Vertex_handle; -typedef Polyhedron::Halfedge_handle Halfedge_handle; -typedef Polyhedron::Facet_handle Facet_handle; +typedef Mesh::Vertex_handle Vertex_handle; +typedef Mesh::Halfedge_handle Halfedge_handle; +typedef Mesh::Facet_handle Facet_handle; namespace PMP = CGAL::Polygon_mesh_processing; @@ -24,7 +24,7 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mech-holes-shark.off"); - Polyhedron poly; + Mesh poly; if(!PMP::IO::read_polygon_mesh(filename, poly)) { std::cerr << "Invalid input." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_LCC.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_LCC.cpp index be7b6166e4e1..898256005108 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_LCC.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_LCC.cpp @@ -14,11 +14,11 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point; typedef CGAL::Linear_cell_complex_traits<3, Kernel> MyTraits; -typedef CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper<2, 3, MyTraits>::type LCC; +typedef CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper<2, 3, MyTraits>::type Mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; @@ -26,7 +26,7 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mech-holes-shark.off"); - LCC mesh; + Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh)) { std::cerr << "Invalid input." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_PH.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_PH.cpp index 09bc213068d1..678597ad255c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_PH.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_PH.cpp @@ -7,17 +7,17 @@ #include #include -#include +#include namespace PMP = CGAL::Polygon_mesh_processing; typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel; -typedef CGAL::Polyhedron_3 Polyhedron; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef CGAL::Polyhedron_3 Mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; int main(int argc, char* argv[]) { - Polyhedron polyhedron; + Mesh polyhedron; const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/sphere.off"); @@ -29,11 +29,11 @@ int main(int argc, char* argv[]) } // define property map to store curvature value and directions - boost::property_map>::type + boost::property_map>::type mean_curvature_map = get(CGAL::dynamic_vertex_property_t(), polyhedron), Gaussian_curvature_map = get(CGAL::dynamic_vertex_property_t(), polyhedron); - boost::property_map>>::type + boost::property_map>>::type principal_curvatures_and_directions_map = get(CGAL::dynamic_vertex_property_t>(), polyhedron); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_SM.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_SM.cpp index 74a678ea0624..ac8378781fe4 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_SM.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_SM.cpp @@ -11,12 +11,12 @@ namespace PMP = CGAL::Polygon_mesh_processing; typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel; -typedef CGAL::Surface_mesh Surface_Mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; int main(int argc, char* argv[]) { - Surface_Mesh smesh; + Mesh smesh; const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/sphere.off"); @@ -29,7 +29,7 @@ int main(int argc, char* argv[]) // creating and tying surface mesh property maps for curvatures (with defaults = 0) bool created = false; - Surface_Mesh::Property_map + Mesh::Property_map mean_curvature_map, Gaussian_curvature_map; boost::tie(mean_curvature_map, created) = @@ -41,7 +41,7 @@ int main(int argc, char* argv[]) assert(created); // we use a tuple of 2 scalar values and 2 vectors for principal curvatures and directions - Surface_Mesh::Property_map> + Mesh::Property_map> principal_curvatures_and_directions_map; boost::tie(principal_curvatures_and_directions_map, created) = @@ -67,4 +67,5 @@ int main(int argc, char* argv[]) << ", GC = " << Gaussian_curvature_map[v] << "\n" << ", PC = [ " << PC.min_curvature << " , " << PC.max_curvature << " ]\n"; } + return 0; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_vertex.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_vertex.cpp index bdcdba6b7fd0..dc78152059b7 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_vertex.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/interpolated_corrected_curvatures_vertex.cpp @@ -6,17 +6,18 @@ #include #include +#include namespace PMP = CGAL::Polygon_mesh_processing; typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel; -typedef CGAL::Surface_mesh Surface_Mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; int main(int argc, char* argv[]) { // instantiating and reading mesh - Surface_Mesh smesh; + Mesh smesh; const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/sphere.off"); @@ -47,4 +48,5 @@ int main(int argc, char* argv[]) << ", GC = " << g << "\n" << ", PC = [ " << p.min_curvature << " , " << p.max_curvature << " ]\n"; } + return 0; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp index f603925bb6b3..072ec4c6360a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp @@ -15,7 +15,7 @@ #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Polyhedron_3 Mesh; // Optional visitor for orientating a polygon soup to demonstrate usage for some functions. // inherits from the default class as some functions are not overloaded @@ -59,12 +59,12 @@ int main(int argc, char* argv[]) Visitor visitor; CGAL::Polygon_mesh_processing::orient_polygon_soup(points, polygons, CGAL::parameters::visitor(visitor)); - Polyhedron mesh; + Mesh mesh; CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh); // Number the faces because 'orient_to_bound_a_volume' needs a face <--> index map int index = 0; - for(Polyhedron::Face_iterator fb=mesh.facets_begin(), fe=mesh.facets_end(); fb!=fe; ++fb) + for(Mesh::Face_iterator fb=mesh.facets_begin(), fe=mesh.facets_end(); fb!=fe; ++fb) fb->id() = index++; if(CGAL::is_closed(mesh)) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/point_inside_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/point_inside_example.cpp index 93b158ce1923..1a8b207cd6bb 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/point_inside_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/point_inside_example.cpp @@ -12,14 +12,14 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Polyhedron_3 Mesh; namespace PMP = CGAL::Polygon_mesh_processing; -double max_coordinate(const Polyhedron& poly) +double max_coordinate(const Mesh& poly) { double max_coord = -std::numeric_limits::infinity(); - for(Polyhedron::Vertex_handle v : vertices(poly)) + for(Mesh::Vertex_handle v : vertices(poly)) { Point p = v->point(); max_coord = (std::max)(max_coord, CGAL::to_double(p.x())); @@ -33,14 +33,14 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/eight.off"); - Polyhedron poly; + Mesh poly; if(!PMP::IO::read_polygon_mesh(filename, poly) || CGAL::is_empty(poly) || !CGAL::is_triangle_mesh(poly)) { std::cerr << "Invalid input." << std::endl; return 1; } - CGAL::Side_of_triangle_mesh inside(poly); + CGAL::Side_of_triangle_mesh inside(poly); double size = max_coordinate(poly); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope.cpp index afbb938afb51..5cc9379992f8 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope.cpp @@ -9,13 +9,13 @@ int main(int argc, char* argv[]) { typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point_3; - typedef CGAL::Surface_mesh Surface_mesh; - typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef CGAL::Surface_mesh Mesh; + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; typedef CGAL::Polyhedral_envelope Envelope; std::ifstream in((argc>1) ? argv[1] : CGAL::data_file_path("meshes/blobby.off")); - Surface_mesh tmesh; + Mesh tmesh; in >> tmesh; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope_mesh_containment.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope_mesh_containment.cpp index 4e814c7dccd5..ede5edf61e8f 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope_mesh_containment.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/polyhedral_envelope_mesh_containment.cpp @@ -13,19 +13,19 @@ int main(int argc, char* argv[]) { typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point_3; - typedef CGAL::Surface_mesh Surface_mesh; + typedef CGAL::Surface_mesh Mesh; typedef CGAL::Polyhedral_envelope Envelope; std::ifstream in((argc>1) ? argv[1] : CGAL::data_file_path("meshes/blobby.off")); - Surface_mesh tmesh; + Mesh tmesh; in >> tmesh; // remesh the input using the longest edge size as target edge length - Surface_mesh query = tmesh; - Surface_mesh::Edge_iterator longest_edge_it = + Mesh query = tmesh; + Mesh::Edge_iterator longest_edge_it = std::max_element(edges(query).begin(), edges(query).end(), - [&query](Surface_mesh::Edge_index e1, Surface_mesh::Edge_index e2) + [&query](Mesh::Edge_index e1, Mesh::Edge_index e2) { return PMP::edge_length(halfedge(e1, query), query) < PMP::edge_length(halfedge(e2, query), query); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp index 742685e7485c..e043f6a9a770 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp @@ -10,9 +10,9 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; -typedef CGAL::Surface_mesh Surface_mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; @@ -20,7 +20,7 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/eight.off"); - Surface_mesh mesh; + Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh)) { std::cerr << "Invalid input." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp index 23053a6766c3..30f1ed16a14c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp @@ -13,8 +13,8 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Polyhedron_3 Polyhedron; -typedef Polyhedron::Vertex_handle Vertex_handle; +typedef CGAL::Polyhedron_3 Mesh; +typedef Mesh::Vertex_handle Vertex_handle; namespace PMP = CGAL::Polygon_mesh_processing; @@ -34,7 +34,7 @@ void extract_k_ring(Vertex_handle v, { v = qv[current_index++]; - Polyhedron::Halfedge_around_vertex_circulator e(v->vertex_begin()), e_end(e); + Mesh::Halfedge_around_vertex_circulator e(v->vertex_begin()), e_end(e); do { Vertex_handle new_v = e->opposite()->vertex(); if (D.insert(std::make_pair(new_v, dist_v + 1)).second) @@ -47,14 +47,14 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/blobby.off"); - Polyhedron poly; + Mesh poly; if(!PMP::IO::read_polygon_mesh(filename, poly) || !CGAL::is_triangle_mesh(poly)) { std::cerr << "Invalid input." << std::endl; return 1; } - std::vector new_facets; + std::vector new_facets; std::vector new_vertices; PMP::refine(poly, faces(poly), @@ -68,7 +68,7 @@ int main(int argc, char* argv[]) refined_off.close(); std::cout << "Refinement added " << new_vertices.size() << " vertices." << std::endl; - Polyhedron::Vertex_iterator v = poly.vertices_begin(); + Mesh::Vertex_iterator v = poly.vertices_begin(); std::advance(v, 82/*e.g.*/); std::vector region; extract_k_ring(v, 12/*e.g.*/, region); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_almost_planar_patches.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_almost_planar_patches.cpp index e3924c3e095c..381183d0c997 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_almost_planar_patches.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_almost_planar_patches.cpp @@ -14,13 +14,13 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point_3; -typedef CGAL::Surface_mesh Surface_mesh; +typedef CGAL::Surface_mesh Mesh; namespace PMP = CGAL::Polygon_mesh_processing; int main() { - Surface_mesh sm; + Mesh sm; CGAL::IO::read_polygon_mesh(CGAL::data_file_path("meshes/fandisk.off"), sm); //apply a perturbation to input vertices so that points are no longer coplanar @@ -51,7 +51,7 @@ int main() edge_is_constrained_map(CGAL::make_random_access_property_map(ecm))); // run the remeshing algorithm using filled properties - Surface_mesh out; + Mesh out; PMP::remesh_almost_planar_patches(sm, out, nb_regions, nb_corners, diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp index 9f591e6a2696..92aa3b15c6fd 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp @@ -12,12 +12,12 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point_3; -typedef CGAL::Surface_mesh Surface_mesh; +typedef CGAL::Surface_mesh Mesh; namespace PMP = CGAL::Polygon_mesh_processing; int main() { - Surface_mesh sm; + Mesh sm; CGAL::IO::read_polygon_mesh(CGAL::data_file_path("meshes/cube_quad.off"), sm); // triangulate faces; @@ -25,8 +25,8 @@ int main() std::cout << "Input mesh has " << faces(sm).size() << " faces" << std::endl; assert(faces(sm).size()==12); - Surface_mesh::Property_map ecm = - sm.add_property_map("ecm",false).first; + Mesh::Property_map ecm = + sm.add_property_map("ecm",false).first; // detect sharp edges of the cube PMP::detect_sharp_edges(sm, 60, ecm); @@ -37,7 +37,7 @@ int main() assert(faces(sm).size()>100); // decimate the mesh - Surface_mesh out; + Mesh out; PMP::remesh_planar_patches(sm, out); CGAL::IO::write_polygon_mesh("cube_decimated.off", out, CGAL::parameters::stream_precision(17)); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp index a7afc963ed70..28d770626e2c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp @@ -9,7 +9,7 @@ #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Polyhedron_3 Mesh; namespace PMP = CGAL::Polygon_mesh_processing; @@ -17,7 +17,7 @@ int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/quads_to_stitch.off"); - Polyhedron mesh; + Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh)) { std::cerr << "Invalid input." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example_OM.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example_OM.cpp index b731e8c02201..cf97918fd3b8 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example_OM.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example_OM.cpp @@ -10,8 +10,8 @@ #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; - typedef OpenMesh::PolyMesh_ArrayKernelT< > Mesh; + int main(int argc, char* argv[]) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/quads_to_stitch.off"); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp index 7587d0123638..9c7ef677bc0a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp @@ -11,7 +11,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point; -typedef CGAL::Surface_mesh Surface_mesh; +typedef CGAL::Surface_mesh Mesh; namespace PMP = CGAL::Polygon_mesh_processing; @@ -20,7 +20,7 @@ int main(int argc, char* argv[]) const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/P.off"); const char* outfilename = (argc > 2) ? argv[2] : "P_tri.off"; - Surface_mesh mesh; + Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh)) { std::cerr << "Error: Invalid input." << std::endl; @@ -41,7 +41,7 @@ int main(int argc, char* argv[]) PMP::triangulate_faces(mesh); // Confirm that all faces are triangles. - for(boost::graph_traits::face_descriptor f : faces(mesh)) + for(boost::graph_traits::face_descriptor f : faces(mesh)) { if(!CGAL::is_triangle(halfedge(f, mesh), mesh)) std::cerr << "Error: non-triangular face left in mesh." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_split_visitor_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_split_visitor_example.cpp index 9b246f7678df..84695b32e325 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_split_visitor_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_split_visitor_example.cpp @@ -6,15 +6,14 @@ #include #include -#include #include #include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef Kernel::Point_3 Point; -typedef CGAL::Surface_mesh Surface_mesh; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef Kernel::Point_3 Point; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::face_descriptor face_descriptor; class Insert_iterator { @@ -41,7 +40,7 @@ class Insert_iterator }; -struct Visitor : public CGAL::Polygon_mesh_processing::Triangulate_faces::Default_visitor +struct Visitor : public CGAL::Polygon_mesh_processing::Triangulate_faces::Default_visitor { typedef std::unordered_map Container; @@ -78,7 +77,7 @@ int main(int argc, char* argv[]) const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/P.off"); std::ifstream input(filename); - Surface_mesh mesh; + Mesh mesh; if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid off file." << std::endl; @@ -87,7 +86,7 @@ int main(int argc, char* argv[]) std::unordered_map t2q; - Surface_mesh copy; + Mesh copy; CGAL::copy_face_graph(mesh, copy, CGAL::parameters::face_to_face_output_iterator(Insert_iterator(t2q))); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/volume_connected_components.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/volume_connected_components.cpp index bd4181c3ff48..e07c803b83e6 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/volume_connected_components.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/volume_connected_components.cpp @@ -12,7 +12,7 @@ #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Surface_mesh Surface_mesh; +typedef CGAL::Surface_mesh Mesh; namespace PMP = CGAL::Polygon_mesh_processing; namespace params = CGAL::parameters; @@ -21,7 +21,7 @@ int main(int argc, char** argv) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/blobby.off"); - Surface_mesh mesh; + Mesh mesh; if(!PMP::IO::read_polygon_mesh(filename, mesh)) { std::cerr << "Invalid input." << std::endl; @@ -29,8 +29,8 @@ int main(int argc, char** argv) } // property map to assign a volume id for each face - Surface_mesh::Property_map vol_id_map = - mesh.add_property_map().first; + Mesh::Property_map vol_id_map = + mesh.add_property_map().first; // fill the volume id map std::vector err_codes; @@ -39,7 +39,7 @@ int main(int argc, char** argv) std::cout << "Found " << nb_vol << " volumes\n"; // write each volume in an OFF file - typedef CGAL::Face_filtered_graph Filtered_graph; + typedef CGAL::Face_filtered_graph Filtered_graph; Filtered_graph vol_mesh(mesh, 0, vol_id_map); for(std::size_t id = 0; id < nb_vol; ++id) { @@ -49,11 +49,12 @@ int main(int argc, char** argv) if(id > 0) vol_mesh.set_selected_faces(id, vol_id_map); - Surface_mesh out; + Mesh out; CGAL::copy_face_graph(vol_mesh, out); std::ostringstream oss; oss << "vol_" << id <<".off"; std::ofstream os(oss.str().data()); os << out; } + return 0; } From f042f5a8eb2559146df06b535808af25683d6fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 22 Nov 2023 16:13:21 +0100 Subject: [PATCH 088/133] Fix initialization warning --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index d3d2beb6c6e4..5adf81dc443a 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -197,11 +197,11 @@ class Alpha_wrapper_3 Alpha_wrapper_3(const Oracle& oracle) : -#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE - m_queue(4096), -#endif m_oracle(oracle), m_tr(Geom_traits(oracle.geom_traits())) +#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE + , m_queue(4096) +#endif { static_assert(std::is_floating_point::value); } From 7fdc36dbbef57506c9431f248c16ee3eeb1d1c58 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 23 Nov 2023 15:48:46 +0100 Subject: [PATCH 089/133] remove *_sizing_field criteria from test --- .../Mesh_3/test_mesh_criteria_creation.cpp | 84 ++++--------------- 1 file changed, 16 insertions(+), 68 deletions(-) diff --git a/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp b/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp index b81befd7a56a..fb74fa720e4b 100644 --- a/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp +++ b/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp @@ -75,28 +75,12 @@ int main() Mc ec1(edge_size = 1); assert( ec1.edge_criteria_object().sizing_field(bp1,1,index) == 1 ); - Mc ec2(edge_sizing_field = Esf(2)); + Mc ec2(edge_size = Esf(2)); assert( ec2.edge_criteria_object().sizing_field(bp1,1,index) == 2 ); - Mc ec3(edge_sizing_field = 3.); + Mc ec3(edge_size = 3.); assert( ec3.edge_criteria_object().sizing_field(bp1,1,index) == 3 ); - Mc ec4(edge_size = 4., - edge_sizing_field = Esf(5.)); - assert( ec4.edge_criteria_object().sizing_field(bp1,1,index) == 4. ); - - Mc ec5(sizing_field = 5.); - assert( ec5.edge_criteria_object().sizing_field(bp1,1,index) == 5 ); - - Mc ec6(sizing_field = 6., - edge_sizing_field = 7.); - assert( ec6.edge_criteria_object().sizing_field(bp1,1,index) == 7. ); - - Mc ec7(sizing_field = 7., - edge_size = 8.); - assert( ec7.edge_criteria_object().sizing_field(bp1,1,index) == 8. ); - - // ----------------------------------- // Test facet criteria // ----------------------------------- @@ -114,43 +98,25 @@ int main() Mc fc1(facet_size = facet_size_ok); assert( ! fc1.facet_criteria_object()(tr, f) ); - Mc fc2(facet_sizing_field = facet_size_ok); - assert( ! fc2.facet_criteria_object()(tr, f) ); - - Mc fc3(facet_sizing_field = Fsf(facet_size_ok)); + Mc fc3(facet_size = Fsf(facet_size_ok)); assert( ! fc3.facet_criteria_object()(tr, f) ); - Mc fc4(facet_sizing_field = facet_size_nok, - facet_size = facet_size_ok); - assert( ! fc4.facet_criteria_object()(tr, f) ); - - Mc fc5(sizing_field = facet_size_ok); - assert( ! fc5.facet_criteria_object()(tr, f) ); - - Mc fc6(facet_size = facet_size_ok, - facet_sizing_field = facet_size_nok, - sizing_field = facet_size_nok); - assert( ! fc6.facet_criteria_object()(tr, f) ); - - Mc fc7(facet_sizing_field = Fsf(facet_size_ok), - sizing_field = facet_size_nok); - assert( ! fc7.facet_criteria_object()(tr, f) ); - Mc fc8(facet_distance = 8.); Mc fc9(facet_angle = 9.); Mc fc10(facet_angle = 10.1, facet_distance = 10.2, facet_size = 10.3, - facet_min_size = 0.2, - facet_sizing_field = Fsf(10.4), - sizing_field = 10.5); + facet_min_size = 0.2); + Mc fc1Ob(facet_angle = 10.11, + facet_distance = 10.12, + facet_min_size = 0.3, + facet_size = Fsf(10.14)); // Test construction from int Mc fc11(facet_size = 11); Mc fc11b(facet_size = 11, facet_min_size = 1); - Mc fc12(facet_sizing_field = 12); - Mc fc12b(facet_sizing_field = 12, facet_min_size = 2); - Mc fc13(sizing_field = 13); + Mc fc12(facet_size = Fsf(12)); + Mc fc12b(facet_size = Fsf(12), facet_min_size = 1); // Test topological criterion creation Mc fc14(facet_topology = CGAL::FACET_VERTICES_ON_SURFACE); @@ -173,41 +139,23 @@ int main() Mc cc1(cell_size = cell_size_ok); assert( ! cc1.cell_criteria_object()(tr, ch) ); - Mc cc2(cell_sizing_field = cell_size_ok); - assert( ! cc2.cell_criteria_object()(tr, ch) ); - - Mc cc3(cell_sizing_field = Fsf(cell_size_ok)); + Mc cc3(cell_size = Fsf(cell_size_ok)); assert( ! cc3.cell_criteria_object()(tr, ch) ); - Mc cc4(cell_sizing_field = cell_size_nok, - cell_size = cell_size_ok); - assert( ! cc4.cell_criteria_object()(tr, ch) ); - - Mc cc5(sizing_field = cell_size_ok); - assert( ! cc5.cell_criteria_object()(tr, ch) ); - - Mc cc6(cell_size = cell_size_ok, - cell_sizing_field = cell_size_nok, - sizing_field = cell_size_nok); - assert( ! cc6.cell_criteria_object()(tr, ch) ); - - Mc cc7(cell_sizing_field = Csf(cell_size_ok), - sizing_field = cell_size_nok); + Mc cc7(cell_size = Csf(cell_size_ok)); assert( ! cc7.cell_criteria_object()(tr, ch) ); Mc cc8(cell_radius_edge_ratio = 8.); Mc cc9(cell_radius_edge_ratio = 9.1, - sizing_field = Csf(9.2) ); + cell_size = Csf(9.2) ); Mc cc10(cell_radius_edge_ratio = 10.1, cell_size = 10.2, + cell_min_size = 0.1); + Mc cc10b(cell_radius_edge_ratio = 10.1, cell_min_size = 0.1, - cell_sizing_field = Csf(10.3), - sizing_field = 10.4); + cell_size = Csf(10.3)); // Test construction from int Mc cc11(cell_size = 11); Mc cc11b(cell_size = 11, cell_min_size = 1); - Mc cc12(cell_sizing_field = 12); - Mc cc12b(cell_sizing_field = 12, cell_min_size = 2); - Mc cc13(sizing_field = 13); } From 25e597ac795e37dbc2326bac7ed1783766ef6c8b Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 23 Nov 2023 15:22:20 +0000 Subject: [PATCH 090/133] Poisson Surface Reconstruction: Enable Structural Filtering --- .../include/CGAL/Reconstruction_triangulation_3.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h b/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h index 9f605978f7ca..5b625f8042ec 100644 --- a/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h +++ b/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -148,6 +149,12 @@ struct Reconstruction_triangulation_default_geom_traits_3 : public BaseGt }; +template < class BaseGt > +struct Triangulation_structural_filtering_traits > { + typedef typename Triangulation_structural_filtering_traits::Use_structural_filtering_tag Use_structural_filtering_tag; +}; + + /// \internal /// The Reconstruction_triangulation_3 class /// provides the interface requested by the Poisson_reconstruction_function class: From 8f8280ce34531e9ba720a76096e6d219c56d0cce Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 23 Nov 2023 19:37:23 +0000 Subject: [PATCH 091/133] Add structural filtering to Robust circumcenter traits --- .../CGAL/Robust_weighted_circumcenter_filtered_traits_3.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Triangulation_3/include/CGAL/Robust_weighted_circumcenter_filtered_traits_3.h b/Triangulation_3/include/CGAL/Robust_weighted_circumcenter_filtered_traits_3.h index 0ab43248e21c..beddf4c0b3db 100644 --- a/Triangulation_3/include/CGAL/Robust_weighted_circumcenter_filtered_traits_3.h +++ b/Triangulation_3/include/CGAL/Robust_weighted_circumcenter_filtered_traits_3.h @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace CGAL { @@ -531,6 +532,13 @@ class Robust_circumcenter_filtered_traits_3 Robust_circumcenter_filtered_traits_3(const Kernel& k = Kernel()) : Kernel(k) { } }; + +template < class BaseGt > +struct Triangulation_structural_filtering_traits > { + typedef typename Triangulation_structural_filtering_traits::Use_structural_filtering_tag Use_structural_filtering_tag; +}; + + template class Robust_weighted_circumcenter_filtered_traits_3 : public Robust_circumcenter_filtered_traits_3 From 30fe1ed629dcd31fe7f30f39c57afd8d9305bffc Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 24 Nov 2023 11:16:05 +0100 Subject: [PATCH 092/133] shape criterion renamed --- .../test/Periodic_3_mesh_3/test_implicit_shapes_bunch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Periodic_3_mesh_3/test/Periodic_3_mesh_3/test_implicit_shapes_bunch.cpp b/Periodic_3_mesh_3/test/Periodic_3_mesh_3/test_implicit_shapes_bunch.cpp index f09fffd0d4f1..87669ceb91d5 100644 --- a/Periodic_3_mesh_3/test/Periodic_3_mesh_3/test_implicit_shapes_bunch.cpp +++ b/Periodic_3_mesh_3/test/Periodic_3_mesh_3/test_implicit_shapes_bunch.cpp @@ -230,7 +230,7 @@ int main() Periodic_mesh_criteria criteria(facet_angle = 30, facet_size = 0.05, facet_distance = 0.025, - cell_radius_edge = 2, + cell_radius_edge_ratio = 2, cell_size = 0.05); // Mesh generation From 65621c2e9e744b78f0889ab33b43ac63d4d8e5e0 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 27 Nov 2023 12:51:20 +0000 Subject: [PATCH 093/133] Spatial Searching: Add example storing triangulation vertices --- Spatial_searching/doc/Spatial_searching/examples.txt | 1 + Spatial_searching/examples/Spatial_searching/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/Spatial_searching/doc/Spatial_searching/examples.txt b/Spatial_searching/doc/Spatial_searching/examples.txt index defc30a2079e..8c3c7920ff77 100644 --- a/Spatial_searching/doc/Spatial_searching/examples.txt +++ b/Spatial_searching/doc/Spatial_searching/examples.txt @@ -11,6 +11,7 @@ \example Spatial_searching/searching_with_circular_query.cpp \example Spatial_searching/searching_surface_mesh_vertices.cpp \example Spatial_searching/searching_polyhedron_vertices.cpp +\example Spatial_searching/searching_triangulation_vertices.cpp \example Spatial_searching/searching_with_point_with_info.cpp \example Spatial_searching/searching_with_point_with_info_inplace.cpp \example Spatial_searching/searching_with_point_with_info_pmap.cpp diff --git a/Spatial_searching/examples/Spatial_searching/CMakeLists.txt b/Spatial_searching/examples/Spatial_searching/CMakeLists.txt index f9546507bd49..b273ac3477bf 100644 --- a/Spatial_searching/examples/Spatial_searching/CMakeLists.txt +++ b/Spatial_searching/examples/Spatial_searching/CMakeLists.txt @@ -23,6 +23,7 @@ create_single_source_cgal_program("searching_with_point_with_info_inplace.cpp") create_single_source_cgal_program("searching_with_point_with_info_pmap.cpp") create_single_source_cgal_program("searching_surface_mesh_vertices.cpp") create_single_source_cgal_program("searching_polyhedron_vertices.cpp") +create_single_source_cgal_program("searching_triangulation_vertices.cpp") create_single_source_cgal_program("searching_polyhedron_vertices_with_fuzzy_sphere.cpp") create_single_source_cgal_program("user_defined_point_and_distance.cpp") create_single_source_cgal_program("using_fair_splitting_rule.cpp") From c018e0fe7c4f6c28f4854756968738e93bbf618c Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 27 Nov 2023 12:54:26 +0000 Subject: [PATCH 094/133] The example itself --- .../searching_triangulation_vertices.cpp | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp diff --git a/Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp b/Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp new file mode 100644 index 000000000000..a045313f3f56 --- /dev/null +++ b/Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Delaunay_triangulation_3 Delaunay; +typedef Delaunay::Vertex_handle Vertex_handle; + + +struct Project { + typedef Vertex_handle argument_type; + typedef const Point_3& Point; + typedef Point result_type; + const Point& operator()( Vertex_handle v) const { return v->point(); } +}; + + +typedef boost::function_property_map Vertex_point_pmap; +typedef CGAL::Search_traits_3 Traits_base; +typedef CGAL::Search_traits_adapter Traits; +typedef CGAL::Orthogonal_k_neighbor_search K_neighbor_search; +typedef K_neighbor_search::Tree Tree; +typedef Tree::Splitter Splitter; +typedef K_neighbor_search::Distance Distance; + +int main(int argc, char* argv[]) +{ + std::ifstream in((argc>1)?argv[1]:CGAL::data_file_path("points_3/kitten.xyz")); + std::vector points; + Point_3 p; + while(in >> p){ + points.push_back(p); + } + + Delaunay dt(points.begin(), points.end()); + + const unsigned int K = 5; + + Project project; + Vertex_point_pmap vppmap(project); + + // Insert number_of_data_points in the tree + Tree tree(dt.finite_vertex_handles().begin(), dt.finite_vertex_handles().end(), Splitter(), Traits(vppmap)); + + // search K nearest neighbors + Point_3 query(0.0, 0.0, 0.0); + Distance tr_dist(vppmap); + + K_neighbor_search search(tree, query, K,0,true,tr_dist); + std::cout <<"The "<< K << " nearest vertices to the query point at (0,0,0) are:" << std::endl; + for(K_neighbor_search::iterator it = search.begin(); it != search.end(); it++){ + std::cout << "vertex " << &*(it->first) << " : " << vppmap[it->first] << " at distance " + << tr_dist.inverse_of_transformed_distance(it->second) << std::endl; + } + + return 0; +} From f36693c48e10dcb008a3916e4bae267964ffb2db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 28 Nov 2023 10:29:46 +0100 Subject: [PATCH 095/133] Fix warning --- .../Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index 383d1103778f..ddc84bc5002f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -217,7 +217,7 @@ struct AW3_interrupter_visitor { } template - constexpr bool go_further(const Wrapper& wrapper) + constexpr bool go_further(const Wrapper&) { return !(*should_stop); } From 6b570f767e9631bc02be240fd61deb6b15e2d693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 28 Nov 2023 17:45:54 +0100 Subject: [PATCH 096/133] fix sign --- .../include/CGAL/Kernel/function_objects.h | 2 +- .../test_approximate_dihedral_angle_3.cpp | 35 +++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 9b6af428e25b..bb476ded1f25 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -934,7 +934,7 @@ namespace CommonKernelFunctors { const double l_ab = CGAL::sqrt(CGAL::to_double(sq_distance(a,b))); const double y = l_ab * CGAL::to_double(scalar_product(ac,abad)); - return FT(std::atan2(y, x) * 180 / CGAL_PI ); + return -FT(std::atan2(y, x) * 180 / CGAL_PI ); } }; diff --git a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp index b39ce5c01e72..dfa703b86f7e 100644 --- a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp +++ b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp @@ -10,20 +10,41 @@ struct query { double expected_angle; }; +void sign_test() +{ + K::Point_3 a(0,0,0), b(1,0,0), c(0,1, 0), d(0,0,1); + + assert( CGAL::approximate_dihedral_angle(a, b, c, d) > 0); + assert( CGAL::approximate_dihedral_angle(c, a, b, d) > 0); + assert( CGAL::approximate_dihedral_angle(a, d, b, c) > 0); + assert( CGAL::approximate_dihedral_angle(c, b, d, a) > 0); + assert( CGAL::approximate_dihedral_angle(d, b, a, c) > 0); + assert( CGAL::approximate_dihedral_angle(d, c, b, a) > 0); + + assert( CGAL::approximate_dihedral_angle(a, b, d, c) < 0); + assert( CGAL::approximate_dihedral_angle(c, a, d, b) < 0); + assert( CGAL::approximate_dihedral_angle(a, d, c, b) < 0); + assert( CGAL::approximate_dihedral_angle(c, b, a, d) < 0); + assert( CGAL::approximate_dihedral_angle(d, b, c, a) < 0); + assert( CGAL::approximate_dihedral_angle(d, c, a, b) < 0); +} + int main() { + sign_test(); + Point_3 a = {0, 0, 0}; Point_3 b = {0, 1, 0}; Point_3 c = {1, 0, 0}; const query queries[] = { { { 1, 0, 0}, 0.}, - { { 1, 0, 1}, 45.}, - { { 0, 0, 1}, 90.}, - { { -1, 0, 1}, 135.}, - { { -1, 0, 0}, 180.}, - { { -1, 0, -1}, -135.}, - { { 0, 0, -1}, -90.}, - { { 1, 0, -1}, -45.}, + { { 1, 0, 1}, -45.}, + { { 0, 0, 1}, -90.}, + { { -1, 0, 1}, -135.}, + { { -1, 0, 0}, -180.}, + { { -1, 0, -1}, 135.}, + { { 0, 0, -1}, 90.}, + { { 1, 0, -1}, 45.}, }; for(auto query: queries) { From abbbb53096037c75c3ffa4da3fed159406ab3827 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Wed, 29 Nov 2023 11:03:50 +0100 Subject: [PATCH 097/133] added missing dependency to OSQP when default solver is used --- .../include/CGAL/Shape_regularization/regularize_segments.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Shape_regularization/include/CGAL/Shape_regularization/regularize_segments.h b/Shape_regularization/include/CGAL/Shape_regularization/regularize_segments.h index 2042cff97b52..ad290801019a 100644 --- a/Shape_regularization/include/CGAL/Shape_regularization/regularize_segments.h +++ b/Shape_regularization/include/CGAL/Shape_regularization/regularize_segments.h @@ -70,6 +70,9 @@ namespace Segments { that should be addressed. The function is based on the class `QP_regularization`. Please refer to that class and these concepts for more information. + This class requires a `QPSolver` model which defaults to the \ref thirdpartyOSQP "OSQP" + library, which must be available on the system. + \tparam InputRange a model of `ConstRange` whose iterator type is `RandomAccessIterator` From 0145bafbc5079ea98e91f82d528220a7ce91123a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 29 Nov 2023 12:22:46 +0100 Subject: [PATCH 098/133] update formula will add comments in a upcoming commit --- Kernel_23/include/CGAL/Kernel/function_objects.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index bb476ded1f25..ab23552b6821 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -930,11 +930,12 @@ namespace CommonKernelFunctors { const Vector_3 ad = vector(a,d); const Vector_3 abad = cross_product(ab,ad); - const double x = CGAL::to_double(scalar_product(cross_product(ab,ac), abad)); + const Vector_3 abac = cross_product(ab,ac); const double l_ab = CGAL::sqrt(CGAL::to_double(sq_distance(a,b))); - const double y = l_ab * CGAL::to_double(scalar_product(ac,abad)); + const double y = l_ab * CGAL::to_double(scalar_product(abac, abad)); + const double z = CGAL::to_double(scalar_product(cross_product(ab,abac),abad)); - return -FT(std::atan2(y, x) * 180 / CGAL_PI ); + return FT(std::atan2(z, y) * 180 / CGAL_PI ); } }; From 0e3f3a33d1165fa1462f4cabd6973c9a87cb6e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 29 Nov 2023 12:27:34 +0100 Subject: [PATCH 099/133] test to be fixed --> tetra orientation is 0 --- Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp index dfa703b86f7e..ec352fb21ddb 100644 --- a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp +++ b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp @@ -41,7 +41,7 @@ int main() { { { 1, 0, 1}, -45.}, { { 0, 0, 1}, -90.}, { { -1, 0, 1}, -135.}, - { { -1, 0, 0}, -180.}, + //{ { -1, 0, 0}, -180.}, { { -1, 0, -1}, 135.}, { { 0, 0, -1}, 90.}, { { 1, 0, -1}, 45.}, From 5879bb72c63a5a8f0a15a75da806778c6ad20dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 29 Nov 2023 13:11:21 +0100 Subject: [PATCH 100/133] add comments about the formula --- .../include/CGAL/Kernel/function_objects.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index ab23552b6821..73f6c672d155 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -931,6 +931,23 @@ namespace CommonKernelFunctors { const Vector_3 abad = cross_product(ab,ad); const Vector_3 abac = cross_product(ab,ac); + + // The dihedral angle we are interested in is the angle around the edge ab which is + // the same as the angle between the vectors abac and abad + // (abac points inside the tetra abcd if its orientation is positive and outside otherwise) + // In order to increase the numerical precision of the computation, we consider the + // vector abad in the basis defined by (ab, abac, ab^abac). + // In this basis, adab=(ab * abad, abac * abad, [ab^abac] * abad), as all basis vector are orthogonal. + // We have ab * abad = 0, so in the plane (zy) of the new basis + // the dihedral angle is the angle between the z axis and abad + // which is the arctan of y/z (up to normalization) + // (Note that ab^abac is in the plane abc, pointing inside the tetra if its orientation is positive and outside otherwise). + // For the normalization, abad appears in both scalar products + // in the quotient so we can ignore its norm. For the second + // terms of the scalar products, we are left with ab^abac and abac. + // Since ab and abac are orthogonal the sinus of the angle between the vector is 1 + // so the norms are ||ab||.||abac|| vs ||abac||, which is why we have a multiplication by ||ab|| + // in y below. const double l_ab = CGAL::sqrt(CGAL::to_double(sq_distance(a,b))); const double y = l_ab * CGAL::to_double(scalar_product(abac, abad)); const double z = CGAL::to_double(scalar_product(cross_product(ab,abac),abad)); From 4bed66e82f142e02066ade584e27e93f5f136559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 29 Nov 2023 13:17:10 +0100 Subject: [PATCH 101/133] fix description --- Kernel_23/include/CGAL/Kernel/function_objects.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 73f6c672d155..55620fd2ed33 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -937,11 +937,11 @@ namespace CommonKernelFunctors { // (abac points inside the tetra abcd if its orientation is positive and outside otherwise) // In order to increase the numerical precision of the computation, we consider the // vector abad in the basis defined by (ab, abac, ab^abac). - // In this basis, adab=(ab * abad, abac * abad, [ab^abac] * abad), as all basis vector are orthogonal. - // We have ab * abad = 0, so in the plane (zy) of the new basis - // the dihedral angle is the angle between the z axis and abad + // In this basis, adab=(ab * abad, abac * abad, [ab^abac] * abad), as all basis vectors are orthogonal. + // We have ab * abad = 0, so in the plane (yz) of the new basis + // the dihedral angle is the angle between the y axis and abad // which is the arctan of y/z (up to normalization) - // (Note that ab^abac is in the plane abc, pointing inside the tetra if its orientation is positive and outside otherwise). + // (Note that ab^abac is in the plane abc, pointing outside the tetra if its orientation is positive and inside otherwise). // For the normalization, abad appears in both scalar products // in the quotient so we can ignore its norm. For the second // terms of the scalar products, we are left with ab^abac and abac. From e3e5bcd34448a62c7e8d5e129ea8041dff359560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 29 Nov 2023 15:25:44 +0100 Subject: [PATCH 102/133] accomodate handle sign face orientation was inversed and somehow matched the bug in the dihedral angle computation function --- .../internal/Surface_mesh_segmentation.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Surface_mesh_segmentation/include/CGAL/Surface_mesh_segmentation/internal/Surface_mesh_segmentation.h b/Surface_mesh_segmentation/include/CGAL/Surface_mesh_segmentation/internal/Surface_mesh_segmentation.h index d0a77fa1a78e..a2a2228f6f59 100644 --- a/Surface_mesh_segmentation/include/CGAL/Surface_mesh_segmentation/internal/Surface_mesh_segmentation.h +++ b/Surface_mesh_segmentation/include/CGAL/Surface_mesh_segmentation/internal/Surface_mesh_segmentation.h @@ -324,8 +324,8 @@ class Surface_mesh_segmentation CGAL_precondition( (! (face(edge,mesh)==boost::graph_traits::null_face())) && (! (face(opposite(edge,mesh),mesh)==boost::graph_traits::null_face())) ); - const Point a = get(vertex_point_pmap,target(edge,mesh)); - const Point b = get(vertex_point_pmap,target(prev(edge,mesh),mesh)); + const Point a = get(vertex_point_pmap,source(edge,mesh)); + const Point b = get(vertex_point_pmap,target(edge,mesh)); const Point c = get(vertex_point_pmap,target(next(edge,mesh),mesh)); const Point d = get(vertex_point_pmap,target(next(opposite(edge,mesh),mesh),mesh)); // As far as I check: if, say, dihedral angle is 5, this returns 175, From df4eed9302f873bf92f30941c9d7de374b69be14 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Wed, 29 Nov 2023 15:27:57 +0100 Subject: [PATCH 103/133] add tests for the dihedral angle --- Data/data/meshes/regular_tetrahedron.off | 11 ++++ .../include/CGAL/Kernel/function_objects.h | 37 +++++++---- .../test_approximate_dihedral_angle_3.cpp | 66 ++++++++++++++----- 3 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 Data/data/meshes/regular_tetrahedron.off diff --git a/Data/data/meshes/regular_tetrahedron.off b/Data/data/meshes/regular_tetrahedron.off new file mode 100644 index 000000000000..08a25ad43b38 --- /dev/null +++ b/Data/data/meshes/regular_tetrahedron.off @@ -0,0 +1,11 @@ +OFF +4 4 0 +-1 0 -0.707107 +1 0 -0.707107 +0 -1 0.707107 +0 1 0.707107 +3 0 1 2 +3 0 3 1 +3 0 2 3 +3 1 3 2 + diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 55620fd2ed33..6bc98833dab4 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -932,22 +932,35 @@ namespace CommonKernelFunctors { const Vector_3 abad = cross_product(ab,ad); const Vector_3 abac = cross_product(ab,ac); - // The dihedral angle we are interested in is the angle around the edge ab which is - // the same as the angle between the vectors abac and abad + // The dihedral angle we are interested in is the angle around the oriented + // edge ab which is the same (in absolute value) as the angle between the + // vectors ab^ac and ab^ad (cross-products). // (abac points inside the tetra abcd if its orientation is positive and outside otherwise) - // In order to increase the numerical precision of the computation, we consider the - // vector abad in the basis defined by (ab, abac, ab^abac). - // In this basis, adab=(ab * abad, abac * abad, [ab^abac] * abad), as all basis vectors are orthogonal. - // We have ab * abad = 0, so in the plane (yz) of the new basis - // the dihedral angle is the angle between the y axis and abad - // which is the arctan of y/z (up to normalization) - // (Note that ab^abac is in the plane abc, pointing outside the tetra if its orientation is positive and inside otherwise). + // + // We consider the vector abad in the basis defined by the three vectors + // (, , ) + // where denote the normalized vector u/|u|. + // + // In this orthonormal basis, the vector adab has the coordinates + // x = * abad + // y = * abad + // z = * abad + // We have x == 0, because abad and ab are orthogonal, and then abad is in + // the plane (yz) of the new basis. + // + // In that basic, the dihedral angle is the angle between the y axis and abad + // which is the arctan of y/z, or atan2(z, y). + // + // (Note that ab^abac is in the plane abc, pointing outside the tetra if + // its orientation is positive and inside otherwise). + // // For the normalization, abad appears in both scalar products // in the quotient so we can ignore its norm. For the second // terms of the scalar products, we are left with ab^abac and abac. - // Since ab and abac are orthogonal the sinus of the angle between the vector is 1 - // so the norms are ||ab||.||abac|| vs ||abac||, which is why we have a multiplication by ||ab|| - // in y below. + // Since ab and abac are orthogonal, the sinus of the angle between the + // two vectors is 1. + // So the norms are |ab|.|abac| vs |abac|, which is why we have a + // multiplication by |ab| in y below. const double l_ab = CGAL::sqrt(CGAL::to_double(sq_distance(a,b))); const double y = l_ab * CGAL::to_double(scalar_product(abac, abad)); const double z = CGAL::to_double(scalar_product(cross_product(ab,abac),abad)); diff --git a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp index ec352fb21ddb..9ad255befacc 100644 --- a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp +++ b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp @@ -29,29 +29,65 @@ void sign_test() assert( CGAL::approximate_dihedral_angle(d, c, a, b) < 0); } +auto almost_equal_angle(double a, double b) { + return std::min(std::abs(a - b), std::abs(a + 360 - b)) < 0.1; +} + +void test_regular_tetrahedron() +{ + auto half_root_of_2 = std::sqrt(2) / 2; + + // Regular tetrahedron + Point_3 a{ -1, 0, -half_root_of_2}; + Point_3 b{ 1, 0, -half_root_of_2}; + Point_3 c{ 0, 1, half_root_of_2}; + Point_3 d{ 0, -1, half_root_of_2}; + assert(orientation(a, b, c, d) == CGAL::POSITIVE); + assert(almost_equal_angle(CGAL::approximate_dihedral_angle(a, b, c, d), 70.5288)); +} + int main() { + std::cout.precision(17); sign_test(); + test_regular_tetrahedron(); Point_3 a = {0, 0, 0}; - Point_3 b = {0, 1, 0}; - Point_3 c = {1, 0, 0}; + Point_3 b = {0, -1, 0}; // ab is oriented so that it sees the plan xz positively. + [[maybe_unused]] Point_3 c = {1, 0, 0}; + // c can be any point in the half-plane xy, with x>0 const query queries[] = { { { 1, 0, 0}, 0.}, - { { 1, 0, 1}, -45.}, - { { 0, 0, 1}, -90.}, - { { -1, 0, 1}, -135.}, - //{ { -1, 0, 0}, -180.}, - { { -1, 0, -1}, 135.}, - { { 0, 0, -1}, 90.}, - { { 1, 0, -1}, 45.}, + { { 1, 0, 1}, 45.}, + { { 0, 0, 1}, 90.}, + { { -1, 0, 1}, 135.}, + { { -1, 0, 0}, 180.}, + { { -1, 0, -1}, -135.}, + { { 0, 0, -1}, -90.}, + { { 1, 0, -1}, -45.}, }; - for(auto query: queries) { - const auto& expected = query.expected_angle; - const auto& p = query.p; - auto approx = CGAL::approximate_dihedral_angle(a, b, c, p); - std::cout << approx << " -- " << expected << '\n'; - assert( std::abs(approx - expected) < 0.1 ); + auto cnt = 0u; + for(double yc = -10; yc < 10; yc += 0.1) { + Point_3 c{1, yc, 0}; + // std::cout << "c = " << c << '\n'; + for(const auto& query : queries) { + for(double yp = -10; yp < 10; yp += 0.3) { + const auto& expected = query.expected_angle; + const Point_3 p{query.p.x(), yp, query.p.z()}; + // std::cout << "p = " << p << '\n'; + auto approx = CGAL::approximate_dihedral_angle(a, b, c, p); + // std::cout << approx << " -- " << expected << '\n'; + if(!almost_equal_angle(approx, expected)) { + std::cout << "ERROR:\n"; + std::cout << "CGAL::approximate_dihedral_angle(" << a << ", " << b << ", " << c << ", " << p << ") = " << approx << '\n'; + std::cout << "expected: " << expected << '\n'; + return 1; + } + ++cnt; + } + } } + std::cout << "OK (" << cnt << " tests)\n"; + assert(cnt > 10000); } From 46877d41341d7426ec67aeded87530988a882299 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Wed, 29 Nov 2023 15:34:36 +0100 Subject: [PATCH 104/133] fix two typos --- Kernel_23/include/CGAL/Kernel/function_objects.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 6bc98833dab4..7848f55e94c8 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -945,10 +945,10 @@ namespace CommonKernelFunctors { // x = * abad // y = * abad // z = * abad - // We have x == 0, because abad and ab are orthogonal, and then abad is in + // We have x == 0, because abad and ab are orthogonal, and thus abad is in // the plane (yz) of the new basis. // - // In that basic, the dihedral angle is the angle between the y axis and abad + // In that basis, the dihedral angle is the angle between the y axis and abad // which is the arctan of y/z, or atan2(z, y). // // (Note that ab^abac is in the plane abc, pointing outside the tetra if From 7b7918947ad3e99b3d046013da409a71a3ff48e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 29 Nov 2023 16:54:43 +0100 Subject: [PATCH 105/133] Fix bbox initialization --- .../Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index db6845db100c..91390c759ddb 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -646,6 +646,13 @@ public Q_SLOTS: std::cout << segments.size() << " edges" << std::endl; std::cout << points.size() << " points" << std::endl; + if(!triangles.empty()) + m_wrap_bbox = triangles.front().bbox(); + else if(!segments.empty()) + m_wrap_bbox = segments.front().bbox(); + else if(!points.empty()) + m_wrap_bbox = points.front().bbox(); + for(const Kernel::Triangle_3& tr : triangles) m_wrap_bbox += tr.bbox(); for(const Kernel::Segment_3& sg : segments) From bef03396715f48b90cdbd5ab414a9817334e16db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 29 Nov 2023 17:43:17 +0100 Subject: [PATCH 106/133] fixes for edges entirely on the isoline --- .../refine_mesh_at_isolevel.h | 27 +++++--- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../test_isolevel_refinement.cpp | 68 +++++++++++++++++++ 3 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_isolevel_refinement.cpp diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index 293d791a47cd..2c91a8ad5efe 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -93,27 +93,24 @@ void refine_mesh_at_isolevel(PolygonMesh& pm, std::unordered_map > faces_to_split; std::vector to_split; + std::unordered_set vertices_on_isoline; for (edge_descriptor e : edges(pm)) { vertex_descriptor src = source(e, pm), tgt = target(e, pm); + if (get(value_map, src)==isovalue) { - for (halfedge_descriptor h : halfedges_around_source(halfedge(e, pm), pm)) + vertices_on_isoline.insert(src); + if (get(value_map, tgt)==isovalue) { - face_descriptor f = face(h, pm); - if (f!=boost::graph_traits::null_face()) - faces_to_split[f].push_back(opposite(h, pm)); + put(ecm, e, true); // special case for faces entirely on an isovalue + continue; } continue; } if (get(value_map, tgt)==isovalue) { - for (halfedge_descriptor h : halfedges_around_target(halfedge(e, pm), pm)) - { - face_descriptor f = face(h, pm); - if (f!=boost::graph_traits::null_face()) - faces_to_split[f].push_back(h); - } + vertices_on_isoline.insert(tgt); continue; } if ( (get(value_map, tgt) < isovalue) != (get(value_map, src) < isovalue) ) @@ -140,6 +137,16 @@ void refine_mesh_at_isolevel(PolygonMesh& pm, faces_to_split[f].push_back(hnew); } + for (vertex_descriptor vh : vertices_on_isoline) + { + for (halfedge_descriptor h : halfedges_around_target(vh, pm)) + { + face_descriptor f = face(h, pm); + if (f!=boost::graph_traits::null_face()) + faces_to_split[f].push_back(h); + } + } + for (const auto& p : faces_to_split) { if(p.second.size()!=2) continue; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index eb9b98cbe593..f2e13399444a 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -65,6 +65,7 @@ create_single_source_cgal_program("triangulate_hole_with_cdt_2_test.cpp") create_single_source_cgal_program("test_pmp_polyhedral_envelope.cpp") create_single_source_cgal_program("test_pmp_np_function.cpp") create_single_source_cgal_program("test_degenerate_pmp_clip_split_corefine.cpp") +create_single_source_cgal_program("test_isolevel_refinement.cpp") # create_single_source_cgal_program("test_pmp_repair_self_intersections.cpp") find_package(Eigen3 3.2.0 QUIET) #(requires 3.2.0 or greater) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_isolevel_refinement.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_isolevel_refinement.cpp new file mode 100644 index 000000000000..9e07c8314352 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_isolevel_refinement.cpp @@ -0,0 +1,68 @@ +#include +#include + +#include +#include + +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Surface_mesh Triangle_mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; + +typedef Triangle_mesh::Property_map Vertex_distance_map; + +int main() +{ + const std::string filename = CGAL::data_file_path("meshes/elephant.off"); + + Triangle_mesh tm; + if(!CGAL::IO::read_polygon_mesh(filename, tm) || + CGAL::is_empty(tm) || !CGAL::is_triangle_mesh(tm)) + { + std::cerr << "Invalid input file." << std::endl; + return EXIT_FAILURE; + } + //property map for the distance values to the source set + Vertex_distance_map vertex_distance = tm.add_property_map("v:distance", 5).first; + std::vector zero_vids={ + /*a closed polyline*/ 2144,145,2690,1752,339,215,1395,338,77,2145,2052,2054,343,1936,22,1751,214,1499,142,358,2694,1750,301,65,59,2650,2060,205,2651,2061,2490,1939,898,13,298, + /*two adjacent triangles*/ 532, 185, 534, 2735, + /*another patch with missing crossed edges*/134,73,1883,2533,72,532,185,131,534 + }; + + std::vector minus_vids = {132, 364}; + + for (int i : zero_vids) + put(vertex_distance, Triangle_mesh::Vertex_index(i), 0); + for (int i : minus_vids) + put(vertex_distance, Triangle_mesh::Vertex_index(i), -5); + + // property map to flag new cut edge added in the mesh + auto ecm = tm.add_property_map("e:is_constrained", 0).first; + + CGAL::Polygon_mesh_processing::refine_mesh_at_isolevel(tm, vertex_distance, 0, CGAL::parameters::edge_is_constrained_map(ecm)); + + std::ofstream debug("edges.polylines.txt"); + for (Triangle_mesh::Edge_index e : edges(tm)) + if (get(ecm, e)) + debug << "2 " << tm.point(source(e, tm)) << " " << tm.point(target(e, tm)) << "\n"; + debug.close(); + + // split the mesh in connected components bounded by the isocurves + std::vector edges_split; + CGAL::Polygon_mesh_processing::split_connected_components(tm, edges_split, CGAL::parameters::edge_is_constrained_map(ecm)); + + // export each submesh in a file + for(std::size_t i=0; i Date: Thu, 30 Nov 2023 09:20:53 +0100 Subject: [PATCH 107/133] protect from macro substitution Co-authored-by: Andreas Fabri --- Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp index 9ad255befacc..dc3ccdaf9899 100644 --- a/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp +++ b/Kernel_23/test/Kernel_23/test_approximate_dihedral_angle_3.cpp @@ -30,7 +30,7 @@ void sign_test() } auto almost_equal_angle(double a, double b) { - return std::min(std::abs(a - b), std::abs(a + 360 - b)) < 0.1; + return (std::min)(std::abs(a - b), std::abs(a + 360 - b)) < 0.1; } void test_regular_tetrahedron() From fd37bc3a16070374bfbeaf83ab5e34336a0dff77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 30 Nov 2023 09:25:04 +0100 Subject: [PATCH 108/133] add missing include --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index 2c91a8ad5efe..eb52b7816679 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -18,6 +18,8 @@ #include #include +#include + namespace CGAL { namespace Polygon_mesh_processing { From a207e3af2e118400b15f0946dc06606a814fc7bc Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Thu, 30 Nov 2023 09:35:56 +0100 Subject: [PATCH 109/133] wrong header Co-authored-by: Andreas Fabri --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index eb52b7816679..cc0738a365bb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -17,7 +17,8 @@ #include #include - +#include +#include #include namespace CGAL { From 8a4c99f19b4942c0bd6e8f1083004013c9c58dee Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 30 Nov 2023 09:53:04 +0100 Subject: [PATCH 110/133] remove unused variables now there is only one possible sizing definition left, they have become useless --- Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp b/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp index fb74fa720e4b..8436b51c64d9 100644 --- a/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp +++ b/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp @@ -93,7 +93,6 @@ int main() cp(tr.point(ch, k+3)))); FT facet_size_ok = radius_facet*FT(10); - FT facet_size_nok = radius_facet/FT(10); Mc fc1(facet_size = facet_size_ok); assert( ! fc1.facet_criteria_object()(tr, f) ); @@ -134,7 +133,6 @@ int main() cp(tr.point(ch, 3)))); FT cell_size_ok = radius_cell*FT(10); - FT cell_size_nok = radius_cell/FT(10); Mc cc1(cell_size = cell_size_ok); assert( ! cc1.cell_criteria_object()(tr, ch) ); From c7ab2ba750bdad57977d79cb652f0df019cb58eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 30 Nov 2023 09:50:40 +0100 Subject: [PATCH 111/133] fix include --- .../CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h index cc0738a365bb..d86b470a2605 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/refine_mesh_at_isolevel.h @@ -17,9 +17,9 @@ #include #include + #include #include -#include namespace CGAL { namespace Polygon_mesh_processing { From 6ad37cd2e6e7526f7cd562db10c91e19036d3b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 30 Nov 2023 11:37:48 +0100 Subject: [PATCH 112/133] Enable pocket purging by default Reasoning is: this is what users expect. --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 5adf81dc443a..727691a80218 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -283,8 +283,9 @@ class Alpha_wrapper_3 // initial cavities, if used). // // -- Warning -- - // If you refine or pause while removing pockets, you will get valid but different wraps. - const bool keep_inner_ccs = choose_parameter(get_parameter(in_np, internal_np::keep_inner_connected_components), true); + // Pockets of "outside" cells will be purged even if the wrapping is interrupted (and + // this option is enabled). + const bool keep_inner_ccs = choose_parameter(get_parameter(in_np, internal_np::keep_inner_connected_components), false); // This parameter enables avoiding recomputing the triangulation from scratch when wrapping // the same input for multiple values of alpha (and typically the same offset values). From fae9bcd5f1d39a090aeb97f790e21abd9bb10154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 30 Nov 2023 11:38:18 +0100 Subject: [PATCH 113/133] Add some comments --- .../include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 727691a80218..d6ca4fb356c3 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -94,6 +94,7 @@ struct Wrapping_default_visitor template void on_flood_fill_begin(const AlphaWrapper&) { } + // Whether the flood filling process should continue template constexpr bool go_further(const Wrapper&) { return true; } @@ -277,6 +278,10 @@ class Alpha_wrapper_3 // Whether or not some cells should be reflagged as "inside" after the refinement+carving loop // as ended, as to ensure that the result is not only combinatorially manifold, but also // geometrically manifold. + // + // -- Warning -- + // Manifoldness postprocessing will be performed even if the wrapping is interrupted (and + // this option is enabled). const bool do_enforce_manifoldness = choose_parameter(get_parameter(in_np, internal_np::do_enforce_manifoldness), true); // Whether to keep pockets of "outside" cells that are not connected to the exterior (or to the From 642ea59de7133f7d4847aab74e0d68c50e0354bf Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 1 Dec 2023 10:21:57 +0100 Subject: [PATCH 114/133] add tooltip for bounds of approximation value --- Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp index b75f648be33e..6056951eba95 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp @@ -610,6 +610,8 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, ui.approx->setRange(diag * 10e-7, // min diag); // max ui.approx->setValue(approx); + ui.approx->setToolTip(tr("Approximation error: in [%1; %2]") + .arg(diag * 10e-7).arg(diag)); ui.protect->setEnabled(features_protection_available); ui.protect->setChecked(features_protection_available); From 1ca77d32afa89ef18c065dce44dc95e39d662f10 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 1 Dec 2023 10:23:44 +0100 Subject: [PATCH 115/133] fix DoubleEdit with Qt6 - let the user add as many digits as wanted (using -1 in setRange) - use standard notation, not scientific (which was the default) - comment QDoubleValidator::fixup that for some reason blocks the edition of the field --- Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp index a50aef4180b2..c452186e1fa5 100644 --- a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp +++ b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp @@ -9,13 +9,14 @@ class DoubleValidator : public QDoubleValidator : QDoubleValidator(parent) { setLocale(QLocale::C); + setNotation(QDoubleValidator::StandardNotation); } void fixup ( QString & input ) const { input.replace(".", locale().decimalPoint()); input.replace(",", locale().decimalPoint()); - QDoubleValidator::fixup(input); +// QDoubleValidator::fixup(input); } QValidator::State validate ( QString & input, int & pos ) const { @@ -59,7 +60,7 @@ class DoubleValidator : public QDoubleValidator void DoubleEdit::setRange(double rmin, double rmax) { - this->validator->setRange(rmin, rmax, this->validator->decimals()); + this->validator->setRange(rmin, rmax, -1); } double DoubleEdit::getValue() From 3fc14d8d56e4fb2649fc63a5173e8c2042276d54 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 1 Dec 2023 11:22:39 +0100 Subject: [PATCH 116/133] use QDoubleValidator::fixup() in DoubleEdit::fixup() with this version the user can write with scientific notation or standard notation, using . or , Note that when input is invalid, value() returns 0 --- Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp index c452186e1fa5..9f6f4c9b5a27 100644 --- a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp +++ b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp @@ -9,18 +9,16 @@ class DoubleValidator : public QDoubleValidator : QDoubleValidator(parent) { setLocale(QLocale::C); - setNotation(QDoubleValidator::StandardNotation); } void fixup ( QString & input ) const { input.replace(".", locale().decimalPoint()); input.replace(",", locale().decimalPoint()); -// QDoubleValidator::fixup(input); + QDoubleValidator::fixup(input); } QValidator::State validate ( QString & input, int & pos ) const { - fixup(input); return QDoubleValidator::validate(input, pos); } }; From f9e405f00454c72c7aff02dda0d232e4c5dfb0ae Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 1 Dec 2023 11:20:12 +0000 Subject: [PATCH 117/133] Adress warning --- .../Spatial_searching/searching_triangulation_vertices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp b/Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp index a045313f3f56..0dfd38e71e1e 100644 --- a/Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp +++ b/Spatial_searching/examples/Spatial_searching/searching_triangulation_vertices.cpp @@ -19,7 +19,7 @@ struct Project { typedef Vertex_handle argument_type; typedef const Point_3& Point; typedef Point result_type; - const Point& operator()( Vertex_handle v) const { return v->point(); } + Point operator()( Vertex_handle v) const { return v->point(); } }; From 07f2f2912bc177a72ea229647a575fe0f10f8fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 1 Dec 2023 22:08:15 +0100 Subject: [PATCH 118/133] Fix exit codes in benchmark scripts --- .../Robustness/compute_robustness_benchmark_data.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py index 9def2bb6cc16..afd8d6912ab2 100755 --- a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/compute_robustness_benchmark_data.py @@ -56,18 +56,18 @@ def compute_robustness_benchmark_data(execname, filename, alpha, max_time): for output_line in output.split("\n"): if output_line == "Command terminated by signal 11": - exit_code = 9 + exit_code = 10 continue elif output_line == "Command terminated by signal 6": - exit_code = 10 + exit_code = 11 continue elif output_line == "Command terminated by signal 8": - exit_code = 11 + exit_code = 12 continue except subprocess.TimeoutExpired: os.killpg(os.getpgid(proc.pid), signal.SIGTERM) - exit_code = 12 + exit_code = 13 output = "process ran too long" print(exit_codes[exit_code]) From ac3f6e689228562f6f814a1acb1e80270a8dc281 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 4 Dec 2023 13:09:22 +0100 Subject: [PATCH 119/133] improve the Mesh_3 log in demo --- .../Mesh_3/Mesh_3_plugin_cgal_code.cpp | 7 ++- .../Polyhedron/Plugins/Mesh_3/Mesh_function.h | 48 +++++++++++++------ 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp index abc82f150339..d48aef5bb1f9 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp @@ -134,6 +134,8 @@ Meshing_thread* cgal_code_mesh_3(QList pMeshes, param.manifold = manifold; param.protect_features = protect_features || protect_borders; param.use_sizing_field_with_aabb_tree = polylines.empty() && protect_features; + param.image_3_ptr = nullptr; + param.weights_ptr = nullptr; typedef ::Mesh_function Mesh_function; @@ -237,6 +239,8 @@ Meshing_thread* cgal_code_mesh_3(const QList pMeshes, param.manifold = manifold; param.protect_features = protect_features || protect_borders; param.use_sizing_field_with_aabb_tree = protect_features; + param.image_3_ptr = nullptr; + param.weights_ptr = nullptr; typedef ::Mesh_function Mesh_function; @@ -292,7 +296,8 @@ Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface* pfunction, param.manifold = manifold; param.detect_connected_components = false; // to avoid random values // in the debug displays - + param.image_3_ptr = nullptr; + param.weights_ptr = nullptr; typedef ::Mesh_function Mesh_function; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h index dfd31aadd849..8bc5a6c3ff68 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h @@ -138,20 +138,40 @@ QStringList Mesh_parameters:: log() const { - return QStringList() - << QString("edge max size: %1").arg(edge_sizing) - << QString("edge min size: %1").arg(edge_min_sizing) - << QString("facet min angle: %1").arg(facet_angle) - << QString("facet max size: %1").arg(facet_sizing) - << QString("facet min size: %1").arg(facet_min_sizing) - << QString("facet approx error: %1").arg(facet_approx) - << QString("tet shape (radius-edge): %1").arg(tet_shape) - << QString("tet max size: %1").arg(tet_sizing) - << QString("tet min size: %1").arg(tet_min_sizing) - << QString("detect connected components: %1") - .arg(detect_connected_components) - << QString("use weights: %1").arg(weights_ptr != nullptr) - << QString("protect features: %1").arg(protect_features); + QStringList res("Mesh criteria"); + + // doubles + if(edge_sizing > 0) + res << QString("edge max size: %1").arg(edge_sizing); + if(edge_min_sizing > 0) + res << QString("edge min size: %1").arg(edge_min_sizing); + if(facet_angle > 0) + res << QString("facet min angle: %1").arg(facet_angle); + if(facet_sizing > 0) + res << QString("facet max size: %1").arg(facet_sizing); + if(facet_min_sizing > 0) + res << QString("facet min size: %1").arg(facet_min_sizing); + if(facet_approx > 0) + res << QString("facet approx error: %1").arg(facet_approx); + if(tet_shape > 0) + res << QString("tet shape (radius-edge): %1").arg(tet_shape); + if(tet_sizing > 0) + res << QString("tet max size: %1").arg(tet_sizing); + if(tet_min_sizing > 0) + res << QString("tet min size: %1").arg(tet_min_sizing); + + // booleans + res << QString("protect features: %1").arg(protect_features); + if(image_3_ptr != nullptr) + { + res << QString("detect connected components: %1") + .arg(detect_connected_components); + res << QString("use weights: %1").arg(weights_ptr != nullptr); + } + res << QString("use aabb tree: %1").arg(use_sizing_field_with_aabb_tree); + res << QString("manifold: %1").arg(manifold); + + return res; } From ab2afb24eaea6c625917e18e6ed7d32cae391bc4 Mon Sep 17 00:00:00 2001 From: albert-github Date: Mon, 4 Dec 2023 16:34:45 +0100 Subject: [PATCH 120/133] Incorrect link to "Perturbations for Delaunay and weighted Delaunay 3D Triangulations" The link for the document "Perturbations for Delaunay and weighted Delaunay 3D Triangulations" was in #7781 (based on #7762) changed but it is not available at he address "https://theses.hal.science/inria-00560388/" but at "https://hal.science/inria-00560388/". (The other changes were correct). Found in Triangulation_3/citelist.html --- Documentation/doc/biblio/cgal_manual.bib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index e16202c69ddf..51dfb1090046 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -778,7 +778,7 @@ @article{cgal:dt-pvrdr-06 , volume = 44 , year = 2011 , pages = "160--168" -, url = "https://theses.hal.science/inria-00560388/" +, url = "https://hal.science/inria-00560388/" , doi = "10.1016/j.comgeo.2010.09.010" } From b87ecf7aab7ec43fbe0869709c4f7df9d2804a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 5 Dec 2023 09:06:47 +0100 Subject: [PATCH 121/133] prevent out-of-bound warnings --- TDS_3/include/CGAL/Triangulation_utils_3.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TDS_3/include/CGAL/Triangulation_utils_3.h b/TDS_3/include/CGAL/Triangulation_utils_3.h index 8b99c725a65f..d656b5e75c55 100644 --- a/TDS_3/include/CGAL/Triangulation_utils_3.h +++ b/TDS_3/include/CGAL/Triangulation_utils_3.h @@ -35,10 +35,10 @@ struct Triangulation_utils_base_3 template < class T > const char Triangulation_utils_base_3::tab_next_around_edge[4][4] = { - {5, 2, 3, 1}, - {3, 5, 0, 2}, - {1, 3, 5, 0}, - {2, 0, 1, 5} }; + {-0, 2, 3, 1}, + {3, -0, 0, 2}, + {1, 3, -0, 0}, + {2, 0, 1, -0} }; template < class T > const int Triangulation_utils_base_3::tab_vertex_triple_index[4][3] = { From 3ebe548cada33a3b6266cbabda885db9ca05c25a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 5 Dec 2023 11:18:13 +0100 Subject: [PATCH 122/133] Revert "prevent out-of-bound warnings" This reverts commit b87ecf7aab7ec43fbe0869709c4f7df9d2804a40. --- TDS_3/include/CGAL/Triangulation_utils_3.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TDS_3/include/CGAL/Triangulation_utils_3.h b/TDS_3/include/CGAL/Triangulation_utils_3.h index d656b5e75c55..8b99c725a65f 100644 --- a/TDS_3/include/CGAL/Triangulation_utils_3.h +++ b/TDS_3/include/CGAL/Triangulation_utils_3.h @@ -35,10 +35,10 @@ struct Triangulation_utils_base_3 template < class T > const char Triangulation_utils_base_3::tab_next_around_edge[4][4] = { - {-0, 2, 3, 1}, - {3, -0, 0, 2}, - {1, 3, -0, 0}, - {2, 0, 1, -0} }; + {5, 2, 3, 1}, + {3, 5, 0, 2}, + {1, 3, 5, 0}, + {2, 0, 1, 5} }; template < class T > const int Triangulation_utils_base_3::tab_vertex_triple_index[4][3] = { From 95b6ef8d2ee6abf3e78ea13ebbc78d8cba064de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 5 Dec 2023 11:19:31 +0100 Subject: [PATCH 123/133] try working around a warning --- TDS_3/include/CGAL/Triangulation_utils_3.h | 1 + 1 file changed, 1 insertion(+) diff --git a/TDS_3/include/CGAL/Triangulation_utils_3.h b/TDS_3/include/CGAL/Triangulation_utils_3.h index 8b99c725a65f..1c4c16c75911 100644 --- a/TDS_3/include/CGAL/Triangulation_utils_3.h +++ b/TDS_3/include/CGAL/Triangulation_utils_3.h @@ -80,6 +80,7 @@ struct Triangulation_utils_3 CGAL_triangulation_precondition( ( i >= 0 && i < 4 ) && ( j >= 0 && j < 4 ) && ( i != j ) ); + CGAL_assume(i!=j); return tab_next_around_edge[i][j]; } From 95825dba608a07d16fca1781ae1a974f80dbbea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 5 Dec 2023 18:11:27 +0100 Subject: [PATCH 124/133] fix copy/paste errors --- .../CGAL/STL_Extension/internal/mesh_parameters_interface.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h index ece342c321b1..9aedf344d434 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h @@ -55,7 +55,7 @@ perturb(const CGAL_NP_CLASS& np = parameters::default_values()) } template -Named_function_parameters<::CGAL::parameters::internal::Exude_options, ::CGAL::internal_np::exude_options_param_t, CGAL_NP_BASE> +Named_function_parameters<::CGAL::parameters::internal::Perturb_options, ::CGAL::internal_np::perturb_options_param_t, CGAL_NP_BASE> perturb(const CGAL_NP_CLASS_1& np1, const CGAL_NP_CLASS_2& np2, const NP& ... nps) { return perturb(::CGAL::internal_np::combine_named_parameters(np1, np2, nps...)); @@ -91,7 +91,7 @@ exude(const CGAL_NP_CLASS& np = parameters::default_values()) using ::CGAL::parameters::choose_parameter; using ::CGAL::parameters::get_parameter; double time_limit = choose_parameter(get_parameter(np,::CGAL::internal_np::maximum_running_time),::CGAL::parameters::internal::undef_parameter); - double sliver_bound = choose_parameter(get_parameter(np,::CGAL::internal_np::lower_sliver_bound),::CGAL::parameters::default_values_for_mesh_3::perturb_sliver_bound); + double sliver_bound = choose_parameter(get_parameter(np,::CGAL::internal_np::lower_sliver_bound),::CGAL::parameters::default_values_for_mesh_3::exude_sliver_bound); ::CGAL::parameters::internal::Exude_options options(true); From dd0cc2ee5c108f5a0aef3eaac07db4986373421c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 5 Dec 2023 22:15:01 +0100 Subject: [PATCH 125/133] Fix a few copy-paste bugs --- .../CGAL/STL_Extension/internal/mesh_parameters_interface.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h index ece342c321b1..8fc2baca0c3a 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/mesh_parameters_interface.h @@ -55,7 +55,7 @@ perturb(const CGAL_NP_CLASS& np = parameters::default_values()) } template -Named_function_parameters<::CGAL::parameters::internal::Exude_options, ::CGAL::internal_np::exude_options_param_t, CGAL_NP_BASE> +Named_function_parameters<::CGAL::parameters::internal::Perturb_options, ::CGAL::internal_np::perturb_options_param_t, CGAL_NP_BASE> perturb(const CGAL_NP_CLASS_1& np1, const CGAL_NP_CLASS_2& np2, const NP& ... nps) { return perturb(::CGAL::internal_np::combine_named_parameters(np1, np2, nps...)); @@ -91,7 +91,7 @@ exude(const CGAL_NP_CLASS& np = parameters::default_values()) using ::CGAL::parameters::choose_parameter; using ::CGAL::parameters::get_parameter; double time_limit = choose_parameter(get_parameter(np,::CGAL::internal_np::maximum_running_time),::CGAL::parameters::internal::undef_parameter); - double sliver_bound = choose_parameter(get_parameter(np,::CGAL::internal_np::lower_sliver_bound),::CGAL::parameters::default_values_for_mesh_3::perturb_sliver_bound); + double sliver_bound = choose_parameter(get_parameter(np,::CGAL::internal_np::lower_sliver_bound),::CGAL::parameters::default_values_for_mesh_3::exude_sliver_bound); ::CGAL::parameters::internal::Exude_options options(true); @@ -304,7 +304,7 @@ mesh_3_options(const CGAL_NP_CLASS& np = parameters::default_values()) options.dump_after_refine_prefix=choose_parameter(get_parameter(np, ::CGAL::internal_np::dump_after_refine_prefix_param), ""); options.dump_after_glob_opt_prefix=choose_parameter(get_parameter(np, ::CGAL::internal_np::dump_after_glob_opt_prefix_param), ""); options.dump_after_perturb_prefix=choose_parameter(get_parameter(np, ::CGAL::internal_np::dump_after_perturb_prefix_param), ""); - options.dump_after_exude_prefix=choose_parameter(get_parameter(np, ::CGAL::internal_np::dump_after_refine_surface_prefix_param), ""); + options.dump_after_exude_prefix=choose_parameter(get_parameter(np, ::CGAL::internal_np::dump_after_exude_prefix_param), ""); options.number_of_initial_points=choose_parameter(get_parameter(np, ::CGAL::internal_np::number_of_initial_points_param), -1); options.nonlinear_growth_of_balls = choose_parameter(get_parameter(np, ::CGAL::internal_np::nonlinear_growth_of_balls_param), false); options.maximal_number_of_vertices=choose_parameter(get_parameter(np, ::CGAL::internal_np::maximal_number_of_vertices_param), 0); From b4d465ce8532df0913a4eecdd8df414be393768e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 5 Dec 2023 22:34:00 +0100 Subject: [PATCH 126/133] Add a test --- Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp b/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp index 14390abda0d0..9fa7eaad0c33 100644 --- a/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp +++ b/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp @@ -58,7 +58,9 @@ int main() facet_distance=field); // Mesh generation - C3t3 c3t3 = CGAL::make_mesh_3(domain, criteria); + C3t3 c3t3 = CGAL::make_mesh_3(domain, criteria, + perturb(time_limit = 0, sliver_bound = 0), + exude(time_limit = 0, sliver_bound = 0)); // // Output // std::ofstream medit_file("out.mesh"); From 560f02c921aab01856605232120b115e25ffbd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 6 Dec 2023 15:29:17 +0100 Subject: [PATCH 127/133] add missing remove_const --- .../CGAL/Polygon_mesh_processing/remesh_planar_patches.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h index 03171af70bcd..48ca74ba2652 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h @@ -304,7 +304,7 @@ mark_constrained_edges( double coplanar_cos_threshold, const VertexPointMap& vpm) { - for(typename boost::graph_traits::edge_descriptor e : edges(tm)) + for(typename boost::graph_traits>::edge_descriptor e : edges(tm)) { if (!get(edge_is_constrained,e)) if (!is_edge_between_coplanar_faces(e, tm, coplanar_cos_threshold, vpm)) @@ -325,7 +325,7 @@ mark_corner_vertices( double coplanar_cos_threshold, const VertexPointMap& vpm) { - typedef boost::graph_traits graph_traits; + typedef boost::graph_traits> graph_traits; std::size_t corner_id = 0; for(typename graph_traits::edge_descriptor e : edges(tm)) { @@ -553,7 +553,7 @@ tag_corners_and_constrained_edges(TriangleMesh& tm, FaceCCIdMap& face_cc_ids, const VertexPointMap& vpm) { - typedef typename boost::graph_traits graph_traits; + typedef typename boost::graph_traits> graph_traits; // mark constrained edges mark_constrained_edges(tm, edge_is_constrained, coplanar_cos_threshold, vpm); From 63556d4faa3f98af3f0c17cd2ed920f6f489761f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 6 Dec 2023 15:50:14 +0100 Subject: [PATCH 128/133] use explicitly const meshes --- .../Polygon_mesh_processing/remesh_planar_patches.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h index 48ca74ba2652..33514d6f2deb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h @@ -299,12 +299,12 @@ template void mark_constrained_edges( - TriangleMesh& tm, + const TriangleMesh& tm, EdgeIsConstrainedMap edge_is_constrained, double coplanar_cos_threshold, const VertexPointMap& vpm) { - for(typename boost::graph_traits>::edge_descriptor e : edges(tm)) + for(typename boost::graph_traits::edge_descriptor e : edges(tm)) { if (!get(edge_is_constrained,e)) if (!is_edge_between_coplanar_faces(e, tm, coplanar_cos_threshold, vpm)) @@ -319,13 +319,13 @@ template std::size_t mark_corner_vertices( - TriangleMesh& tm, + const TriangleMesh& tm, EdgeIsConstrainedMap& edge_is_constrained, VertexCornerIdMap& vertex_corner_id, double coplanar_cos_threshold, const VertexPointMap& vpm) { - typedef boost::graph_traits> graph_traits; + typedef boost::graph_traits graph_traits; std::size_t corner_id = 0; for(typename graph_traits::edge_descriptor e : edges(tm)) { @@ -546,14 +546,14 @@ template std::pair -tag_corners_and_constrained_edges(TriangleMesh& tm, +tag_corners_and_constrained_edges(const TriangleMesh& tm, double coplanar_cos_threshold, VertexCornerIdMap& vertex_corner_id, EdgeIsConstrainedMap& edge_is_constrained, FaceCCIdMap& face_cc_ids, const VertexPointMap& vpm) { - typedef typename boost::graph_traits> graph_traits; + typedef typename boost::graph_traits graph_traits; // mark constrained edges mark_constrained_edges(tm, edge_is_constrained, coplanar_cos_threshold, vpm); From f0426b8aa6f3d9a73018e801a49aad51bd5613ae Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 7 Dec 2023 09:33:31 +0000 Subject: [PATCH 129/133] PMP: Write into different files to avoid concurrent writing --- ...angulate_hole_Polyhedron_3_no_delaunay_test.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/triangulate_hole_Polyhedron_3_no_delaunay_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/triangulate_hole_Polyhedron_3_no_delaunay_test.cpp index 1dcb214fe398..61b0ed153b43 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/triangulate_hole_Polyhedron_3_no_delaunay_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/triangulate_hole_Polyhedron_3_no_delaunay_test.cpp @@ -335,7 +335,7 @@ void test_triangulate_refine_and_fair_hole_compile() { std::vector patch_vertices; // use all param - read_poly_with_borders("elephant_quad_hole.off", poly, border_reps); + read_poly_with_borders("elephant_quad_hole_no_DT3.off", poly, border_reps); CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole (poly, border_reps[0], back_inserter(patch_facets), back_inserter(patch_vertices), CGAL::parameters:: @@ -343,14 +343,14 @@ void test_triangulate_refine_and_fair_hole_compile() { sparse_linear_solver(Default_solver())); // default solver - read_poly_with_borders("elephant_quad_hole.off", poly, border_reps); + read_poly_with_borders("elephant_quad_hole_no_DT3.off", poly, border_reps); CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole (poly, border_reps[0], back_inserter(patch_facets), back_inserter(patch_vertices), CGAL::parameters:: weight_calculator(CGAL::Weights::Uniform_weight())); // default solver and weight - read_poly_with_borders("elephant_quad_hole.off", poly, border_reps); + read_poly_with_borders("elephant_quad_hole_no_DT3.off", poly, border_reps); CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole (poly, border_reps[0], back_inserter(patch_facets), back_inserter(patch_vertices)); } @@ -369,11 +369,11 @@ void generate_elephant_with_hole() { Halfedge_handle nh=opposite(halfedge(fd,poly), poly); CGAL::Euler::remove_face(halfedge(fd, poly), poly); - std::ofstream output("elephant_triangle_hole.off"); + std::ofstream output("elephant_triangle_hole_no_DT3.off"); output << poly; output.close(); CGAL::Euler::remove_face(nh, poly); - output.open("elephant_quad_hole.off"); + output.open("elephant_quad_hole_no_DT3.off"); output << poly; return; } @@ -389,8 +389,8 @@ typedef CGAL::Surface_mesh Polyhedron; generate_elephant_with_hole(); std::vector input_files; - input_files.push_back("elephant_triangle_hole.off"); - input_files.push_back("elephant_quad_hole.off"); + input_files.push_back("elephant_triangle_hole_no_DT3.off"); + input_files.push_back("elephant_quad_hole_no_DT3.off"); input_files.push_back(CGAL::data_file_path("meshes/mech-holes-shark.off")); // std::cerr.precision(15); for(std::vector::iterator it = input_files.begin(); it != input_files.end(); ++it) { From dc04e5baa58f856c386e4b5fa8bc4de84cbe6746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 7 Dec 2023 11:30:17 +0100 Subject: [PATCH 130/133] use doxygen macro --- .../CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h index 5c3a99efef5b..e673ac9dfbb7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Adaptive_sizing_field.h @@ -38,7 +38,7 @@ namespace Polygon_mesh_processing * Edges too long with respect to the local target edge length are split in two, while * edges that are too short are collapsed. * -* This class depends on the Eigen library. +* This class depends on the \eigen library. * * \cgalModels{PMPSizingField} * From 7aab407b8cfd3a39ecad5f207ea88403246d1735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 7 Dec 2023 11:32:17 +0100 Subject: [PATCH 131/133] add user friendly use case --- .../doc/Polygon_mesh_processing/Concepts/PMPSizingField.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h index 02822cea9e70..e3c647510c99 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h @@ -60,6 +60,7 @@ Point_3 split_placement(const halfedge_descriptor h, const PolygonMesh& pmesh) const; /// function called after the addition of the split vertex `v` in `pmesh`. +/// This function can be used for exemple to update a pre-computed sizing field. void register_split_vertex(const vertex_descriptor v, const PolygonMesh& pmesh); From 96955790a1fd1069343605b7dcb8752ad1e6309a Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Thu, 7 Dec 2023 11:57:42 +0100 Subject: [PATCH 132/133] typo Co-authored-by: Jane Tournois --- .../doc/Polygon_mesh_processing/Concepts/PMPSizingField.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h index e3c647510c99..b1216f3281ea 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPSizingField.h @@ -60,7 +60,7 @@ Point_3 split_placement(const halfedge_descriptor h, const PolygonMesh& pmesh) const; /// function called after the addition of the split vertex `v` in `pmesh`. -/// This function can be used for exemple to update a pre-computed sizing field. +/// This function can be used for example to update a pre-computed sizing field. void register_split_vertex(const vertex_descriptor v, const PolygonMesh& pmesh); From 20b99521ac05cfe27abf119f15a92d23b4d543a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 11 Dec 2023 12:17:49 +0100 Subject: [PATCH 133/133] Fix typo in benchmarks --- .../Alpha_wrap_3/Robustness/robustness_benchmark.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp index 353e5569d1f9..3bf23fe02012 100644 --- a/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp +++ b/Alpha_wrap_3/benchmark/Alpha_wrap_3/Robustness/robustness_benchmark.cpp @@ -21,7 +21,7 @@ enum Robustness_benchmark_exit_code VALID_SOLID_OUTPUT = 0, // Failure - INTPUT_IS_INVALID = 1, + INPUT_IS_INVALID = 1, OUTPUT_IS_NOT_TRIANGLE_MESH = 2, OUTPUT_IS_COMBINATORIAL_NON_MANIFOLD = 3, OUTPUT_HAS_BORDERS = 4, @@ -59,7 +59,7 @@ int main(int argc, char** argv) } if(argc < 3 || relative_alpha_ratio <= 0.) - return AW3i::INTPUT_IS_INVALID; + return AW3i::INPUT_IS_INVALID; Mesh input_mesh; if(!PMP::IO::read_polygon_mesh(entry_name_ptr, input_mesh) || @@ -70,7 +70,7 @@ int main(int argc, char** argv) #endif ) { - return AW3i::INTPUT_IS_INVALID; + return AW3i::INPUT_IS_INVALID; } const CGAL::Bbox_3 bbox = PMP::bbox(input_mesh);