diff --git a/Triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h b/Triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h index 983b8ce93f6..effcab37312 100644 --- a/Triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Conforming_Delaunay_triangulation_3.h @@ -466,7 +466,7 @@ public: } bool use_finite_edges_map() const { - return debug_flags[static_cast(Debug_flags::use_finite_edges_map)]; + return update_all_finite_edges_ && debug_flags[static_cast(Debug_flags::use_finite_edges_map)]; } void use_finite_edges_map(bool b) { @@ -497,13 +497,32 @@ public: return id; } + bool is_edge(Vertex_handle va, Vertex_handle vb) const { + const bool is_edge_v1 = + ((debug_finite_edges_map() && use_finite_edges_map()) || !use_finite_edges_map()) && tr.tds().is_edge(va, vb); + const bool is_edge_v2 = + use_finite_edges_map() && all_finite_edges.find(make_sorted_pair(va, vb)) != all_finite_edges.end(); + if(debug_finite_edges_map() && use_finite_edges_map() && is_edge_v1 != is_edge_v2) { + std::cerr << "!! Inconsistent edge status\n"; + std::cerr << " -> constraint " << display_vert(va) << " " << display_vert(vb) << '\n'; + std::cerr << " -> edge " << (is_edge_v1 ? "is" : "is not") << " in the triangulation\n"; + std::cerr << " -> edge " << (is_edge_v2 ? "is" : "is not") << " in all_finite_edges\n"; + debug_dump("bug-inconsistent-edge-status"); + CGAL_error(); + } + const bool is_edge = use_finite_edges_map() ? is_edge_v2 : is_edge_v1; + return is_edge; + } + + using T_3::is_edge; + bool is_conforming() const { return std::all_of(constraint_hierarchy.sc_begin(), constraint_hierarchy.sc_end(), [this](const auto &sc) { const auto va = sc.first.first; const auto vb = sc.first.second; - const auto is_edge = this->tr.tds().is_edge(va, vb); + const auto is_edge = this->is_edge(va, vb); #if CGAL_DEBUG_CDT_3 & 128 && __has_include() std::cerr << std::format("is_conforming>> Edge is 3D: {} ({} , {})\n", is_edge, @@ -592,7 +611,7 @@ public: std::for_each( constraint_hierarchy.sc_begin(), constraint_hierarchy.sc_end(), [this, &out, &any_missing_segment](const auto &sc) { - if (!tr.tds().is_edge(sc.first.first, sc.first.second)) { + if (!this->is_edge(sc.first.first, sc.first.second)) { const auto v0 = sc.first.first; const auto v1 = sc.first.second; out << "2 " << this->tr.point(v0) << " " << this->tr.point(v1) @@ -639,6 +658,7 @@ protected: template void restore_Delaunay(Visitor& visitor) { + update_all_finite_edges(); while(!subconstraints_to_conform.empty()) { const auto [subconstraint, constraint_id] = subconstraints_to_conform.top(); subconstraints_to_conform.pop(); @@ -685,20 +705,7 @@ protected: const Vertex_handle va = subconstraint.first; const Vertex_handle vb = subconstraint.second; CGAL_assertion(va != vb); - const bool is_edge_v1 = - ((debug_finite_edges_map() && use_finite_edges_map()) || !use_finite_edges_map()) && tr.tds().is_edge(va, vb); - const bool is_edge_v2 = - use_finite_edges_map() && all_finite_edges.find(make_sorted_pair(va, vb)) != all_finite_edges.end(); - if(debug_finite_edges_map() && use_finite_edges_map() && is_edge_v1 != is_edge_v2) { - std::cerr << "!! Inconsistent edge status\n"; - std::cerr << " -> constraint " << display_vert(va) << " " << display_vert(vb) << '\n'; - std::cerr << " -> edge " << (is_edge_v1 ? "is" : "is not") << " in the triangulation\n"; - std::cerr << " -> edge " << (is_edge_v2 ? "is" : "is not") << " in all_finite_edges\n"; - debug_dump("bug-inconsistent-edge-status"); - CGAL_error(); - } - const bool is_edge = use_finite_edges_map() ? is_edge_v2 : is_edge_v1; - if(!is_edge) { + if(!this->is_edge(va, vb)) { const auto& [steiner_pt, hint, ref_vertex] = construct_Steiner_point(constraint, subconstraint); [[maybe_unused]] const auto v = insert_Steiner_point_on_subconstraint(steiner_pt, hint, subconstraint, constraint, visitor); @@ -1015,6 +1022,20 @@ protected: using Hash = boost::hash; std::unordered_set all_finite_edges; + bool update_all_finite_edges_ = false; + + void update_all_finite_edges() { + if(!update_all_finite_edges_) { + update_all_finite_edges_ = true; + if(use_finite_edges_map()) { + all_finite_edges.clear(); + all_finite_edges.reserve(tr.number_of_finite_edges()); + for(auto e: tr.all_edges()) { + new_edge(e); + } + } + } + } enum class Debug_flags { Steiner_points = 0, diff --git a/Triangulation_3/include/CGAL/Constrained_Delaunay_triangulation_3.h b/Triangulation_3/include/CGAL/Constrained_Delaunay_triangulation_3.h index 633e0a8498b..685cfadd735 100644 --- a/Triangulation_3/include/CGAL/Constrained_Delaunay_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Constrained_Delaunay_triangulation_3.h @@ -1296,7 +1296,7 @@ private: CGAL_assertion(!cdt_2.is_edge(vb, vd)); const auto vb_3d = vb->info().vertex_handle_3d; const auto vd_3d = vd->info().vertex_handle_3d; - if(tr.tds().is_edge(vb_3d, vd_3d)) { + if(this->is_edge(vb_3d, vd_3d)) { // let's insert the diagonal [bd] in the CDT_2 cdt_2.insert_constraint(vb, vd); #if CGAL_DEBUG_CDT_3 & 64 @@ -2178,12 +2178,12 @@ private: ("NOTE: diagonal: {:.6} {:.6} {} in tr\n", IO::oformat(*diagonal.begin(), with_point), IO::oformat(*std::next(diagonal.begin()), with_point), - tr.tds().is_edge(*diagonal.begin(), *std::next(diagonal.begin())) ? "IS" : "is NOT"); + this->is_edge(*diagonal.begin(), *std::next(diagonal.begin())) ? "IS" : "is NOT"); std::cerr << std::format( "NOTE: the other diagonal: {:.6} {:.6} {} in tr\n", IO::oformat(*other_diagonal.begin(), with_point), IO::oformat(*std::next(other_diagonal.begin()), with_point), - tr.tds().is_edge(*other_diagonal.begin(), *std::next(other_diagonal.begin())) ? "IS" : "is NOT"); + this->is_edge(*other_diagonal.begin(), *std::next(other_diagonal.begin())) ? "IS" : "is NOT"); if(cdt_2.geom_traits().side_of_oriented_circle_2_object()( (*region_border_vertices.begin())->point(), (*std::next(region_border_vertices.begin()))->point(), (*std::next(region_border_vertices.begin(), 2))->point(), @@ -2979,7 +2979,7 @@ private: const auto i = edge.second; const auto va_3d = fh->vertex(cdt_2.cw(i))->info().vertex_handle_3d; const auto vb_3d = fh->vertex(cdt_2.ccw(i))->info().vertex_handle_3d; - const bool is_3d = this->tds().is_edge(va_3d, vb_3d); + const bool is_3d = this->is_edge(va_3d, vb_3d); #if CGAL_CDT_3_CAN_USE_CXX20_FORMAT if(this->debug_copy_triangulation_into_hole()) { std::cerr << std::format("Edge is 3D: {:6} ({} , {})\n", @@ -3150,7 +3150,7 @@ public: << " != number_of_finite_edges() = " << this->number_of_finite_edges() << std::endl; } for(auto e: this->all_finite_edges) { - test = this->tds().is_edge(e.first, e.second); + test = this->is_edge(e.first, e.second); result = result && test; if(!test && verbose) { std::cerr << "edge (" << IO::oformat(e.first, with_point_and_info) << ", " diff --git a/Triangulation_3/test/Triangulation_3/cdt_3_from_off.cpp b/Triangulation_3/test/Triangulation_3/cdt_3_from_off.cpp index 4205396ac68..60f4b48951b 100644 --- a/Triangulation_3/test/Triangulation_3/cdt_3_from_off.cpp +++ b/Triangulation_3/test/Triangulation_3/cdt_3_from_off.cpp @@ -54,8 +54,8 @@ using K = CGAL::Exact_predicates_inexact_constructions_kernel; #endif // use Epick -using Vb = CGAL::Constrained_Delaunay_triangulation_vertex_base_3; -using Cb = CGAL::Constrained_Delaunay_triangulation_cell_base_3; +struct Vb : public CGAL::Constrained_Delaunay_triangulation_vertex_base_3 {}; +struct Cb : public CGAL::Constrained_Delaunay_triangulation_cell_base_3 {}; using Tds = CGAL::Triangulation_data_structure_3; using Delaunay = CGAL::Delaunay_triangulation_3; using CDT = CGAL::Constrained_Delaunay_triangulation_3; @@ -81,6 +81,7 @@ struct CDT_options bool debug_validity = false; bool debug_finite_edges_map = false; bool use_finite_edges_map = false; + bool call_is_valid = true; double ratio = 0.1; double vertex_vertex_epsilon = 1e-14; double segment_vertex_epsilon = 1e-14; @@ -196,6 +197,8 @@ int main(int argc, char* argv[]) options.coplanar_polygon_max_distance = std::stod(argv[++i]); } else if(arg == "--quiet") { options.quiet = true; + } else if(arg == "--no-is-valid") { + options.call_is_valid = false; } else if(arg == "--debug-missing-regions") { options.debug_missing_regions = true; } else if(arg == "--debug-regions") { @@ -545,9 +548,11 @@ int go(Mesh mesh, CDT_options options) { CGAL_CDT_3_TASK_BEGIN(insert_vertices_task_handle); auto start_time = std::chrono::high_resolution_clock::now(); + CDT::Cell_handle hint{}; for(auto v: vertices(mesh)) { if(options.merge_facets && false == get(v_selected_map, v)) continue; - auto vh = cdt.insert(get(pmap, v)); + auto vh = cdt.insert(get(pmap, v), hint, false); + hint = vh->cell(); put(tr_vertex_pmap, v, vh); } if(!options.quiet) { @@ -776,9 +781,9 @@ int go(Mesh mesh, CDT_options options) { std::cerr << "Number of vertices after conforming: " << cdt.number_of_vertices() << "\n\n"; } CGAL_CDT_3_TASK_BEGIN(validation_task_handle); - CGAL_assertion(cdt.Delaunay::is_valid(true)); - CGAL_assertion(cdt.is_valid(true)); - CGAL_assertion(cdt.is_conforming()); + CGAL_assertion(!options.call_is_valid || cdt.Delaunay::is_valid(true)); + CGAL_assertion(!options.call_is_valid || cdt.is_valid(true)); + CGAL_assertion(!options.call_is_valid || cdt.is_conforming()); CGAL_CDT_3_TASK_END(validation_task_handle); if(exit_code == EXIT_SUCCESS) { try { @@ -802,8 +807,8 @@ int go(Mesh mesh, CDT_options options) { finally(); CGAL_CDT_3_TASK_BEGIN(validation_task_handle); - CGAL_assertion(cdt.is_conforming()); - CGAL_assertion(cdt.is_valid(true)); + CGAL_assertion(!options.call_is_valid || cdt.is_conforming()); + CGAL_assertion(!options.call_is_valid || cdt.is_valid(true)); CGAL_CDT_3_TASK_END(validation_task_handle); return exit_code;