diff --git a/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h b/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h index 83700ee7534..d9216e7e9ec 100644 --- a/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h +++ b/Constrained_triangulation_3/include/CGAL/Conforming_constrained_Delaunay_triangulation_3.h @@ -41,6 +41,7 @@ #include #include +#include #include @@ -589,25 +590,23 @@ public: #ifndef DOXYGEN_RUNNING template - bool preconditions_verified(const PolygonMesh& mesh, const CGAL_NP_CLASS& np) + bool preconditions_verified_mesh(const PolygonMesh& mesh, const CGAL_NP_CLASS& np) { - bool verified = true; if(CGAL::is_triangle_mesh(mesh)) - { - verified = verified && !CGAL::Polygon_mesh_processing::does_self_intersect(mesh); - CGAL_precondition_msg(verified, - "Conforming_constrained_Delaunay_triangulation_3: mesh self-intersects"); - } - else - { - PolygonMesh trimesh; - CGAL::copy_face_graph(mesh, trimesh, np); - CGAL::Polygon_mesh_processing::triangulate_faces(trimesh, np); - verified = verified && !CGAL::Polygon_mesh_processing::does_self_intersect(trimesh); - CGAL_precondition_msg(verified, - "Conforming_constrained_Delaunay_triangulation_3: mesh self-intersects"); - } - return verified; + return !CGAL::Polygon_mesh_processing::does_self_intersect(mesh, np); + PolygonMesh trimesh; + CGAL::copy_face_graph(mesh, trimesh, np); + bool OK = CGAL::Polygon_mesh_processing::triangulate_faces(trimesh, np); + if (!OK) return false; + return !CGAL::Polygon_mesh_processing::does_self_intersect(trimesh); + } + + template + bool preconditions_verified_soup(const PointRange& points, + const PolygonRange& polygons, + const CGAL_NP_CLASS& np) + { + return CGAL::Polygon_mesh_processing::does_polygon_soup_self_intersect(points, polygons, np); } #endif @@ -625,119 +624,120 @@ public: // ---------------------------------- const bool check_preconditions = parameters::choose_parameter(parameters::get_parameter(np, internal_np::check_preconditions), false); - if(!check_preconditions || preconditions_verified(mesh, np)) - { - auto mesh_vp_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get(CGAL::vertex_point, mesh)); - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - std::vector>> patch_edges; + CGAL_precondition_msg(check_preconditions || preconditions_verified_mesh(mesh, np), "Conforming_constrained_Delaunay_triangulation_3: mesh self-intersects"); - auto v_selected_map = get(CGAL::dynamic_vertex_property_t{}, mesh); + if(check_preconditions && !preconditions_verified_mesh(mesh, np)) return; - int number_of_patches = 0; - constexpr bool has_face_patch_map = !parameters::is_default_parameter::value; + auto mesh_vp_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), + get(CGAL::vertex_point, mesh)); - if constexpr (has_face_patch_map) { - auto mesh_face_patch_map = parameters::get_parameter(np, internal_np::face_patch); - using Patch_id_type = CGAL::cpp20::remove_cvref_t; - Patch_id_type max_patch_id{0}; - for(auto f : faces(mesh)) { - max_patch_id = (std::max)(max_patch_id, get(mesh_face_patch_map, f)); - } - number_of_patches = static_cast(max_patch_id + 1); - patch_edges.resize(number_of_patches); - for(auto h : halfedges(mesh)) { - if(is_border(h, mesh)) - continue; - auto f = face(h, mesh); - auto patch_id = get(mesh_face_patch_map, f); - auto opp = opposite(h, mesh); - if(is_border(opp, mesh) || patch_id != get(mesh_face_patch_map, face(opp, mesh))) { - auto va = source(h, mesh); - auto vb = target(h, mesh); - patch_edges[patch_id].emplace_back(va, vb); - put(v_selected_map, va, true); - put(v_selected_map, vb, true); - } - } + using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + std::vector>> patch_edges; - } else { - number_of_patches = num_faces(mesh); + auto v_selected_map = get(CGAL::dynamic_vertex_property_t{}, mesh); + + int number_of_patches = 0; + constexpr bool has_face_patch_map = !parameters::is_default_parameter::value; + + if constexpr (has_face_patch_map) { + auto mesh_face_patch_map = parameters::get_parameter(np, internal_np::face_patch); + using Patch_id_type = CGAL::cpp20::remove_cvref_t; + Patch_id_type max_patch_id{0}; + for(auto f : faces(mesh)) { + max_patch_id = (std::max)(max_patch_id, get(mesh_face_patch_map, f)); } - - using Vertex_handle = typename Triangulation::Vertex_handle; - using Cell_handle = typename Triangulation::Cell_handle; - auto tr_vertex_map = get(CGAL::dynamic_vertex_property_t(), mesh); - Cell_handle hint_ch{}; - for(auto v : vertices(mesh)) { - if constexpr(has_face_patch_map) { - if(false == get(v_selected_map, v)) continue; - } - auto p = get(mesh_vp_map, v); - auto vh = cdt_impl.insert(p, hint_ch, false); - vh->ccdt_3_data().set_vertex_type(CDT_3_vertex_type::CORNER); - hint_ch = vh->cell(); - put(tr_vertex_map, v, vh); - } - - cdt_impl.add_bbox_points_if_not_dimension_3(); - - struct { - decltype(tr_vertex_map)* vertex_map; - auto operator()(vertex_descriptor v) const { return get(*vertex_map, v); } - } tr_vertex_fct{&tr_vertex_map}; - - if constexpr(has_face_patch_map) { - for(int i = 0; i < number_of_patches; ++i) { - auto& edges = patch_edges[i]; - if(edges.empty()) - continue; - auto polylines = segment_soup_to_polylines(edges); - while(true) { - const auto non_closed_polylines_begin = - std::partition(polylines.begin(), polylines.end(), - [](const auto& polyline) { return polyline.front() == polyline.back(); }); - if(non_closed_polylines_begin == polylines.end()) - break; - edges.clear(); - for(auto it = non_closed_polylines_begin; it != polylines.end(); ++it) { - auto& polyline = *it; - for(auto it = polyline.begin(), end = polyline.end() - 1; it != end; ++it) { - edges.emplace_back(*it, *(it + 1)); - } - } - polylines.erase(non_closed_polylines_begin, polylines.end()); - auto other_polylines = segment_soup_to_polylines(edges); - polylines.insert(polylines.end(), std::make_move_iterator(other_polylines.begin()), - std::make_move_iterator(other_polylines.end())); - } - - std::optional face_index; - for(auto& polyline : polylines) { - CGAL_assertion(polyline.front() == polyline.back()); - polyline.pop_back(); - auto begin = boost::make_transform_iterator(polyline.begin(), tr_vertex_fct); - auto end = boost::make_transform_iterator(polyline.end(), tr_vertex_fct); - face_index = cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false, - face_index ? *face_index : -1); - } - } - } else { - for(auto f : faces(mesh)) { - auto face_vertices = vertices_around_face(halfedge(f, mesh), mesh); - - auto begin = boost::make_transform_iterator(face_vertices.begin(), tr_vertex_fct); - auto end = boost::make_transform_iterator(face_vertices.end(), tr_vertex_fct); - - cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false); + number_of_patches = static_cast(max_patch_id + 1); + patch_edges.resize(number_of_patches); + for(auto h : halfedges(mesh)) { + if(is_border(h, mesh)) + continue; + auto f = face(h, mesh); + auto patch_id = get(mesh_face_patch_map, f); + auto opp = opposite(h, mesh); + if(is_border(opp, mesh) || patch_id != get(mesh_face_patch_map, face(opp, mesh))) { + auto va = source(h, mesh); + auto vb = target(h, mesh); + patch_edges[patch_id].emplace_back(va, vb); + put(v_selected_map, va, true); + put(v_selected_map, vb, true); } } - cdt_impl.restore_Delaunay(); - cdt_impl.restore_constrained_Delaunay(); - // std::cerr << cdt_3_format("cdt_impl: {} vertices, {} cells\n", cdt_impl.number_of_vertices(), - // cdt_impl.number_of_cells()); + } else { + number_of_patches = num_faces(mesh); } + + using Vertex_handle = typename Triangulation::Vertex_handle; + using Cell_handle = typename Triangulation::Cell_handle; + auto tr_vertex_map = get(CGAL::dynamic_vertex_property_t(), mesh); + Cell_handle hint_ch{}; + for(auto v : vertices(mesh)) { + if constexpr(has_face_patch_map) { + if(false == get(v_selected_map, v)) continue; + } + auto p = get(mesh_vp_map, v); + auto vh = cdt_impl.insert(p, hint_ch, false); + vh->ccdt_3_data().set_vertex_type(CDT_3_vertex_type::CORNER); + hint_ch = vh->cell(); + put(tr_vertex_map, v, vh); + } + + cdt_impl.add_bbox_points_if_not_dimension_3(); + + struct { + decltype(tr_vertex_map)* vertex_map; + auto operator()(vertex_descriptor v) const { return get(*vertex_map, v); } + } tr_vertex_fct{&tr_vertex_map}; + + if constexpr(has_face_patch_map) { + for(int i = 0; i < number_of_patches; ++i) { + auto& edges = patch_edges[i]; + if(edges.empty()) + continue; + auto polylines = segment_soup_to_polylines(edges); + while(true) { + const auto non_closed_polylines_begin = + std::partition(polylines.begin(), polylines.end(), + [](const auto& polyline) { return polyline.front() == polyline.back(); }); + if(non_closed_polylines_begin == polylines.end()) + break; + edges.clear(); + for(auto it = non_closed_polylines_begin; it != polylines.end(); ++it) { + auto& polyline = *it; + for(auto it = polyline.begin(), end = polyline.end() - 1; it != end; ++it) { + edges.emplace_back(*it, *(it + 1)); + } + } + polylines.erase(non_closed_polylines_begin, polylines.end()); + auto other_polylines = segment_soup_to_polylines(edges); + polylines.insert(polylines.end(), std::make_move_iterator(other_polylines.begin()), + std::make_move_iterator(other_polylines.end())); + } + + std::optional face_index; + for(auto& polyline : polylines) { + CGAL_assertion(polyline.front() == polyline.back()); + polyline.pop_back(); + auto begin = boost::make_transform_iterator(polyline.begin(), tr_vertex_fct); + auto end = boost::make_transform_iterator(polyline.end(), tr_vertex_fct); + face_index = cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false, + face_index ? *face_index : -1); + } + } + } else { + for(auto f : faces(mesh)) { + auto face_vertices = vertices_around_face(halfedge(f, mesh), mesh); + + auto begin = boost::make_transform_iterator(face_vertices.begin(), tr_vertex_fct); + auto end = boost::make_transform_iterator(face_vertices.end(), tr_vertex_fct); + + cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false); + } + } + cdt_impl.restore_Delaunay(); + cdt_impl.restore_constrained_Delaunay(); + // std::cerr << cdt_3_format("cdt_impl: {} vertices, {} cells\n", cdt_impl.number_of_vertices(), + // cdt_impl.number_of_cells()); } /*! @@ -754,6 +754,13 @@ public: // ---------------------------------- // cstr... (polygon soup) // ---------------------------------- + const bool check_preconditions = + parameters::choose_parameter(parameters::get_parameter(np, internal_np::check_preconditions), false); + + CGAL_precondition_msg(check_preconditions || preconditions_verified_soup(points, polygons, np), "Conforming_constrained_Delaunay_triangulation_3: polygon soup self-intersects"); + + if(check_preconditions && !preconditions_verified_soup(points, polygons, np)) return; + using PointRange_const_iterator = typename PointRange::const_iterator; using PointRange_value_type = typename std::iterator_traits::value_type; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_self_intersections.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_self_intersections.h index 971f65d24a4..d963e6a5010 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_self_intersections.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_self_intersections.h @@ -42,7 +42,9 @@ bool does_polygon_soup_self_intersect(const PointRange& points, // otherwise, we need to triangulate the polygons beforehand using Polygon = CGAL::cpp20::remove_cvref_t; std::vector triangles(polygons.begin(), polygons.end()); - triangulate_polygons(points, triangles, np); + bool OK = triangulate_polygons(points, triangles, np); + + if (!OK) return false; return does_triangle_soup_self_intersect(points, triangles, np); }