From a6f7b3c1636c4ab1d57fecd862555ad400111542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 13 Dec 2024 17:58:53 +0100 Subject: [PATCH 1/3] WIP handle nested coplanar CC --- .../Corefinement/Face_graph_output_builder.h | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h index c27ae2bda3a..71c4accf20c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h @@ -759,6 +759,71 @@ class Face_graph_output_builder coplanar_patches_of_tm2.set(tm2_patch_ids[ fid2 ]); } + + //we have the correspondance between cpln patches thanks to faces in tm1_coplanar_faces and tm2_coplanar_faces + CGAL_assertion(tm1_coplanar_faces.size()==tm2_coplanar_faces.size()); + // TODO: move it to do it lazily + std::vector coplanar_tm1_to_coplanar_tm2; + std::vector is_oo_tm1(nb_patches_tm1, false); + std::vector is_oo_tm2(nb_patches_tm2, false); + if (!tm1_coplanar_faces.empty()) + { + coplanar_tm1_to_coplanar_tm2.resize(nb_patches_tm1, NID); + for (std::size_t i=0; i> max_pts_1(nb_patches_tm1); + for (face_descriptor fd : faces(tm1)) + { + std::size_t patch_id = tm1_patch_ids[get(fids1, fd)]; + if (!coplanar_patches_of_tm1.test(patch_id)) continue; + halfedge_descriptor hd=halfedge(fd, tm1); + for (halfedge_descriptor h : CGAL::halfedges_around_face(hd, tm1)) + { + vertex_descriptor vd = target(h, tm1); + if (!max_pts_1[patch_id].has_value() || get(vpm1,max_pts_1[patch_id].value())> max_pts_2(nb_patches_tm2); + for (face_descriptor fd : faces(tm2)) + { + std::size_t patch_id = tm2_patch_ids[get(fids2, fd)]; + if (!coplanar_patches_of_tm2.test(patch_id)) continue; + halfedge_descriptor hd=halfedge(fd, tm2); + for (halfedge_descriptor h : CGAL::halfedges_around_face(hd, tm2)) + { + vertex_descriptor vd = target(h, tm2); + if (!max_pts_2[patch_id].has_value() || get(vpm2,max_pts_2[patch_id].value()) Date: Mon, 16 Dec 2024 20:21:11 +0100 Subject: [PATCH 2/3] add test --- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../test_corefinement_cavities.cpp | 120 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_cavities.cpp diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index eb9b98cbe59..5f95e3eb196 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_corefinement_cavities.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_corefinement_cavities.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_cavities.cpp new file mode 100644 index 00000000000..e07ad7e5975 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_cavities.cpp @@ -0,0 +1,120 @@ +#include +#include +#include + +template +void make_hexa(double x, double y, double z, + double X, double Y, double Z, + Mesh& mesh, int t) +{ + CGAL::make_hexahedron( + Point(x,y,Z), + Point(X,y,Z), + Point(X,y,z), + Point(x,y,z), + Point(x,Y,z), + Point(x,Y,Z), + Point(X,Y,Z), + Point(X,Y,z), + mesh); + + using face_descriptor = typename boost::graph_traits::face_descriptor; + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + + std::vector fcs(faces(mesh).begin(), faces(mesh).end()); + for (face_descriptor f : fcs) + { + halfedge_descriptor h = halfedge(f, mesh); + if (t==1) h=next(h,mesh); + halfedge_descriptor h2=next(next(h, mesh), mesh); + CGAL::Euler::split_face(h, h2, mesh); + } +} + +using K = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = K::Point_3; +using Mesh = CGAL::Surface_mesh; + +namespace PMP = CGAL::Polygon_mesh_processing; + + +void test_operations(Mesh A, Mesh B, + bool reverse_A, bool reverse_B, + std::string round, + std::size_t union_v, std::size_t inter_v, std::size_t diff1_v, std::size_t diff2_v) +{ + if (reverse_A) PMP::reverse_face_orientations(A); + if (reverse_B) PMP::reverse_face_orientations(B); + + Mesh out_union, out_inter, out_diff1, out_diff2; + std::array, 4> output; + output[PMP::Corefinement::UNION] = &out_union; + output[PMP::Corefinement::INTERSECTION] = &out_inter; + output[PMP::Corefinement::TM1_MINUS_TM2] = &out_diff1; + output[PMP::Corefinement::TM2_MINUS_TM1] = &out_diff2; + + Mesh lA=A, lB=B; + PMP::corefine_and_compute_boolean_operations(lA,lB,output); +#ifdef VERBOSE + std::ofstream("out_union_"+round+".off") << out_union; + std::ofstream("out_inter_"+round+".off") << out_inter; + std::ofstream("out_diff1_"+round+".off") << out_diff1; + std::ofstream("out_diff2_"+round+".off") << out_diff2; +#endif + assert(vertices(out_union).size()==union_v); + assert(vertices(out_inter).size()==inter_v); + assert(vertices(out_diff1).size()==diff1_v); + assert(vertices(out_diff2).size()==diff2_v); +} + +int main() +{ + + Mesh A, mh, B; + make_hexa(0, 0, 0, + 4, 4, 4, + A, 0); + make_hexa(1, 1, 1, + 2, 2, 2, + mh, 0); + make_hexa(1, 1, 1, + 2, 2, 2, + B, 1); + + Mesh A2, mh2, B2; + make_hexa(5, 0, 0, + 9, 4, 4, + A2, 0); + make_hexa(6, 1, 1, + 7, 2, 2, + mh2, 0); + make_hexa(6, 1, 1, + 7, 2, 2, + B2, 1); + + A.join(A2); + mh.join(mh2); + PMP::reverse_face_orientations(mh); + A.join(mh); + B.join(B2); + +#ifdef VERBOSE + std::ofstream("A.off") << A; + std::ofstream("B.off") << B; +#endif + + test_operations(A, B, false, false, "r00", 16, 0, 44, 28); + test_operations(A, B, false, true, "r01", 28, 44, 0, 16); + test_operations(A, B, true, false, "r10", 44, 28, 16, 0); + test_operations(A, B, true, true, "r11", 0, 16, 28, 44); + + test_operations(A, A, false, false, "a00", 32, 32, 0, 0); + test_operations(A, A, false, true, "a01", 0, 0, 32, 32); + test_operations(A, A, true, false, "a10", 0, 0, 32, 32); + test_operations(A, A, true, true, "a11", 32, 32, 0, 0); + + test_operations(B, B, false, false, "b00", 16, 16, 0, 0); + test_operations(B, B, false, true, "b01", 0, 0, 16, 16); + test_operations(B, B, true, false, "b10", 0, 0, 16, 16); + test_operations(B, B, true, true, "b11", 16, 16, 0, 0); +} From 8bc0b888b8e6c498847975694fcb6219dc8803ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 18 Dec 2024 11:35:17 +0100 Subject: [PATCH 3/3] clean up patch and make filling lazy --- .../Corefinement/Face_graph_output_builder.h | 117 ++++++++---------- .../test_corefinement_cavities.cpp | 3 + 2 files changed, 54 insertions(+), 66 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h index 71c4accf20c..e7f1469169d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h @@ -743,6 +743,10 @@ class Face_graph_output_builder boost::dynamic_bitset<> coplanar_patches_of_tm2_for_union_and_intersection(nb_patches_tm2,false); patch_status_not_set_tm1.set(); patch_status_not_set_tm2.set(); + // extra containers used when entire connected components are identical (filled only if needed) + std::vector coplanar_tm1_to_coplanar_tm2; + std::vector extreme_vertex_per_cc_1; + std::vector extreme_vertex_per_cc_2; // first set coplanar status of patches using the coplanar faces collected during the // extra intersection edges collected. This is important in the case of full connected components @@ -759,71 +763,6 @@ class Face_graph_output_builder coplanar_patches_of_tm2.set(tm2_patch_ids[ fid2 ]); } - - //we have the correspondance between cpln patches thanks to faces in tm1_coplanar_faces and tm2_coplanar_faces - CGAL_assertion(tm1_coplanar_faces.size()==tm2_coplanar_faces.size()); - // TODO: move it to do it lazily - std::vector coplanar_tm1_to_coplanar_tm2; - std::vector is_oo_tm1(nb_patches_tm1, false); - std::vector is_oo_tm2(nb_patches_tm2, false); - if (!tm1_coplanar_faces.empty()) - { - coplanar_tm1_to_coplanar_tm2.resize(nb_patches_tm1, NID); - for (std::size_t i=0; i> max_pts_1(nb_patches_tm1); - for (face_descriptor fd : faces(tm1)) - { - std::size_t patch_id = tm1_patch_ids[get(fids1, fd)]; - if (!coplanar_patches_of_tm1.test(patch_id)) continue; - halfedge_descriptor hd=halfedge(fd, tm1); - for (halfedge_descriptor h : CGAL::halfedges_around_face(hd, tm1)) - { - vertex_descriptor vd = target(h, tm1); - if (!max_pts_1[patch_id].has_value() || get(vpm1,max_pts_1[patch_id].value())> max_pts_2(nb_patches_tm2); - for (face_descriptor fd : faces(tm2)) - { - std::size_t patch_id = tm2_patch_ids[get(fids2, fd)]; - if (!coplanar_patches_of_tm2.test(patch_id)) continue; - halfedge_descriptor hd=halfedge(fd, tm2); - for (halfedge_descriptor h : CGAL::halfedges_around_face(hd, tm2)) - { - vertex_descriptor vd = target(h, tm2); - if (!max_pts_2[patch_id].has_value() || get(vpm2,max_pts_2[patch_id].value())::null_vertex(); + extreme_vertex_per_cc_1.assign(nb_patches_tm1, null_v); + for (face_descriptor fd : faces(tm1)) + { + std::size_t patch_id = tm1_patch_ids[get(fids1, fd)]; + if (!coplanar_patches_of_tm1.test(patch_id)) continue; + halfedge_descriptor hd=halfedge(fd, tm1); + for (halfedge_descriptor h : CGAL::halfedges_around_face(hd, tm1)) + { + vertex_descriptor vd = target(h, tm1); + if (extreme_vertex_per_cc_1[patch_id]==null_v || get(vpm1,extreme_vertex_per_cc_1[patch_id])