From d7759abbb74ba969a8adc3872a4199723a07406f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 1 Apr 2022 15:02:18 +0200 Subject: [PATCH] add a hidden parameter to allow non-manifold vertices or edges this is to be used only is advanced code that deals with invalid T3 --- .../Mesh_complex_3_in_triangulation_3_fwd.h | 3 +- .../Plugins/Mesh_3/C3t3_io_plugin.cpp | 3 +- SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h | 165 ++++++++++++------ .../tetrahedron_soup_to_triangulation_3.h | 18 +- .../internal/parameters_interface.h | 1 + .../internal/collapse_short_edges.h | 4 +- 6 files changed, 140 insertions(+), 54 deletions(-) diff --git a/Installation/include/CGAL/SMDS_3/Mesh_complex_3_in_triangulation_3_fwd.h b/Installation/include/CGAL/SMDS_3/Mesh_complex_3_in_triangulation_3_fwd.h index 631e85211b4..9b0c2d1e38e 100644 --- a/Installation/include/CGAL/SMDS_3/Mesh_complex_3_in_triangulation_3_fwd.h +++ b/Installation/include/CGAL/SMDS_3/Mesh_complex_3_in_triangulation_3_fwd.h @@ -41,7 +41,8 @@ namespace SMDS_3 { bool build_triangulation_from_file(std::istream& is, Tr& tr, bool verbose = false, - bool replace_domain_0 = false); + bool replace_domain_0 = false, + bool allow_non_manifold = false); } // namespace SMDS_3 } // namespace CGAL diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index a0d02e08b97..3f2b08782fb 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -129,7 +129,8 @@ Polyhedron_demo_c3t3_binary_io_plugin::load( item->setName(fileinfo.baseName()); item->set_valid(false); - if(CGAL::SMDS_3::build_triangulation_from_file(in, item->c3t3().triangulation(), true)) + if(CGAL::SMDS_3::build_triangulation_from_file(in, item->c3t3().triangulation(), + /*verbose = */true, /*replace_subdomain_0 = */false, /*allow_non_manifold = */true)) { item->c3t3().rescan_after_load_of_triangulation(); //fix counters for facets and cells for( C3t3::Cell_handle cit : item->c3t3().triangulation().finite_cell_handles()) diff --git a/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h b/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h index bb5d4a8cf0a..e87178f76a4 100644 --- a/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h +++ b/SMDS_3/include/CGAL/SMDS_3/tet_soup_to_c3t3.h @@ -68,7 +68,8 @@ template bool add_facet_to_incident_cells_map(const typename Tr::Cell_handle c, int i, boost::unordered_map, std::vector > >& incident_cells_map, - const bool verbose) + const bool verbose, + const bool allow_non_manifold) { typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Cell_handle Cell_handle; @@ -76,8 +77,10 @@ bool add_facet_to_incident_cells_map(const typename Tr::Cell_handle c, int i, typedef std::pair Incident_cell; typedef boost::unordered_map > Incident_cells_map; + bool success = true; + // the opposite vertex of f in c is i - Facet_vvv f = make_ordered_vertex_array(c->vertex((i + 1) % 4), + Facet_vvv f = CGAL::SMDS_3::make_ordered_vertex_array(c->vertex((i + 1) % 4), c->vertex((i + 2) % 4), c->vertex((i + 3) % 4)); CGAL_precondition(f[0] != f[1] && f[1] != f[2]); @@ -94,11 +97,12 @@ bool add_facet_to_incident_cells_map(const typename Tr::Cell_handle c, int i, { if(verbose) std::cout << "Error in add_facet_to_incident_cells_map" << std::endl; - return false; + if(!allow_non_manifold) + success = false; } is_insert_successful.first->second.push_back(e); } - return true; + return success; } template @@ -110,12 +114,14 @@ bool build_finite_cells(Tr& tr, std::vector > >& incident_cells_map, const FacetPatchMap& border_facets, const bool verbose, - bool replace_domain_0 = false) + const bool replace_domain_0) { typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Cell_handle Cell_handle; typedef typename Tr::Cell::Surface_patch_index Surface_patch_index; + bool success = true; + CGAL_assertion_code( typename Tr::Geom_traits::Construct_point_3 cp = tr.geom_traits().construct_point_3_object(); @@ -168,8 +174,9 @@ bool build_finite_cells(Tr& tr, // build the map used for adjacency later for(int j=0; j<4; ++j) { - if(!add_facet_to_incident_cells_map(c, j, incident_cells_map, verbose)) - return false; + if(!CGAL::SMDS_3::add_facet_to_incident_cells_map(c, j, incident_cells_map, verbose, false)) + //do not allow non-manifold in the finite cells case + success = false; if(border_facets.size() != 0) { std::array facet; @@ -208,7 +215,7 @@ bool build_finite_cells(Tr& tr, } } } - return true; + return success; } template @@ -216,14 +223,15 @@ bool add_infinite_facets_to_incident_cells_map(typename Tr::Cell_handle c, int inf_vert_pos, boost::unordered_map, std::vector > >& incident_cells_map, - const bool verbose) + const bool verbose, + const bool allow_non_manifold) { int l = (inf_vert_pos + 1) % 4; - bool b1 = add_facet_to_incident_cells_map(c, l, incident_cells_map, verbose); + bool b1 = CGAL::SMDS_3::add_facet_to_incident_cells_map(c, l, incident_cells_map, verbose, allow_non_manifold); l = (inf_vert_pos + 2) % 4; - bool b2 = add_facet_to_incident_cells_map(c, l, incident_cells_map, verbose); + bool b2 = CGAL::SMDS_3::add_facet_to_incident_cells_map(c, l, incident_cells_map, verbose, allow_non_manifold); l = (inf_vert_pos + 3) % 4; - bool b3 = add_facet_to_incident_cells_map(c, l, incident_cells_map, verbose); + bool b3 = CGAL::SMDS_3::add_facet_to_incident_cells_map(c, l, incident_cells_map, verbose, allow_non_manifold); return b1 && b2 && b3; } @@ -231,7 +239,8 @@ template bool build_infinite_cells(Tr& tr, boost::unordered_map, std::vector > >& incident_cells_map, - const bool verbose) + const bool verbose, + const bool allow_non_manifold) { typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Cell_handle Cell_handle; @@ -239,6 +248,8 @@ bool build_infinite_cells(Tr& tr, typedef std::pair Incident_cell; typedef boost::unordered_map > Incident_cells_map; + bool success = true; + std::vector infinite_cells; // check the incident cells map for facets who only have one incident cell @@ -289,7 +300,7 @@ bool build_infinite_cells(Tr& tr, { for (int i = 1; i < 4; ++i) { - std::array vs = make_ordered_vertex_array(c->vertex((i + 1) % 4), + std::array vs = CGAL::SMDS_3::make_ordered_vertex_array(c->vertex((i + 1) % 4), c->vertex((i + 2) % 4), c->vertex((i + 3) % 4)); if (facets.find(vs) == facets.end()) @@ -299,42 +310,78 @@ bool build_infinite_cells(Tr& tr, } } for (auto fp : facets) - CGAL_assertion(fp.second == 2); + { + if (fp.second != 2) + { + std::cout << "Warning : non manifold edge" << std::endl; + std::cout << "fp.second = " << fp.second << std::endl; + std::cout << fp.first[0]->point() << " " + << fp.first[1]->point() << " " + << fp.first[2]->point() << std::endl; + success = false; + } +// CGAL_assertion(fp.second == 2); + } #endif // add the facets to the incident cells map for (const Cell_handle& c : infinite_cells) - if(!add_infinite_facets_to_incident_cells_map(c, 0, incident_cells_map, verbose)) - return false; + if(!CGAL::SMDS_3::add_infinite_facets_to_incident_cells_map(c, + 0, + incident_cells_map, + verbose, + allow_non_manifold)) + success = false; - return true; + return success; +} + +template +bool has_infinite_vertex(const std::array& v, + const Tr& tr) +{ + for (auto vh : v) + { + if (tr.infinite_vertex() == vh) + return true; + } + return false; } template bool assign_neighbors(Tr& tr, const boost::unordered_map, - std::vector > >& incident_cells_map) + std::vector > >& incident_cells_map, + const bool allow_non_manifold) { typedef typename Tr::Cell_handle Cell_handle; typedef std::pair Incident_cell; typedef boost::unordered_map, std::vector > Incident_cells_map; + bool success = true; + typename Incident_cells_map::const_iterator icit = incident_cells_map.begin(); for(; icit!=incident_cells_map.end(); ++icit) { const std::vector& adjacent_cells = icit->second; - if(adjacent_cells.size() != 2) - return false; + if (adjacent_cells.size() == 2) + { + Cell_handle c0 = adjacent_cells[0].first; + int i0 = adjacent_cells[0].second; + Cell_handle c1 = adjacent_cells[1].first; + int i1 = adjacent_cells[1].second; - Cell_handle c0 = adjacent_cells[0].first; - int i0 = adjacent_cells[0].second; - Cell_handle c1 = adjacent_cells[1].first; - int i1 = adjacent_cells[1].second; - - tr.tds().set_adjacency(c0, i0, c1, i1); + tr.tds().set_adjacency(c0, i0, c1, i1); + } + else if(allow_non_manifold)// if (adjacent_cells.size() == 4) + { + const auto& v = icit->first; + CGAL_assertion(has_infinite_vertex(v, tr)); + success = false; + } } - return true; + return success; } template& subdomains, const FacetPatchMap& border_facets, std::vector& vertex_handle_vector, - const bool verbose = false, - bool replace_domain_0 = false) + const bool verbose,// = false, + const bool replace_domain_0,// = false, + const bool allow_non_manifold) // = false { typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Cell_handle Cell_handle; @@ -358,6 +406,8 @@ bool build_triangulation_impl(Tr& tr, typedef std::pair Incident_cell; typedef boost::unordered_map > Incident_cells_map; + bool success = true; + Incident_cells_map incident_cells_map; vertex_handle_vector.resize(points.size() + 1); // id to vertex_handle //index 0 is for infinite vertex @@ -379,14 +429,23 @@ bool build_triangulation_impl(Tr& tr, } if (!finite_cells.empty()) { - if(!build_finite_cells(tr, finite_cells, subdomains, vertex_handle_vector, incident_cells_map, - border_facets, verbose, replace_domain_0)) - return false; - if(!build_infinite_cells(tr, incident_cells_map, verbose)) - return false; + if (!CGAL::SMDS_3::build_finite_cells(tr, finite_cells, subdomains, vertex_handle_vector, incident_cells_map, + border_facets, verbose, replace_domain_0)) + { + if(verbose) std::cout << "build_finite_cells went wrong" << std::endl; + success = false; + } + if (!CGAL::SMDS_3::build_infinite_cells(tr, incident_cells_map, verbose, allow_non_manifold)) + { + if(verbose) std::cout << "build_infinite_cells went wrong" << std::endl; + success = false; + } tr.tds().set_dimension(3); - if (!assign_neighbors(tr, incident_cells_map)) - return false; + if (!CGAL::SMDS_3::assign_neighbors(tr, incident_cells_map, allow_non_manifold)) + { + if(verbose) std::cout << "assign_neighbors went wrong" << std::endl; + success = false; + } if (verbose) { std::cout << "built triangulation : " << std::endl; @@ -396,7 +455,7 @@ bool build_triangulation_impl(Tr& tr, if(verbose) std::cout << tr.number_of_vertices() << " vertices" << std::endl; - return true;// tr.tds().is_valid(); + return success;// tr.tds().is_valid(); //TDS not valid when cells do not cover the convex hull of vertices } @@ -410,13 +469,15 @@ bool build_triangulation_one_subdomain(Tr& tr, const typename Tr::Cell::Subdomain_index& subdomain, const FacetPatchMap& border_facets, std::vector& vertex_handle_vector, - const bool verbose = false, - bool replace_domain_0 = false) + const bool verbose,// = false, + const bool replace_domain_0,// = false + const bool allow_non_manifold)// = false { std::vector subdomains(finite_cells.size(), subdomain); return build_triangulation_impl(tr, points, finite_cells, subdomains, border_facets, vertex_handle_vector, - verbose, replace_domain_0); + verbose, replace_domain_0, + allow_non_manifold); } template subdomains(finite_cells.size(), subdomain); std::vector vertex_handle_vector; return build_triangulation_impl(tr, points, finite_cells, subdomains, border_facets, vertex_handle_vector, - verbose, replace_domain_0); + verbose, replace_domain_0, + allow_non_manifold); } template vertex_handle_vector; std::vector subdomains_vector( subdomains.begin(), subdomains.end()); return build_triangulation_impl(tr, points, finite_cells, subdomains_vector, border_facets, vertex_handle_vector, - verbose, replace_domain_0); + verbose, replace_domain_0, + allow_non_manifold); } template bool build_triangulation_from_file(std::istream& is, Tr& tr, const bool verbose, - bool replace_domain_0) + const bool replace_domain_0, + const bool allow_non_manifold) { using Point_3 = typename Tr::Point; using Subdomain_index = typename Tr::Cell::Subdomain_index; @@ -575,7 +641,8 @@ bool build_triangulation_from_file(std::istream& is, return build_triangulation_with_subdomains_range(tr, points, finite_cells, subdomains, border_facets, verbose, - replace_domain_0 && !dont_replace_domain_0); + replace_domain_0 && !dont_replace_domain_0, + allow_non_manifold); } } // namespace SMDS_3 diff --git a/SMDS_3/include/CGAL/tetrahedron_soup_to_triangulation_3.h b/SMDS_3/include/CGAL/tetrahedron_soup_to_triangulation_3.h index 8f6ebc27e82..4b41f7bfff2 100644 --- a/SMDS_3/include/CGAL/tetrahedron_soup_to_triangulation_3.h +++ b/SMDS_3/include/CGAL/tetrahedron_soup_to_triangulation_3.h @@ -92,7 +92,8 @@ namespace CGAL { } typename Tr::Cell::Subdomain_index default_si(1); - CGAL::SMDS_3::build_triangulation_one_subdomain(tr, points, finite_cells, default_si, border_facets); + CGAL::SMDS_3::build_triangulation_one_subdomain(tr, points, finite_cells, default_si, border_facets, + /*verbose = */false, /*replace_domain_0 = */false, /*allow_non_manifold =*/false); CGAL_assertion(CGAL::SMDS_3::internal::is_convex(tr)); @@ -144,6 +145,15 @@ namespace CGAL { * set to have `1` as `Subdomain_index`} * \cgalParamExtra{to avoid copies of large data sets, this parameter can be passed using `std::cref`} * \cgalParamNEnd + *\cond SKIP_IN_MANUAL + * \cgalParamNBegin{allow_non_manifold} + * \cgalParamDescription{allows the construction of a triangulation with non-manifold edges + * and non manifold vertices. The triangulation is invalid if this situation is met, + * so it should be used only in advanced cases, and the triangulation will be hardly usable.} + * \cgalParamType{bool} + * \cgalParamDefault{false} + * \cgalParamNEnd + *\encond * \cgalNamedParamsEnd * * @returns the 3D triangulation built from parameters @@ -188,8 +198,12 @@ namespace CGAL { const Subdomains_ref_type& subdomains = choose_parameter( get_parameter_reference(np, internal_np::subdomain_indices), 1); + const bool non_manifold = choose_parameter( + get_parameter(np, internal_np::allow_non_manifold), + false); - CGAL::SMDS_3::build_triangulation_with_subdomains_range(tr, points, tets, subdomains, facets); + CGAL::SMDS_3::build_triangulation_with_subdomains_range(tr, points, tets, subdomains, facets, + /*verbose = */false, /*replace_domain_0 = */false, non_manifold); CGAL_assertion(CGAL::SMDS_3::internal::is_convex(tr)); 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 25144940231..b0778fbe556 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -216,6 +216,7 @@ CGAL_add_named_parameter(all_vertices_t, all_vertices, all_vertices) CGAL_add_named_parameter(all_cells_t, all_cells, all_cells) CGAL_add_named_parameter(rebind_labels_t, rebind_labels, rebind_labels) CGAL_add_named_parameter(show_patches_t, show_patches, show_patches) +CGAL_add_named_parameter(allow_non_manifold_t, allow_non_manifold, allow_non_manifold) // output parameters CGAL_add_named_parameter(face_proxy_map_t, face_proxy_map, face_proxy_map) diff --git a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h index 8e29061e860..cf5ef4a470d 100644 --- a/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h +++ b/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/collapse_short_edges.h @@ -111,7 +111,9 @@ public: std::map border_facets; if (CGAL::SMDS_3::build_triangulation_impl( triangulation, points, finite_cells, subdomains, border_facets, - new_vertices /*, verbose*/)) + new_vertices, /*verbose*/ false, + /*replace_domain_0*/ false, + /*allow_non_manifold*/false)) { CGAL_assertion(triangulation.tds().is_valid()); CGAL_assertion(triangulation.infinite_vertex() == new_vertices[0]);