diff --git a/Constrained_triangulation_3/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt b/Constrained_triangulation_3/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt index 92c4b6f64cc..e299c39b6b1 100644 --- a/Constrained_triangulation_3/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt +++ b/Constrained_triangulation_3/doc/Constrained_triangulation_3/Constrained_triangulation_3.txt @@ -181,20 +181,18 @@ following example demonstrates how to build such a triangulation. \cgalExample{Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_from_soup.cpp } -\subsection CT_3_example_ccdt_fpmap Build a Conforming Constrained Delaunay Triangulation with Known Face Patches +\subsection CT_3_example_ccdt_fpmap Build a Conforming Constrained Delaunay Triangulation with Known Polygon Identifiers -If the user already knows the set of patch identifiers to associate with each face, this information can be +If the user already knows the set of polygon identifiers to associate with each face, this information can be provided and preserved throughout the construction of the conforming constrained Delaunay triangulation. The following example demonstrates how to detect surface patches separated by sharp edges and use this segmentation during the tetrahedralization process. -When the named parameter `face_patch_map` is specified, -the face constraint indices in the 3D triangulation (accessible -via `CGAL::Conforming_constrained_Delaunay_triangulation_cell_data_3::face_constraint_index()`) are -set to the corresponding patch identifiers from the given property map. If this parameter is not provided, each -input polygon is assigned a unique face index. +When the named parameter `plc_face_id` is specified, each constrained face in the 3D triangulation +is assigned to the corresponding input PLC face, identified in the provided property map. +If this parameter is not specified, each input polygon, or PLC face, is given a unique face index. \cgalExample{Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_fpmap.cpp} diff --git a/Constrained_triangulation_3/examples/Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_fpmap.cpp b/Constrained_triangulation_3/examples/Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_fpmap.cpp index 30e4eabee4d..7af6e26962e 100644 --- a/Constrained_triangulation_3/examples/Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_fpmap.cpp +++ b/Constrained_triangulation_3/examples/Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_fpmap.cpp @@ -37,7 +37,7 @@ int main(int argc, char* argv[]) std::cout << "Wrote segmented mesh to " << filename << "\n"; auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh, - CGAL::parameters::face_patch_map(face_patch_map)); + CGAL::parameters::plc_face_id(face_patch_map)); std::cout << "Number of vertices in the CDT: " << ccdt.triangulation().number_of_vertices() << '\n' @@ -47,7 +47,7 @@ int main(int argc, char* argv[]) filename = argc > 3 ? argv[3] : "out.mesh"; std::ofstream out(filename); out.precision(17); - CGAL::IO::write_MEDIT(out, ccdt); + CGAL::IO::write_MEDIT(out, ccdt, CGAL::parameters::with_plc_face_id(true)); std::cout << "Wrote CDT to " << filename << "\n"; return EXIT_SUCCESS; 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 e3bd5f60fc7..5bb76a99090 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 @@ -658,14 +658,14 @@ public: 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; + constexpr bool has_plc_face_id = !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; + if constexpr (has_plc_face_id) { + auto mesh_plc_face_id = parameters::get_parameter(np, internal_np::plc_face_id); + 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)); + max_patch_id = (std::max)(max_patch_id, get(mesh_plc_face_id, f)); } number_of_patches = static_cast(max_patch_id + 1); patch_edges.resize(number_of_patches); @@ -673,9 +673,9 @@ public: if(is_border(h, mesh)) continue; auto f = face(h, mesh); - auto patch_id = get(mesh_face_patch_map, f); + auto patch_id = get(mesh_plc_face_id, f); auto opp = opposite(h, mesh); - if(is_border(opp, mesh) || patch_id != get(mesh_face_patch_map, face(opp, mesh))) { + if(is_border(opp, mesh) || patch_id != get(mesh_plc_face_id, face(opp, mesh))) { auto va = source(h, mesh); auto vb = target(h, mesh); patch_edges[patch_id].emplace_back(va, vb); @@ -692,7 +692,7 @@ public: 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 constexpr(has_plc_face_id) { if(false == get(v_selected_map, v)) continue; } auto p = get(mesh_vp_map, v); @@ -709,7 +709,7 @@ public: auto operator()(vertex_descriptor v) const { return get(*vertex_map, v); } } tr_vertex_fct{&tr_vertex_map}; - if constexpr(has_face_patch_map) { + if constexpr(has_plc_face_id) { for(int i = 0; i < number_of_patches; ++i) { auto& edges = patch_edges[i]; if(edges.empty()) @@ -792,12 +792,12 @@ public: auto point_map = choose_parameter(get_parameter(np, internal_np::point_map), CGAL::Identity_property_map{}); - constexpr bool has_face_patch_map = !parameters::is_default_parameter::value; + constexpr bool has_plc_face_id = !parameters::is_default_parameter::value; using std::cbegin; using std::cend; - if constexpr (false == has_face_patch_map) { + if constexpr (false == has_plc_face_id) { using Vertex_handle = typename Triangulation::Vertex_handle; using Cell_handle = typename Triangulation::Cell_handle; using Vec_vertex_handle = std::vector; @@ -836,7 +836,7 @@ public: using PID = CGAL::cpp20::remove_cvref_t; constexpr auto invalid_patch_id = (std::numeric_limits::max)(); Surface_mesh surface_mesh; - auto face_patch_pmap = + auto plc_face_id_pmap = surface_mesh.template add_property_map("fpm", invalid_patch_id).first; auto to_point = [point_map](const PointRange_value_type& v) { return get(point_map, v); }; @@ -849,14 +849,14 @@ public: PMP::orient_polygon_soup(rw_points, rw_polygons); auto polygon_to_face_output_iterator = boost::make_function_output_iterator( - [face_patch_pmap, polygon_patch_map](std::pair pid_f) { - put(face_patch_pmap, pid_f.second, get(polygon_patch_map, pid_f.first)); + [plc_face_id_pmap, polygon_patch_map](std::pair pid_f) { + put(plc_face_id_pmap, pid_f.second, get(polygon_patch_map, pid_f.first)); }); PMP::polygon_soup_to_polygon_mesh(std::move(rw_points), std::move(rw_polygons), surface_mesh, np.polygon_to_face_output_iterator(polygon_to_face_output_iterator)); Conforming_constrained_Delaunay_triangulation_3 ccdt{std::move(surface_mesh), - CGAL::parameters::face_patch_map(face_patch_pmap) + CGAL::parameters::plc_face_id(plc_face_id_pmap) .do_self_intersection_tests(false) .geom_traits(cdt_impl.geom_traits())}; *this = std::move(ccdt); diff --git a/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h b/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h index c72925a7bea..f3c87c11314 100644 --- a/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h +++ b/Constrained_triangulation_3/include/CGAL/IO/write_MEDIT.h @@ -12,6 +12,10 @@ #include "CGAL/type_traits.h" #include "CGAL/unordered_flat_map.h" #include + +#include +#include + #include #include @@ -27,12 +31,24 @@ namespace IO * file format. * @param os the output stream * @param ccdt the conforming constrained Delaunay triangulation to be written + * \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * + * \cgalNamedParamsBegin + * \cgalParamNBegin{with_plc_face_id} + * \cgalParamDescription{a Boolean activating the numbering of PLC face identifiers in the output} + * \cgalParamType{Boolean} + * \cgalParamDefault{`false`} + * \cgalParamNEnd + * \cgalNamedParamsEnd + * \see \ref IOStreamMedit */ -template +template void write_MEDIT(std::ostream& os, - const Conforming_constrained_Delaunay_triangulation_3& ccdt) + const Conforming_constrained_Delaunay_triangulation_3& ccdt, + const NamedParameters& np = parameters::default_values()) { const auto& tr = ccdt.triangulation(); @@ -62,15 +78,21 @@ void write_MEDIT(std::ostream& os, } } + using parameters::choose_parameter; + using parameters::get_parameter; + const bool has_plc_face_id + = choose_parameter(get_parameter(np, internal_np::with_plc_face_id), false); + + auto plc_patch_map = boost::make_function_property_map([&](const Facet& f) + { return has_plc_face_id ? f.first->ccdt_3_data().face_constraint_index(f.second) + 1 : 1; }); + return SMDS_3::output_to_medit(os, tr, tr.finite_vertex_handles(), ccdt.constrained_facets(), tr.finite_cell_handles(), boost::make_function_property_map([](Vertex_handle) { return 0; }), - boost::make_function_property_map([](const Facet& f) { - return f.first->ccdt_3_data().face_constraint_index(f.second) + 1; - }), + plc_patch_map, boost::make_function_property_map([&](Cell_handle ch) { return cells_in_domain[ch] ? 1 : 0; })); diff --git a/Constrained_triangulation_3/include/CGAL/make_conforming_constrained_Delaunay_triangulation_3.h b/Constrained_triangulation_3/include/CGAL/make_conforming_constrained_Delaunay_triangulation_3.h index 2c3ad815691..65f71bba9eb 100644 --- a/Constrained_triangulation_3/include/CGAL/make_conforming_constrained_Delaunay_triangulation_3.h +++ b/Constrained_triangulation_3/include/CGAL/make_conforming_constrained_Delaunay_triangulation_3.h @@ -20,6 +20,9 @@ #include #include +#include +#include + namespace CGAL { /*! @@ -39,14 +42,14 @@ namespace CGAL { during the triangulation process. By default, each face of the input is considered a polygonal constraint for the triangulation. The - named parameter `face_patch_map` can be used to describe larger polygonal constraints, possibly with holes. If + named parameter `plc_face_id` can be used to describe larger polygonal constraints, possibly with holes. If used, this parameter must be a property map that associates each face of the input with a patch identifier. Faces with the same patch identifier are considered part of the same surface patch. Each of these surface patches (defined as the union of the input faces with a given patch identifier) is expected to be a polygon or a polygon with holes, with coplanar vertices (or nearly coplanar up to the precision of the number type used). The generated triangulation will conform to the faces of the input, or to the surface patches - described by the `face_patch_map` property map if provided. + described by the `plc_face_id` property map if provided. \pre The input data must not be coplanar. @@ -108,11 +111,13 @@ namespace CGAL { * must be available in `PolygonMesh`.} * \cgalParamNEnd * - * \cgalParamNBegin{face_patch_map} - * \cgalParamDescription{a property map associating a patch identifier to each face of `mesh`} + * \cgalParamNBegin{plc_face_id} + * \cgalParamDescription{a property map associating a patch identifier to each face of `mesh`. + * Each identifier corresponds to a planar surface patch. Each surface + * patch can be composed of several faces of `mesh`, forming a planar polygon.} * \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits::%face_descriptor` * as key type and with any value type that is a *regular* type (model of `Regular`)} - * \cgalParamExtra{If this parameter is omitted, each face of the mesh is considered a separate patch. + * \cgalParamExtra{If this parameter is omitted, each face of `mesh` is considered a separate patch. * Faces with the same patch identifier are considered part of the same surface patch.} * \cgalParamNEnd * @@ -182,8 +187,10 @@ auto make_conforming_constrained_Delaunay_triangulation_3(const PolygonMesh &mes * \cgalParamDefault{`CGAL::Identity_property_map`} * \cgalParamNEnd * - * \cgalParamNBegin{face_patch_map} - * \cgalParamDescription{a property map associating a patch identifier to each face of `soup`} + * \cgalParamNBegin{plc_face_id} + * \cgalParamDescription{a property map associating a patch identifier to each face of `soup`. + * Each identifier corresponds to a planar surface patch. Each surface + * patch can be composed of several faces of `soup`, forming a planar polygon.} * \cgalParamType{a class model of `ReadWritePropertyMap` with `std::size_t` * as key type and with any value type that is a *regular* type (model of `Regular`)} * \cgalParamExtra{If this parameter is omitted, each face of the polygon soup is considered a separate patch.} 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 c2673ce9dde..b6456a2307c 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -404,3 +404,7 @@ CGAL_add_named_parameter(do_not_modify_geometry_t, do_not_modify_geometry, do_no //List of named parameters used in Straight_skeleton_2 CGAL_add_named_parameter_with_compatibility_ref_only(angles_param_t, angles_param, angles) CGAL_add_named_parameter(maximum_height_t, maximum_height, maximum_height) + +// List of named parameters used in the package 'Constrained_triangulation_3' +CGAL_add_named_parameter(plc_face_id_t, plc_face_id, plc_face_id) +CGAL_add_named_parameter(with_plc_face_id_t, with_plc_face_id, with_plc_face_id)