diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h index 05ca9388ebb..d059c3eb33d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h @@ -547,6 +547,65 @@ bool clip(TriangleMesh& tm, return clip(tm, clipper, np, parameters::all_default()); } +/** + * \ingroup PMP_corefinement_grp + * clips `tm` by keeping the part that is inside `iso_cuboid`. + * If `tm` is closed, the clipped part can be closed too if the named parameter `clip_volume` is set to `true`. + * See Subsection \ref coref_clip for more details. + * + * \note In the current implementation it is not possible to set the vertex point map and the default will be used. `Iso_cuboid_3` must be + * from the same %Kernel as the point of the vertex point map. + * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink + * + * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. + * An internal property map for `CGAL::vertex_point_t` must be available. + * + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * + * @param tm input triangulated surface mesh + * @param iso_cuboid iso-cuboid used to clip `tm`. + * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor` + * that is used to track the creation of new faces. + * \cgalParamEnd + * \cgalParamBegin{throw_on_self_intersection} if `true`, + * the set of triangles closed to the intersection of `tm` and `iso_cuboid` will be + * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` + * will be thrown if at least one is found. + * \cgalParamEnd + * \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on + * the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface + * (i.e., `tm` will be kept closed). + * \cgalParamEnd + * \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `is_cuboid` + * will not be part of the output. + * \cgalNamedParamsEnd + * + * @return `true` if the output surface mesh is manifold. + * If `false` is returned `tm` is only refined by the intersection with `iso_cuboid`. + */ +template +bool clip(TriangleMesh& tm, +#ifdef DOXYGEN_RUNNING + const Iso_cuboid_3& iso_cuboid, +#else + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid, +#endif + const NamedParameters& np) +{ + if(boost::begin(faces(tm))==boost::end(faces(tm))) return true; + TriangleMesh clipper; + + make_hexahedron(iso_cuboid[0], iso_cuboid[1], iso_cuboid[2], iso_cuboid[3], + iso_cuboid[4], iso_cuboid[5], iso_cuboid[6], iso_cuboid[7], + clipper); + triangulate_faces(clipper); + + return clip(tm, clipper, np, parameters::all_default()); +} /*! * \ingroup PMP_corefinement_grp @@ -635,9 +694,6 @@ void split(TriangleMesh& tm, * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin - * \cgalParamBegin{vertex_point_map} - * the property map with the points associated to the vertices of `tm`. - * \cgalParamEnd * \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor` * that is used to track the creation of new faces. * \cgalParamEnd @@ -680,23 +736,22 @@ void split(TriangleMesh& tm, //else nothing to do, no intersection. } + /** * \ingroup PMP_corefinement_grp - * clips `tm` by keeping the part that is inside `iso_cuboid`. - * If `tm` is closed, the clipped part can be closed too if the named parameter `clip_volume` is set to `true`. - * See Subsection \ref coref_clip for more details. + * adds intersection edges of `iso_cuboid` and `tm` in `tm` and duplicates those edges. * - * \note In the current implementation it is not possible to set the vertex point map and the default will be used. `Iso_cuboid_3` must be - * from the same %Kernel as the point of the vertex point map. + * \note In the current implementation it is not possible to set the vertex point map and the default will be used. + * \note `Iso_cuboid_3` must be from the same %Kernel as the point of the vertex point map. * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink * - * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. + * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph` * An internal property map for `CGAL::vertex_point_t` must be available. * * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * * @param tm input triangulated surface mesh - * @param iso_cuboid iso-cuboid used to clip `tm`. + * @param iso_cuboid iso-cuboid used to split `tm`. * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin @@ -708,36 +763,26 @@ void split(TriangleMesh& tm, * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` * will be thrown if at least one is found. * \cgalParamEnd - * \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on - * the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface - * (i.e., `tm` will be kept closed). - * \cgalParamEnd - * \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `is_cuboid` - * will not be part of the output. * \cgalNamedParamsEnd - * - * @return `true` if the output surface mesh is manifold. - * If `false` is returned `tm` is only refined by the intersection with `iso_cuboid`. */ template -bool clip(TriangleMesh& tm, -#ifdef DOXYGEN_RUNNING - const Iso_cuboid_3& iso_cuboid, -#else - const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid, -#endif - const NamedParameters& np) +void split(TriangleMesh& tm, + #ifdef DOXYGEN_RUNNING + const Iso_cuboid_3& iso_cuboid, + #else + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid, + #endif + const NamedParameters& np) { - if(boost::begin(faces(tm))==boost::end(faces(tm))) return true; - TriangleMesh clipper; + TriangleMesh splitter; make_hexahedron(iso_cuboid[0], iso_cuboid[1], iso_cuboid[2], iso_cuboid[3], - iso_cuboid[4], iso_cuboid[5], iso_cuboid[6], iso_cuboid[7], - clipper); - triangulate_faces(clipper); + iso_cuboid[4], iso_cuboid[5], iso_cuboid[6], iso_cuboid[7], + splitter); + triangulate_faces(splitter); - return clip(tm, clipper, np, parameters::all_default()); + split(tm, splitter, np, parameters::all_default()); } /// \cond SKIP_IN_MANUAL @@ -806,6 +851,13 @@ void split(TriangleMesh& tm, split(tm, plane, parameters::all_default()); } +template +void split(TriangleMesh& tm, + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid) +{ + split(tm, iso_cuboid, parameters::all_default()); +} + /// \endcond } } //end of namespace CGAL::Polygon_mesh_processing diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h index e5d25bc983a..2dfaade293d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h @@ -215,7 +215,7 @@ connected_components(const PolygonMesh& pmesh, NamedParameters, internal::No_constraint//default > ::type EdgeConstraintMap; - + EdgeConstraintMap ecmap = choose_parameter(get_parameter(np, internal_np::edge_is_constrained)); @@ -931,23 +931,48 @@ struct No_mark template < class PolygonMesh, class PolygonMeshRange, class FIMap, class VIMap, - class HIMap, class Ecm > + class HIMap, class Ecm, class NamedParameters > void split_connected_components_impl(FIMap fim, HIMap him, VIMap vim, Ecm ecm, PolygonMeshRange& range, - const PolygonMesh& tm) + const PolygonMesh& tm, + const NamedParameters& np) { - typename boost::template property_map< + typedef typename internal_np::Lookup_named_param_def < + internal_np::face_patch_t, + NamedParameters, + typename boost::template property_map< PolygonMesh, CGAL::dynamic_face_property_t >::const_type - pidmap = get(CGAL::dynamic_face_property_t(), tm); + > ::type Fpm; - int nb_patches = CGAL::Polygon_mesh_processing::connected_components( - tm, pidmap, CGAL::parameters::face_index_map(fim) - .edge_is_constrained_map(ecm)); + using parameters::choose_parameter; + using parameters::get_parameter; + using parameters::is_default_parameter; - for(int i=0; i(), tm)); + + std::size_t nb_patches = 0; + if(is_default_parameter(get_parameter(np, internal_np::face_patch))) + { + nb_patches = CGAL::Polygon_mesh_processing::connected_components( + tm, pidmap, CGAL::parameters::face_index_map(fim) + .edge_is_constrained_map(ecm)); + } + else + { + for(const auto& f : faces(tm)) + { + std::size_t patch = get(pidmap, f); + if(patch > nb_patches) + nb_patches = patch; + } + nb_patches+=1; + } + + for(std::size_t i=0; i filter_graph(tm, i, pidmap, CGAL::parameters::face_index_map(fim) @@ -986,6 +1011,11 @@ void split_connected_components_impl(FIMap fim, * \cgalNPBegin{halfedge_index_map} * a property map containing a unique index for each halfedge initialized 0 to `num_halfedges(pm)` * \cgalNPEnd + * \cgalParamBegin{face_patch_map} a property map with the patch id's associated to the + faces of `pm`. Instance of a class model of `ReadPropertyMap`. + If not provided, an internal map will be filled with a call to + `connected_components()` with `edge_is_constrained_map()` (if provided). +* \cgalParamEnd * \cgalNamedParamsEnd * */ @@ -1009,7 +1039,7 @@ void split_connected_components(const PolygonMesh& pm, internal::split_connected_components_impl(CGAL::get_initialized_face_index_map(pm, np), CGAL::get_initialized_halfedge_index_map(pm, np), CGAL::get_initialized_vertex_index_map(pm, np), - ecm, cc_meshes, pm); + ecm, cc_meshes, pm, np); } template diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp index 512724ba23d..591c99a0ba8 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp @@ -528,9 +528,15 @@ void test_split() std::vector meshes; PMP::split(tm1, tm2); + //try with np + typename boost::template property_map< + TriangleMesh, CGAL::dynamic_face_property_t >::type + pidmap = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::Polygon_mesh_processing::connected_components( + tm1, pidmap, CGAL::parameters::all_default()); PMP::split_connected_components(tm1, meshes, - params::all_default()); + params::face_patch_map(pidmap)); CGAL_assertion(meshes.size() == 5); //if the order is not deterministc, put the num_vertices in a list and check @@ -540,6 +546,7 @@ void test_split() CGAL_assertion(num_vertices(meshes[2]) == 142); CGAL_assertion(num_vertices(meshes[3]) == 83); CGAL_assertion(num_vertices(meshes[4]) == 104); + CGAL_assertion(tm1.is_valid()); CGAL::clear(tm1); CGAL::clear(tm2); @@ -580,32 +587,82 @@ void test_split() //if the list does contain all those numbers. CGAL_assertion(num_vertices(meshes[0]) == 588); CGAL_assertion(num_vertices(meshes[1]) == 50); + CGAL_assertion(tm1.is_valid()); CGAL::clear(tm1); CGAL::clear(tm2); meshes.clear(); } +template +void test_isocuboid() +{ + TriangleMesh tm; + //closed intersection curves + std::ifstream input("data-coref/elephant.off"); + input >> tm; + + if(!input) + { + std::cerr<<"File not found. Aborting."< meshes; + K::Iso_cuboid_3 splitter(K::Point_3(-0.3, -0.45, -0.25), + K::Point_3( 0.3, 0.45, 0.25)); + PMP::split(tm, splitter); + + PMP::split_connected_components(tm, + meshes); + + CGAL_assertion(meshes.size() == 10); + //if the order is not deterministc, put the num_vertices in a list and check + //if the list does contain all those numbers. + CGAL_assertion(num_vertices(meshes[0]) == 2657); + CGAL_assertion(num_vertices(meshes[1]) == 131 ); + CGAL_assertion(num_vertices(meshes[2]) == 32 ); + CGAL_assertion(num_vertices(meshes[3]) == 123 ); + CGAL_assertion(num_vertices(meshes[4]) == 220 ); + CGAL_assertion(num_vertices(meshes[5]) == 107 ); + CGAL_assertion(num_vertices(meshes[6]) == 121 ); + CGAL_assertion(num_vertices(meshes[7]) == 56 ); + CGAL_assertion(num_vertices(meshes[8]) == 49 ); + CGAL_assertion(num_vertices(meshes[9]) == 13 ); + CGAL_assertion(tm.is_valid()); + + CGAL::clear(tm); + meshes.clear(); +} int main() { + std::cout << "Surface Mesh" << std::endl; test(); std::cout << "Polyhedron" << std::endl; test(); - + std::cout << "running test_split with Surface_mesh\n"; test_split(); + + std::cout << "running test_iso_cuboid with Surface_mesh\n"; + test_isocuboid(); std::cout << "running test_split_plane with Surface_mesh\n"; test_split_plane(); - + std::cout << "running test_split with Polyhedron\n"; test_split(); - + std::cout << "running test_split_plane with Polyhedron\n"; test_split_plane(); + std::cout << "running test_iso_cuboid with Polyhedron\n"; + test_isocuboid(); std::cout << "Done!" << std::endl; return EXIT_SUCCESS;