From d2be97b1eb4ef32ab6e4fc59d048a21beee2ccca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 23 Nov 2021 10:16:23 +0100 Subject: [PATCH] fix bug when both edges to remove are constrained edges --- .../CGAL/boost/graph/Euler_operations.h | 15 +- BGL/test/BGL/CMakeLists.txt | 2 + .../test_Collapse_edge_with_constraints.cpp | 331 ++++++++++++++++++ 3 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 BGL/test/BGL/test_Collapse_edge_with_constraints.cpp diff --git a/BGL/include/CGAL/boost/graph/Euler_operations.h b/BGL/include/CGAL/boost/graph/Euler_operations.h index 8d5268da6e0..598b7cbb3c4 100644 --- a/BGL/include/CGAL/boost/graph/Euler_operations.h +++ b/BGL/include/CGAL/boost/graph/Euler_operations.h @@ -1603,7 +1603,20 @@ collapse_edge(typename boost::graph_traits::edge_descriptor v0v1, if (!is_border(edges_to_erase[1],g)) join_face(edges_to_erase[1],g); else - remove_face(opposite(edges_to_erase[1],g),g); + { + if (!is_border(pq, g)) + remove_face(opposite(edges_to_erase[1],g),g); + else + { + if(!is_border(opposite(next(qp,g),g),g)) + { + // q will be removed, swap it with p + internal::swap_vertices(p, q, g); + } + remove_face(opposite(edges_to_erase[1],g),g); + return q; + } + } join_vertex(pq,g); return q; } diff --git a/BGL/test/BGL/CMakeLists.txt b/BGL/test/BGL/CMakeLists.txt index 8d5b0e7b652..3a4ee63223b 100644 --- a/BGL/test/BGL/CMakeLists.txt +++ b/BGL/test/BGL/CMakeLists.txt @@ -89,6 +89,8 @@ create_single_source_cgal_program( "test_test_face.cpp" ) create_single_source_cgal_program( "test_Collapse_edge.cpp" ) +create_single_source_cgal_program( "test_Collapse_edge_with_constraints.cpp" ) + create_single_source_cgal_program("test_graph_traits.cpp") create_single_source_cgal_program("test_Properties.cpp") diff --git a/BGL/test/BGL/test_Collapse_edge_with_constraints.cpp b/BGL/test/BGL/test_Collapse_edge_with_constraints.cpp new file mode 100644 index 00000000000..bcf1ca8e3c7 --- /dev/null +++ b/BGL/test/BGL/test_Collapse_edge_with_constraints.cpp @@ -0,0 +1,331 @@ +#include +#include +#include + +typedef CGAL::Simple_cartesian K; +typedef K::Point_3 Point_3; +typedef CGAL::Surface_mesh Mesh; +typedef Mesh::Property_map ECM; + + +bool test_one_side(Mesh::Halfedge_index h, Mesh m) +{ + std::pair ecm_and_bool = m.property_map("ecm"); + Mesh::Vertex_index vkept=target(h, m); + CGAL::Euler::collapse_edge(edge(h, m), m, ecm_and_bool.first); + return (!m.is_removed(vkept) && CGAL::is_valid_polygon_mesh(m)); +} + +bool test(Mesh::Halfedge_index h, Mesh& m) +{ + return test_one_side(h, m) && test_one_side(opposite(h, m), m); +} + +int main() +{ + // ---------------------------------------------- // + // two faces incident to the edge to be collapsed // + // ---------------------------------------------- // + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + /* ECM ecm = */m.add_property_map("ecm", false).first; + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(next(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(next(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } +// duplicate block + add one border (1) + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + /* ECM ecm = */m.add_property_map("ecm", false).first; + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(next(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(next(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + // duplicate block + add one border (2) + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + /* ECM ecm = */m.add_property_map("ecm", false).first; + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(next(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(next(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } +// duplicate block + add one border (1) + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + /* ECM ecm = */m.add_property_map("ecm", false).first; + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(next(h2c,m), m), true); + put(ecm, edge(prev(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index h2c = CGAL::Euler::add_center_vertex(h, m); + Mesh::Halfedge_index hb1 = opposite(prev(h2c, m), m); + assert(is_border(hb1, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + Mesh::Halfedge_index hb2 = opposite(next(opposite(h2c,m), m), m); + assert(is_border(hb2, m)); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c,m), m), true); + put(ecm, edge(next(opposite(h2c,m),m), m), true); + bool res = test(h2c, m); + assert(res); + } + // ---------------------------------------------- // + // one face incident to the edge to be collapsed // + // ---------------------------------------------- // + // center triangle with 2 border edges (1) + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb1=opposite(next(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + /* ECM ecm = */m.add_property_map("ecm", false).first; + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb1=opposite(next(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(next(h2c, m),m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb1=opposite(next(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c, m),m), true); + bool res = test(h2c, m); + assert(res); + } + // center triangle with 2 border edges (2) + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb2=opposite(prev(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + /* ECM ecm = */m.add_property_map("ecm", false).first; + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb2=opposite(prev(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(next(h2c, m),m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb2=opposite(prev(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c, m),m), true); + bool res = test(h2c, m); + assert(res); + } + // center triangle with 1 border edges + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb1=opposite(next(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + Mesh::Halfedge_index hb2=opposite(prev(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + /* ECM ecm = */m.add_property_map("ecm", false).first; + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb1=opposite(next(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + Mesh::Halfedge_index hb2=opposite(prev(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(next(h2c, m),m), true); + bool res = test(h2c, m); + assert(res); + } + { + Mesh m; + Mesh::Halfedge_index h2c = CGAL::make_triangle(Point_3(),Point_3(),Point_3(),m); + Mesh::Halfedge_index hb1=opposite(next(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb1, m), hb1, m); + Mesh::Halfedge_index hb2=opposite(prev(h2c,m),m); + CGAL::Euler::add_vertex_and_face_to_border(prev(hb2, m), hb2, m); + ECM ecm = m.add_property_map("ecm", false).first; + put(ecm, edge(prev(h2c, m),m), true); + bool res = test(h2c, m); + assert(res); + } +}