@@ -1274,6 +1274,7 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
12741274 using Geom_traits = typename T_3::Geom_traits;
12751275 using Point_3 = typename T_3::Point;
12761276 using Segment_3 = typename Geom_traits::Segment_3;
1277+ using Triangle_3 = typename Geom_traits::Triangle_3;
12771278 using Vector_3 = typename Geom_traits::Vector_3;
12781279 using Locate_type = typename T_3::Locate_type;
12791280 using size_type = typename T_3::size_type;
@@ -1486,21 +1487,24 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
14861487 return std::nullopt ;
14871488 }
14881489
1489- template <typename Offsets , typename Facets >
1490+ template <typename Components , typename Map >
14901491 CGAL::Surface_mesh<Point_3>
14911492 construct_star_component_mesh (std::size_t component_index,
1492- const Offsets& component_offsets ,
1493- const Facets& facets ) const
1493+ const Components& components ,
1494+ const Map& map_from_incident_constraint_face_id_to_new_triangles ) const
14941495 {
14951496 CGAL::Surface_mesh<Point_3> component_mesh;
14961497 std::vector<Point_3> points;
14971498 std::vector<std::array<std::size_t , 3 >> triangles;
14981499 std::size_t vertex_index = 0 ;
1499- for (std::size_t facet_id = component_offsets[component_index - 1 ],
1500- end = component_offsets[component_index];
1500+ for (std::size_t facet_id = components. component_offsets [component_index - 1 ],
1501+ end = components. component_offsets [component_index];
15011502 facet_id < end; ++facet_id)
15021503 {
1503- const auto & [cell, facet_index, _] = facets[facet_id];
1504+ const auto & [cell, facet_index, type] = components.facets [facet_id];
1505+ if (type == Star_components_facets::Type_of_facet::INCIDENT_TO_V) {
1506+ continue ;
1507+ }
15041508 if (tr ().is_infinite (Facet (cell, facet_index))) {
15051509 continue ;
15061510 }
@@ -1512,34 +1516,40 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
15121516 triangles.push_back ({vertex_index, vertex_index + 2 , vertex_index + 1 });
15131517 vertex_index += 3 ;
15141518 } // end for each facet in the component
1519+ const auto & incident_face_ids = components.component_incident_constraint_face_ids [component_index - 1 ];
1520+ for (auto face_id : incident_face_ids) {
1521+ const auto & new_triangles = map_from_incident_constraint_face_id_to_new_triangles.at (face_id);
1522+ for (const auto & triangle : new_triangles) {
1523+ points.push_back (triangle[0 ]);
1524+ points.push_back (triangle[1 ]);
1525+ points.push_back (triangle[2 ]);
1526+ triangles.push_back ({vertex_index, vertex_index + 1 , vertex_index + 2 });
1527+ vertex_index += 3 ;
1528+ }
1529+ }
15151530 CGAL::Polygon_mesh_processing::merge_duplicate_points_in_polygon_soup (points, triangles);
1516-
1517- std::vector<std::pair<std::size_t , typename CGAL::Surface_mesh<Point_3>::Face_index>>
1518- triangle_index_to_face_descriptor;
1519- CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh (
1520- points,
1521- triangles,
1522- component_mesh,
1523- CGAL::parameters::polygon_to_face_output_iterator (std::back_inserter (triangle_index_to_face_descriptor)));
1531+ CGAL::Polygon_mesh_processing::orient_polygon_soup (points, triangles);
1532+ CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh (points, triangles, component_mesh);
15241533 return component_mesh;
15251534 }
15261535
15271536 std::optional<Point_3> compute_center_point_if_possible (const CGAL::Surface_mesh<Point_3>& component_mesh) const {
15281537 return CGAL::Polygon_mesh_processing::kernel_point (component_mesh, parameters::allow_open_input (true ));
15291538 }
15301539
1531- template <typename Offsets , typename Facets >
1540+ template <typename Components , typename Map >
15321541 CGAL::Surface_mesh<Point_3>
1533- construct_link_mesh_for_debug (const Offsets& component_offsets ,
1534- const Facets& facets ) const
1542+ construct_link_mesh_for_debug (const Components& components ,
1543+ const Map& map_from_incident_constraint_face_id_to_new_triangles ) const
15351544 {
15361545 using Mesh = CGAL::Surface_mesh<Point_3>;
15371546 using face_descriptor = typename Mesh::Face_index;
15381547 Mesh link_mesh;
15391548 auto [patch_id_map, _] = link_mesh.template add_property_map <face_descriptor, int >(" f:patch_id" , 0 );
15401549
1541- for (std::size_t component_index = 1 ; component_index < component_offsets.size (); ++component_index) {
1542- Mesh component_mesh = construct_star_component_mesh (component_index, component_offsets, facets);
1550+ for (std::size_t component_index = 1 ; component_index < components.component_offsets .size (); ++component_index) {
1551+ Mesh component_mesh = construct_star_component_mesh (component_index, components,
1552+ map_from_incident_constraint_face_id_to_new_triangles);
15431553
15441554 std::vector<face_descriptor> new_faces;
15451555 auto out_it = boost::make_function_output_iterator (
@@ -1552,9 +1562,12 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
15521562 return link_mesh;
15531563 }
15541564
1555- template <typename Offsets, typename Facets>
1556- void dump_link_mesh_of_vertex_to_ply (Vertex_handle v, const Offsets& component_offsets, const Facets& facets) const {
1557- const auto link_mesh = construct_link_mesh_for_debug (component_offsets, facets);
1565+ template <typename Components, typename Map>
1566+ void dump_link_mesh_of_vertex_to_ply (Vertex_handle v,
1567+ const Components& components,
1568+ const Map& map_from_incident_constraint_face_id_to_new_triangles) const {
1569+ const auto link_mesh =
1570+ construct_link_mesh_for_debug (components, map_from_incident_constraint_face_id_to_new_triangles);
15581571
15591572 std::stringstream filename;
15601573 filename << " dump_link_mesh_vertex" << IO::oformat (v, With_offset_tag{}) << " .ply" ;
@@ -1759,15 +1772,18 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
17591772 return out;
17601773 } // end collect_star_components_facets(..)
17611774
1762- template <typename New_CDT_2_face_handles_output_iterator, typename Map_from_hole_edge_to_facet_3d>
1775+ enum Run_mode { NORMAL_RUN, DRY_RUN };
1776+
1777+ template <typename CDT_2, typename New_CDT_2_face_handles_output_iterator, typename Map_from_hole_edge_to_facet_3d>
17631778 std::pair<New_CDT_2_face_handles_output_iterator, Facet>
17641779 fill_cdt_2_hole_with_delaunay (CDT_2& cdt_2,
17651780 Face_index face_index,
17661781 CDT_3_vertex_type vertex_type,
17671782 std::list<CDT_2_edge>& hole_boundary,
17681783 const Map_from_hole_edge_to_facet_3d& map_from_hole_edge_to_facet_3d,
17691784 Face_is_outside_the_face is_outside_the_face,
1770- New_CDT_2_face_handles_output_iterator new_face_handles_out)
1785+ New_CDT_2_face_handles_output_iterator new_face_handles_out,
1786+ Run_mode run_mode = NORMAL_RUN)
17711787 {
17721788 const bool is_a_half_hole = vertex_type == CDT_3_vertex_type::STEINER_ON_EDGE;
17731789 if (this ->debug ().move_Steiner_vertices ()) {
@@ -1985,7 +2001,16 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
19852001
19862002 *new_face_handles_out++ = fh_2d;
19872003 }; // end of `action_for_each_new_2d_face`
1988- CGAL::fill_hole_delaunay (cdt_2, hole_boundary, boost::make_function_output_iterator (action_for_each_new_2d_face));
2004+ switch (run_mode) {
2005+ case NORMAL_RUN:
2006+ CGAL::fill_hole_delaunay (cdt_2, hole_boundary, boost::make_function_output_iterator (action_for_each_new_2d_face));
2007+ break ;
2008+ case DRY_RUN:
2009+ CGAL::fill_hole_delaunay (cdt_2, hole_boundary, new_face_handles_out);
2010+ break ;
2011+ default :
2012+ CGAL_unreachable ();
2013+ }
19892014 return {new_face_handles_out, half_hole_front_facet};
19902015 }
19912016
@@ -1994,12 +2019,20 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
19942019 remove_Steiner_vertex_from_cdt_2 (Vertex_handle v,
19952020 CDT_3_vertex_type vertex_type,
19962021 Face_index face_id,
1997- New_CDT_2_face_handles_output_iterator new_face_handles_out)
2022+ New_CDT_2_face_handles_output_iterator new_face_handles_out,
2023+ Run_mode run_mode = NORMAL_RUN)
19982024 {
19992025 std::tuple<New_CDT_2_face_handles_output_iterator, Facet, Facet> result{new_face_handles_out, {}, {}};
20002026 auto & [new_face_handles_out_it, half_hole_front_facet, second_half_hole_front_facet] = result;
2001- auto & mutable_cdt_2 = non_const_face_cdt_2 (face_id);
2002- const auto & cdt_2 = mutable_cdt_2;
2027+
2028+ using CDT_2_base = typename CDT_2::Triangulation;
2029+ auto & original_mutable_cdt_2 = static_cast <CDT_2_base&>(non_const_face_cdt_2 (face_id));
2030+ std::unique_ptr<CDT_2_base> cdt_2_copy_ptr{};
2031+ if (run_mode == DRY_RUN) {
2032+ cdt_2_copy_ptr.reset (new CDT_2_base (original_mutable_cdt_2));
2033+ }
2034+ auto & mutable_cdt_2 = (run_mode == DRY_RUN) ? *cdt_2_copy_ptr : original_mutable_cdt_2;
2035+ const auto & cdt_2 = mutable_cdt_2;
20032036
20042037 typename CDT_2::Locate_type lt;
20052038 int i;
@@ -2089,7 +2122,7 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
20892122 std::for_each (faces_to_delete.begin (), faces_to_delete.end (),
20902123 [&mutable_cdt_2](CDT_2_face_handle f) { mutable_cdt_2.delete_face (f); });
20912124 return fill_cdt_2_hole_with_delaunay (mutable_cdt_2, face_id, vertex_type, hole_boundary, hole_boundary_map,
2092- is_outside_the_face, new_face_handles_out);
2125+ is_outside_the_face, new_face_handles_out, run_mode );
20932126 };
20942127
20952128 auto set_constrained = [&](CDT_2_edge e, bool is_constrained) {
@@ -2170,7 +2203,8 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
21702203 auto [out_it, facet_side_1] = bore_hole_and_fill_with_delaunay (
21712204 vertex_type, hole_side_1, hole_side_1_faces_to_delete, side_1_hole_is_outside_the_face);
21722205 new_face_handles_out = out_it;
2173- CGAL_assertion (side_1_hole_is_outside_the_face == OUTSIDE || facet_side_1.first != Cell_handle{});
2206+ CGAL_assertion (run_mode == DRY_RUN ||
2207+ side_1_hole_is_outside_the_face == OUTSIDE || facet_side_1.first != Cell_handle{});
21742208
21752209 // - now the edge opposite to `(side_2_last_face, side_2_last_edge_index)` is on the border of the hole
21762210 // `hole_side_2`, so we can start sewing from there
@@ -2179,7 +2213,8 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
21792213 auto [out_it_2, facet_side_2] = bore_hole_and_fill_with_delaunay (
21802214 vertex_type, hole_side_2, hole_side_2_faces_to_delete, side_2_hole_is_outside_the_face);
21812215 new_face_handles_out = out_it_2;
2182- CGAL_assertion (side_2_hole_is_outside_the_face == OUTSIDE || facet_side_2.first != Cell_handle{});
2216+ CGAL_assertion (run_mode == DRY_RUN ||
2217+ side_2_hole_is_outside_the_face == OUTSIDE || facet_side_2.first != Cell_handle{});
21832218
21842219 half_hole_front_facet = facet_side_1;
21852220 second_half_hole_front_facet = facet_side_2;
@@ -2264,13 +2299,42 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
22642299 }
22652300 return false ;
22662301 }
2302+ const auto v_type = vertex_type (v);
2303+
2304+ std::map<Face_index, std::vector<Triangle_3>> map_from_incident_constraint_face_id_to_new_triangles;
2305+
2306+ auto dry_run_output_iterator = [&](Face_index face_id) {
2307+ auto * triangles_for_this_face_ptr = &map_from_incident_constraint_face_id_to_new_triangles[face_id];
2308+ std::function<void (CDT_2_face_handle)> func = [&,triangles_for_this_face_ptr](CDT_2_face_handle fh_2d) {
2309+ const auto v1 = vertex_3d (fh_2d->vertex (0 ));
2310+ const auto v2 = vertex_3d (fh_2d->vertex (1 ));
2311+ const auto v3 = vertex_3d (fh_2d->vertex (2 ));
2312+ triangles_for_this_face_ptr->emplace_back (v1->point (), v2->point (), v3->point ());
2313+ };
2314+ return boost::make_function_output_iterator (func);
2315+ };
2316+
2317+ if (v_type == CDT_3_vertex_type::STEINER_IN_FACE) {
2318+ CGAL_assertion (star_components.component_incident_constraint_face_ids .size () == 2 );
2319+ [[maybe_unused]] const auto & [face_id, _] = star_components.face_ids_between_consecutive_components .front ();
2320+ remove_Steiner_vertex_from_cdt_2 (v, v_type, face_id, dry_run_output_iterator (face_id), DRY_RUN);
2321+ } else {
2322+ CGAL_assertion (v_type == CDT_3_vertex_type::STEINER_ON_EDGE);
2323+ for (std::size_t component_index = 0 , end = star_components.face_ids_between_consecutive_components .size ();
2324+ component_index < end; ++component_index)
2325+ {
2326+ const auto & [face_id, _] = star_components.face_ids_between_consecutive_components [component_index];
2327+
2328+ remove_Steiner_vertex_from_cdt_2 (v, v_type, face_id, dry_run_output_iterator (face_id), DRY_RUN);
2329+ }
2330+ }
22672331
22682332 const auto components_central_points = std::invoke ([&]() {
22692333 std::optional<boost::container::small_vector<Point_3, 8 >> central_points{std::in_place};
22702334 central_points->reserve (nb_of_star_components);
22712335 for (std::size_t component_index = 1 ; component_index <= nb_of_star_components; ++component_index) {
2272- auto component_mesh =
2273- construct_star_component_mesh (component_index, star_components. component_offsets , star_components. facets );
2336+ auto component_mesh = construct_star_component_mesh (component_index, star_components,
2337+ map_from_incident_constraint_face_id_to_new_triangles );
22742338 auto opt_kernel_center_point = compute_center_point_if_possible (component_mesh);
22752339 if (this ->debug ().move_Steiner_vertices ()) {
22762340 std::cerr << " - incident constraint faces ids of component #" << component_index << " : {"
@@ -2300,7 +2364,7 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
23002364 }); // end compute central points for each component
23012365
23022366 if (this ->debug ().move_Steiner_vertices ()) {
2303- dump_link_mesh_of_vertex_to_ply (v, star_components. component_offsets , star_components. facets );
2367+ dump_link_mesh_of_vertex_to_ply (v, star_components, map_from_incident_constraint_face_id_to_new_triangles );
23042368 }
23052369
23062370 if (!components_central_points.has_value ()) {
@@ -2356,7 +2420,6 @@ class Conforming_constrained_Delaunay_triangulation_3_impl : public Conforming_D
23562420 std::size_t nb_of_new_2d_faces = 0 ;
23572421 CGAL::Counting_output_iterator output_iterator{&nb_of_new_2d_faces};
23582422
2359- const auto v_type = vertex_type (v);
23602423 if (v_type == CDT_3_vertex_type::STEINER_IN_FACE) {
23612424 CGAL_assertion (star_components.component_incident_constraint_face_ids .size () == 2 );
23622425 const auto & [face_id, orientation] = star_components.face_ids_between_consecutive_components .front ();
0 commit comments