diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index 80e14319e8f..fc476d7bc82 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -23,7 +23,9 @@ CGAL_add_named_parameter(face_index_t, face_index, face_index_map) CGAL_add_named_parameter(edge_index_t, edge_index, edge_index_map) CGAL_add_named_parameter(halfedge_index_t, halfedge_index, halfedge_index_map) CGAL_add_named_parameter(edge_is_constrained_t, edge_is_constrained, edge_is_constrained_map) -CGAL_add_named_parameter(face_patch_id_t, face_patch_id, face_patch_id_map) +CGAL_add_named_parameter(vertex_num_feature_edges_t, vertex_num_feature_edges, vertex_num_feature_edges_map) +CGAL_add_named_parameter(halfedge_is_feature_t, halfedge_is_feature, halfedge_is_feature_map) +CGAL_add_named_parameter(maximum_number_of_patches_t, maximum_number_of_patches, maximum_number_of_patches) CGAL_add_named_parameter(set_cache_policy_t, set_cache_policy, set_cache) CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) CGAL_add_named_parameter(get_cost_policy_params_t, get_cost_policy_params, get_cost_params) diff --git a/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h b/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h index 9f6307baa9b..8a4e4899f01 100644 --- a/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h @@ -799,7 +799,7 @@ detect_features(FT angle_in_degree, P2vmap p2vmap; namespace PMP = CGAL::Polygon_mesh_processing; - PMP::Detect_features_in_polygon_mesh detect_features; + std::size_t nb_of_patch_plus_one = 1; BOOST_FOREACH(Polyhedron_type& p, poly) { initialize_ts(p); @@ -812,16 +812,17 @@ detect_features(FT angle_in_degree, #endif // CGAL_MESH_3_VERBOSE // Get sharp features - detect_features.detect_sharp_edges(p, angle_in_degree); - detect_features.detect_surface_patches(p); - detect_features.detect_vertices_incident_patches(p); + typedef typename boost::property_map >::type PIDMap; + typedef typename boost::property_map >::type VIPMap; + PIDMap pid_map = get(face_patch_id_t(), p); + VIPMap vip_map = get(vertex_incident_patches_t(), p); + CGAL::Polygon_mesh_processing::detect_features(p, angle_in_degree,pid_map, vip_map, + CGAL::Polygon_mesh_processing::parameters::maximum_number_of_patches(&nb_of_patch_plus_one)); internal::Mesh_3::Is_featured_edge is_featured_edge(p); add_featured_edges_to_graph(p, is_featured_edge, g_copy, p2vmap); } - const std::size_t nb_of_patch_plus_one = - detect_features.maximal_surface_patch_index()+1; this->patch_id_to_polyhedron_id.resize(nb_of_patch_plus_one); this->patch_has_featured_edges.resize(nb_of_patch_plus_one); this->several_vertices_on_patch.resize(nb_of_patch_plus_one); diff --git a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h index a1a25a2a3af..db1a467e868 100644 --- a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h @@ -448,23 +448,23 @@ detect_features(FT angle_in_degree, std::vector& poly) vertex_descriptor> P2vmap; // TODO: replace this map by and unordered_map P2vmap p2vmap; - - CGAL::Polygon_mesh_processing::Detect_features_in_polygon_mesh detect_features; BOOST_FOREACH(Polyhedron& p, poly) { initialize_ts(p); - + typedef typename boost::property_map >::type PIDMap; + typedef typename boost::property_map >::type VIPMap; + PIDMap pid_map = get(face_patch_id_t(), p); + VIPMap vip_map = get(vertex_incident_patches_t(), p); // Get sharp features - detect_features.detect_sharp_edges(p, angle_in_degree); - detect_features.detect_surface_patches(p); - detect_features.detect_vertices_incident_patches(p); + CGAL::Polygon_mesh_processing::detect_features(p, angle_in_degree,pid_map, vip_map); + internal::Mesh_3::Is_featured_edge is_featured_edge(p); add_featured_edges_to_graph(p, is_featured_edge, g_copy, p2vmap); } add_features_from_split_graph_into_polylines(g_copy); - borders_detected_ = true;/*done by Mesh_3::detect_features*/ + borders_detected_ = true;/*done by PMP::detect_features*/ } template < typename GT_, typename P_, typename TA_, diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index bc5bfaad841..b8cf5740243 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -152,6 +152,30 @@ the property map containing information about edges of the input polygon mesh be a default property map where no edge is constrained is provided. \cgalNPEnd +\cgalNPBegin{ maximum_number_of_patches } \anchor PMP_maximum_number_of_patches +contains the surface patch beeing treated +1.\n +\b Type : `std::size_t`* \n +\b Default : a pointer to a `std::size_t` with value 1. +\cgalNPEnd + +\cgalNPBegin{ halfedge_is_feature_map } \anchor PMP_halfedge_is_feature_map +the property map containing information about halfedges of the input polygon mesh being featured or not.\n +\b Type : a class model of `ReadWritePropertyMap` with +`boost::graph_traits::%halfedge_descriptor` as key type and +`bool` as value type. It should be default constructible.\n +\b Default value is \code boost::get(CGAL::halfedge_is_feature, pmesh)\endcode +\cgalNPEnd + +\cgalNPBegin{ vertex_num_feature_edges_map } \anchor PMP_vertex_num_feature_edges_map +the property map containing the number of feature edges being incident to the vertices of the polygon mesh `pmesh`.\n +\b Type : a class model of `ReadWritePropertyMap` with +`boost::graph_traits::%vertex_descriptor` as key type and +`int` as value type. It should be default constructible.\n +\b Default value is \code boost::get(CGAL::vertex_num_feature_edges_t(), pmesh)\endcode +\cgalNPEnd + + + \cgalNPBegin{ vertex_is_constrained_map } \anchor PMP_vertex_is_constrained_map the property map containing information about vertices of the input polygon mesh being constrained or not. Constrained vertices may be replaced by new vertices, but the number and location diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index f12ac34f80d..31c0cc371e5 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -49,6 +49,9 @@ /// of the bounded volumes. /// \ingroup PkgPolygonMeshProcessing +/// \defgroup PMP_detect_features_grp Detect Features Functions +/// Functions to detect sharp edges and surface patch ids of polygon meshes. +/// \ingroup PkgPolygonMeshProcessing /*! \addtogroup PkgPolygonMeshProcessing @@ -150,6 +153,12 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::max_distance_to_triangle_mesh()` - `CGAL::Polygon_mesh_processing::sample_triangle_mesh()` +##Detect Features Functions ## +- `CGAL::Polygon_mesh_processing::detect_features()` +- `CGAL::Polygon_mesh_processing::detect_sharp_edges()` +- `CGAL::Polygon_mesh_processing::detect_surface_patches()` +- `CGAL::Polygon_mesh_processing::detect_vertices_incident_patches()` + ## Miscellaneous ## - `CGAL::Polygon_mesh_slicer` - `CGAL::Side_of_triangle_mesh` diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 92d8f80d1ae..ee5492ea0f7 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -106,6 +106,7 @@ create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" ) create_single_source_cgal_program( "random_perturbation_SM_example.cpp" ) create_single_source_cgal_program( "corefinement_LCC.cpp") create_single_source_cgal_program( "hole_filling_example_LCC.cpp" ) +create_single_source_cgal_program( "detect_features_example.cpp" ) if(OpenMesh_FOUND) create_single_source_cgal_program( "compute_normals_example_OM.cpp" ) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Detect_features_in_polygon_mesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Detect_features_in_polygon_mesh.h index 02e487d6c53..60058b10e32 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Detect_features_in_polygon_mesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Detect_features_in_polygon_mesh.h @@ -26,318 +26,461 @@ #include -#include -#include #include +#include #include #include namespace CGAL { namespace Polygon_mesh_processing { + +namespace internal +{ +template +Int +generate_patch_id(Int, int i) +{ + return Int(i); +} + +template +std::pair +generate_patch_id(std::pair, int i) +{ + return std::pair(i, 0); +} + +template +typename GT::Vector_3 +facet_normal(const PolygonMesh& polygonMesh, + const typename boost::graph_traits::face_descriptor& f) +{ + return Polygon_mesh_processing::compute_face_normal(f,polygonMesh); +} + + +template +bool +is_sharp(PolygonMesh& polygonMesh, + const typename boost::graph_traits::halfedge_descriptor& he, + typename GT::FT cos_angle) +{ + typedef typename boost::graph_traits::face_descriptor face_descriptor; + if(is_border(edge(he,polygonMesh),polygonMesh)){ + return false; + } + face_descriptor f1 = face(he,polygonMesh); + face_descriptor f2 = face(opposite(he,polygonMesh),polygonMesh); + + const typename GT::Vector_3& n1 = facet_normal(polygonMesh, f1); + const typename GT::Vector_3& n2 = facet_normal(polygonMesh, f2); + + if ( n1 * n2 <= cos_angle ) + return true; + else + return false; +} + + +template +void +flood(PolygonMesh& polygonMesh, + typename boost::graph_traits::face_descriptor f, + PatchIdMap& pid_map, + const typename boost::property_traits::value_type& patch_id, + std::set::face_descriptor>& unsorted_faces, + HIF_map& hif) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef std::set face_descriptor_set; + typedef std::set He_handle_set; + // Initialize he_to_explore with halfedges of the starting facet + He_handle_set he_to_explore; + BOOST_FOREACH(halfedge_descriptor hd, + CGAL::halfedges_around_face(halfedge(f,polygonMesh), polygonMesh)) + { + he_to_explore.insert(opposite(hd,polygonMesh)); + } + + // While there is something to explore + while ( ! he_to_explore.empty() ) + { + // Get next halfedge to explore + halfedge_descriptor he = *(he_to_explore.begin()); + he_to_explore.erase(he_to_explore.begin()); + + // If we don't go through a border of the patch + if ( ! get(hif, he) && ! is_border(he,polygonMesh) ) + { + face_descriptor explored_facet = face(he,polygonMesh); + + // Mark facet and delete it from unsorted + put(pid_map, explored_facet, patch_id); + unsorted_faces.erase(explored_facet); + + // Add/Remove facet's halfedge to/from explore list + BOOST_FOREACH(halfedge_descriptor hd, + CGAL::halfedges_around_face(halfedge(explored_facet,polygonMesh), + polygonMesh)) + { + halfedge_descriptor current_he = hd; + + // do not explore heh again + if ( current_he == he ) { continue; } + + // if current_he is not in to_explore set, add it, otherwise remove it + // (because we just explore the facet he_begin is pointing to) + if ( he_to_explore.erase(current_he) == 0 ) + { + he_to_explore.insert(opposite(current_he,polygonMesh)); + } + } + } + } +} + +} //end internal + /*! - * \ingroup detect_features_grp - * Probably does something + * \ingroup PMP_detect_features_grp * - * \tparam PolygonMesh a model of `FaceGraph` - * \tparam FT is a number type. It must be -either `double` or `float`, or an exact number type. - * \tparam NamedParameters a sequence of \ref namedparameters + * Detects the sharp edges of `p` by comparing with `angle_in_deg` and computes the number of sharp edges incident to each vertex. * - * \param p the polygon mesh - * \param angle_in_deg the roof angle. - * \param np optional \ref namedparameters described below + * Property maps for CGAL::halfedge_is_feature_t and vertex_num_feature_edges_t should be either + * available as internal property maps to `p` or provided as Named Parameters. + * + * \tparam PolygonMesh a model of `FaceGraph` + * \tparam FT a number type. It is + * either deduced from the `geom_traits` \ref namedparameters if provided, + * or from the geometric traits class deduced from the point property map + * of `PolygonMesh`. + * \tparam NamedParameters a sequence of \ref namedparameters + * + * \param p the polygon mesh + * \param angle_in_deg the floor angle. + * \param np optional \ref namedparameters described below * * \cgalNamedParamsBegin - * \cgalParamBegin{face_patch_id_map} a property map containing the patches identifiers for the faces of `pmesh` \cgalParamEnd + * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd + * \cgalParamBegin{halfedge_is_feature_map} a property map that will contain the sharp edges of `p` \cgalParamEnd + * \cgalParamBegin{vertex_num_feature_edges_map} a property map that will contain the number of adjacent feature edges for each vertex of `p` \cgalParamEnd * \cgalNamedParamsEnd * */ - template +#ifdef DOXYGEN_RUNNING +template +#else +template +#endif +void detect_sharp_edges(PolygonMesh& p, + #ifdef DOXYGEN_RUNNING + FT angle_in_deg, + #else + typename GetGeomTraits::type::FT angle_in_deg, + #endif + const NamedParameters& np) +{ + //extract types from NPs + typedef typename boost::lookup_named_param_def < + internal_np::halfedge_is_feature_t, + NamedParameters, + typename boost::property_map::type//default + > ::type HIF_map; + HIF_map hif + = choose_param(get_param(np, internal_np::halfedge_is_feature), + get(CGAL::halfedge_is_feature, p)); + + typedef typename boost::lookup_named_param_def < + internal_np::vertex_num_feature_edges_t, + NamedParameters, + typename boost::property_map::type//default + > ::type VNFE_map; + VNFE_map vnfe + = choose_param(get_param(np, internal_np::vertex_num_feature_edges), + get(CGAL::vertex_num_feature_edges_t(), p)); + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + // Initialize vertices + + BOOST_FOREACH(typename boost::graph_traits::vertex_descriptor vd, vertices(p)) + { + put(vnfe,vd, 0); + } + + FT cos_angle ( std::cos(CGAL::to_double(angle_in_deg) * CGAL_PI / 180.) ); + + // Detect sharp edges + BOOST_FOREACH(typename boost::graph_traits::edge_descriptor ed, edges(p)) + { + typename boost::graph_traits::halfedge_descriptor he = halfedge(ed,p); + if(is_border(he,p) || angle_in_deg == FT() || + (angle_in_deg != FT(180) && internal::is_sharp(p,he,cos_angle)) + ) + { + put(hif, he, true); + put(hif, opposite(he,p), true); + + put(vnfe, target(he,p), get(vnfe, target(he,p))+1); + put(vnfe, source(he,p), get(vnfe, source(he,p))+1); + } + } +} + +/*! + * \ingroup PMP_detect_features_grp + * + * Computes for each face the index of the corresponding surface patch, + * based on the feature edges. + * + * A filled property map for CGAL::halfedge_is_feature_t should be either + * available as an internal property map to `p` or provided as one of the Named Parameters. + * + * \tparam PolygonMesh a model of `FaceGraph` + * \tparam PatchIdMap a model of `ReadWritePropertyMap` with + `boost::graph_traits::%face_descriptor` as key type + and the desired patch id, model of `CopyConstructible` as value type. + * \tparam NamedParameters a sequence of \ref namedparameters + * + * \param p the polygon mesh + * \param patch_id_map a property map that will contain the surface patch ids for the faces of `p`. + * \param np optional \ref namedparameters described below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd + * \cgalParamBegin{halfedge_is_feature_map} a property map containing the sharp edges of `p` \cgalParamEnd + * \cgalParamBegin{maximum_number_of_patches} an `std::size_t`* the highest number of patches. This usually starts at 1. \cgalParamEnd + * \cgalNamedParamsEnd + * \returns the number of surface patches. + * + * @see `CGAL::Polygon_mesh_processing::detect_features()` + */ +template +std::size_t +detect_surface_patches(PolygonMesh& p, + PatchIdMap& patch_id_map, + const NamedParameters& np) +{ + //extract types from NPs + typedef typename boost::lookup_named_param_def < + internal_np::halfedge_is_feature_t, + NamedParameters, + typename boost::property_map::type//default + > ::type HIF_map; + HIF_map hif + = choose_param(get_param(np, internal_np::halfedge_is_feature), + get(CGAL::halfedge_is_feature, p)); + + std::size_t dummy = 1; + std::size_t* current_surface_index_ = + boost::choose_param(get_param(np, internal_np::maximum_number_of_patches), &dummy); + + + + typedef typename GetGeomTraits::type GT; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::property_traits::value_type PatchId; + // Initialize unsorted_faces + typedef std::set face_descriptor_set; + face_descriptor_set unsorted_faces; + BOOST_FOREACH(typename boost::graph_traits::face_descriptor fd, faces(p)) + { + unsorted_faces.insert(fd); + } + + // Flood + while ( ! unsorted_faces.empty() ) + { + face_descriptor f = *(unsorted_faces.begin()); + unsorted_faces.erase(unsorted_faces.begin()); + + const PatchId patch_id = internal::generate_patch_id(PatchId(), + *current_surface_index_); + put(patch_id_map, f, patch_id); + internal::flood(p, f, patch_id_map, patch_id,unsorted_faces, hif); + ++(*current_surface_index_); + } + return *current_surface_index_ - 1; +} + + +/*! + * \ingroup PMP_detect_features_grp + * + * Gets for each vertex the patch ids of the incident faces. + * + * * A filled property map for CGAL::halfedge_is_feature_t should be either + * available as an internal property map to `p` or provided as one of the Named Parameters. + * + * \tparam PolygonMesh a model of `FaceGraph` + * \tparam PatchIdMap a model of `ReadWritePropertyMap` with + `boost::graph_traits::%face_descriptor` as key type + and the desired patch id, model of `CopyConstructible` as value type. + * \tparam VertexIncidentPatchesMap a model of `ReadWritePropertyMap` with + `boost::graph_traits::%vertex_descriptor` as key type + and a set of the desired patch id, model of `CopyConstructible` as value type. + + * \tparam NamedParameters a sequence of \ref namedparameters + * + * \param p the polygon mesh + * \param patch_id_map a property map containing the surface patch ids for the faces of `p`. It must be already filled. + * \param vertex_incident_patches_map a property map that will contain the patch ids of all the incident faces of each vertex of `p`. + * \param np optional \ref namedparameters described below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd + * \cgalParamBegin{halfedge_is_feature_map} a property map containing the sharp edges of `p` \cgalParamEnd + * \cgalNamedParamsEnd + * + * * @see `CGAL::Polygon_mesh_processing::detect_features()` + */ + +template +void detect_vertices_incident_patches(PolygonMesh& p, + PatchIdMap& patch_id_map, + VertexIncidentPatchesMap& vertex_incident_patches_map, + const NamedParameters& np) +{ + //extract types from NPs + typedef typename boost::lookup_named_param_def < + internal_np::halfedge_is_feature_t, + NamedParameters, + typename boost::property_map::type//default + > ::type HIF_map; + HIF_map hif + = choose_param(get_param(np, internal_np::halfedge_is_feature), + get(CGAL::halfedge_is_feature, p)); + + + typedef typename GetGeomTraits::type GT; + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename boost::property_traits::value_type PatchId; + BOOST_FOREACH(vertex_descriptor vit,vertices(p)) + { + // Look only at feature vertices + if( ! get(hif, halfedge(vit, p)) ){ continue; } + + // Loop on incident facets of vit + std::set set; + BOOST_FOREACH(halfedge_descriptor he, halfedges_around_target(vit,p)) + { + if( ! is_border(he,p) ) + { + set.insert(get(patch_id_map,face(he,p))); + } + else if( ! is_border(opposite(he,p),p) ) + { + set.insert(get(patch_id_map, face(opposite(he,p),p))); + } + } + put(vertex_incident_patches_map, vit, set); + } +} + +/*! + * \ingroup PMP_detect_features_grp + * + * Detects the sharpd edges of `p` according to `angle_in_deg` and computes the corresponding + * surface patch ids for each face. + * + * This function calls successively `CGAL::Polygon_mesh_processing::detect_sharp_edges()`, + * `CGAL::Polygon_mesh_processing::detect_surface_patches()` and + * `CGAL::Polygon_mesh_processing::detect_vertices_incident_patches()` + * + * Property maps for CGAL::halfedge_is_feature_t and vertex_num_feature_edges_t should be either + * available as internal property maps to `p` or provided as Named Parameters. + * + * \tparam PolygonMesh a model of `FaceGraph` + * \tparam FT a number type. It is + * either deduced from the `geom_traits` \ref namedparameters if provided, + * or from the geometric traits class deduced from the point property map + * of `PolygonMesh`. + * \tparam PatchIdMap a model of `ReadWritePropertyMap` with + `boost::graph_traits::%face_descriptor` as key type + and the desired patch id, model of `CopyConstructible` as value type. + * \tparam VertexIncidentPatchesMap a model of `ReadWritePropertyMap` with + `boost::graph_traits::%vertex_descriptor` as key type + and a set of the desired patch id, model of `CopyConstructible` as value type. + + * \tparam NamedParameters a sequence of \ref namedparameters + * + * \param p the polygon mesh + * \param angle_in_deg the floor angle. + * \param patch_id_map a property map that will contain the surface patch ids for the faces of `p`. + * \param vertex_incident_patches_map a property map that will contain the patch ids of all the incident faces of each vertex of `p`. + * \param np optional \ref namedparameters described below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd + * \cgalParamBegin{halfedge_is_feature_map} a property map that will contain the sharp edges of `p` \cgalParamEnd + * \cgalParamBegin{vertex_num_feature_edges_map} a property map that will contain the number of adjacent feature edges for each vertex of `p` \cgalParamEnd + * \cgalParamBegin{maximum_number_of_patches} an `std::size_t` that that will contain the number of surface patches of `p`. \cgalParamEnd + * \cgalNamedParamsEnd + * + * @see `CGAL::Polygon_mesh_processing::detect_sharp_edges()` + * @see `CGAL::Polygon_mesh_processing::detect_surface_patches()` + * @see `CGAL::Polygon_mesh_processing::detect_vertices_incident_patches()` + */ +#ifdef DOXYGEN_RUNNING +template +#else +template +#endif void detect_features(PolygonMesh& p, + #ifdef DOXYGEN_RUNNING FT angle_in_deg, + #else + typename GetGeomTraits::type::FT angle_in_deg, + #endif + PatchIdMap& patch_id_map, + VertexIncidentPatchesMap& vertex_incident_patches_map, const NamedParameters& np) { - typedef typename boost::lookup_named_param_def < - internal_np::face_patch_id_t, - NamedParameters, - typename boost::property_map >::type//default - > ::type PatchId_pmap; - PatchId_pmap pid_map - = choose_param(get_param(np, internal_np::face_patch_id), - get(typename CGAL::face_patch_id_t(), p)); - - Detect_features_in_polygon_mesh go(pid_map); - // AF todo: Add overload for the next three functions so that we use the pid_map - // Add a default for pid_map - go.detect_sharp_edges(p,angle_in_deg); - go.detect_surface_patches(p); - go.detect_vertices_incident_patches(p); + detect_sharp_edges(p,angle_in_deg, np); + detect_surface_patches(p, patch_id_map, np); + detect_vertices_incident_patches(p, patch_id_map, vertex_incident_patches_map, np); } - - template -class Detect_features_in_polygon_mesh +//Convenient overrides +template +void detect_sharp_edges(PolygonMesh& p, + FT angle_in_deg) { -public: + detect_sharp_edges(p, angle_in_deg, parameters::all_default()); +} - typedef Polyhedron_ Polyhedron; - typedef Patch_id_ Patch_id; - - typedef typename boost::property_traits::type>::value_type Point_3; - - typedef typename Kernel_traits::Kernel Geom_traits; - - typedef typename Geom_traits::Vector_3 Vector_3; - typedef typename Geom_traits::FT FT; - - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - - typedef CGAL::Compare_handles_with_or_without_timestamps Compare_handles; - - typedef std::set face_descriptor_set; - typedef std::set He_handle_set; - -public: - Detect_features_in_polygon_mesh(PatchId_pmap& pid_map) - : current_surface_index_(1), - pid_map(pid_map) - {} - - void detect_sharp_edges(Polyhedron& polyhedron, - FT angle_in_deg = FT(60)) const; - void detect_surface_patches(Polyhedron& polyhedron); - void detect_vertices_incident_patches(Polyhedron& p); - - int maximal_surface_patch_index() const { - return current_surface_index_ - 1; - } - -private: - Vector_3 facet_normal(const Polyhedron& polyhedron, const face_descriptor& f) const; - bool is_sharp(Polyhedron& polyhedron, const halfedge_descriptor& he, FT cos_angle) const; - void flood(Polyhedron& polyhedron, - face_descriptor f, const Patch_id& id, - face_descriptor_set& unsorted_faces) const; - - template - Int generate_patch_id(Int, int); - - template - std::pair generate_patch_id(std::pair, int); - -private: - // Stores the current surface index (usefull to detect different patches - // on different polyhedra) - int current_surface_index_; - PatchId_pmap pid_map; -}; - - -template -void -Detect_features_in_polygon_mesh:: -detect_sharp_edges(Polyhedron& polyhedron, FT angle_in_deg) const +template +typename boost::graph_traits::faces_size_type +detect_surface_patches(PolygonMesh& p, + PatchIdMap& patch_id_map) { - // Initialize vertices - typename boost::property_map::type vnfe - = get(vertex_num_feature_edges_t(),polyhedron); - - typename boost::property_map::type hif - = get(halfedge_is_feature_t(),polyhedron); - - BOOST_FOREACH(typename boost::graph_traits::vertex_descriptor vd, vertices(polyhedron)) - { - put(vnfe,vd, 0); - } - - FT cos_angle ( std::cos(CGAL::to_double(angle_in_deg) * CGAL_PI / 180.) ); - - // Detect sharp edges - BOOST_FOREACH(typename boost::graph_traits::edge_descriptor ed, edges(polyhedron)) - { - typename boost::graph_traits::halfedge_descriptor he = halfedge(ed,polyhedron); - if(is_border(he,polyhedron) || angle_in_deg == FT() || - (angle_in_deg != FT(180) && is_sharp(polyhedron,he,cos_angle)) - ) - { - put(hif, he, true); - put(hif, opposite(he,polyhedron), true); - - put(vnfe, target(he,polyhedron), get(vnfe, target(he,polyhedron))+1); - put(vnfe, source(he,polyhedron), get(vnfe, source(he,polyhedron))+1); - } - } + return detect_surface_patches(p, patch_id_map, parameters::all_default()); +} +template +void detect_vertices_incident_patches(PolygonMesh& p, + PatchIdMap& patch_id_map, + VertexIncidentPatchesMap& vertex_incident_patches_map) +{ + detect_vertices_incident_patches(p, patch_id_map, vertex_incident_patches_map, parameters::all_default()); +} +template +void detect_features(PolygonMesh& p, + FT angle_in_deg, + PatchIdMap& patch_id_map, + VertexIncidentPatchesMap& vertex_incident_patches_map) +{ + detect_features(p,angle_in_deg, patch_id_map, vertex_incident_patches_map, parameters::all_default()); } -template -template -Int -Detect_features_in_polygon_mesh:: -generate_patch_id(Int, int i) -{ - return Int(i); -} - -template -template -std::pair -Detect_features_in_polygon_mesh:: -generate_patch_id(std::pair, int i) -{ - return std::pair(i, 0); -} - -template -void -Detect_features_in_polygon_mesh:: -detect_surface_patches(Polyhedron& polyhedron) -{ - // Initialize unsorted_faces - face_descriptor_set unsorted_faces; - BOOST_FOREACH(typename boost::graph_traits::face_descriptor fd, faces(polyhedron)) - { - unsorted_faces.insert(fd); - } - - // Flood - while ( ! unsorted_faces.empty() ) - { - face_descriptor f = *(unsorted_faces.begin()); - unsorted_faces.erase(unsorted_faces.begin()); - - const Patch_id patch_id = generate_patch_id(Patch_id(), - current_surface_index_); - put(pid_map, f, patch_id); - flood(polyhedron, f,patch_id,unsorted_faces); - ++current_surface_index_; - } -} -template -void -Detect_features_in_polygon_mesh:: -detect_vertices_incident_patches(Polyhedron& polyhedron) -{ - typename boost::property_map::type hif - = get(halfedge_is_feature,polyhedron); - typedef typename boost::property_map >::type VIP_map; - VIP_map vip = get(vertex_incident_patches_t(),polyhedron); - - BOOST_FOREACH(vertex_descriptor vit,vertices(polyhedron)) - { - // Look only at feature vertices - if( ! get(hif, halfedge(vit, polyhedron)) ){ continue; } - - // Loop on incident facets of vit - std::set set; - BOOST_FOREACH(halfedge_descriptor he, halfedges_around_target(vit,polyhedron)) - { - if( ! is_border(he,polyhedron) ) - { - set.insert(get(pid_map,face(he,polyhedron))); - } - else if( ! is_border(opposite(he,polyhedron),polyhedron) ) - { - set.insert(get(pid_map, face(opposite(he,polyhedron),polyhedron))); - } - } - put(vip, vit, set); - } -} - -// ----------------------------------- -// Private methods -// ----------------------------------- -template -typename Detect_features_in_polygon_mesh::Vector_3 -Detect_features_in_polygon_mesh:: -facet_normal(const Polyhedron& polyhedron, const face_descriptor& f) const -{ - return Polygon_mesh_processing::compute_face_normal(f,polyhedron); -} - - -template -bool -Detect_features_in_polygon_mesh:: -is_sharp(Polyhedron& polyhedron, const halfedge_descriptor& he, FT cos_angle) const -{ - if(is_border(edge(he,polyhedron),polyhedron)){ - return false; - } - face_descriptor f1 = face(he,polyhedron); - face_descriptor f2 = face(opposite(he,polyhedron),polyhedron); - - const Vector_3& n1 = facet_normal(polyhedron, f1); - const Vector_3& n2 = facet_normal(polyhedron, f2); - - if ( n1 * n2 <= cos_angle ) - return true; - else - return false; -} - - -template -void -Detect_features_in_polygon_mesh:: -flood(Polyhedron& polyhedron, - face_descriptor f, - const Patch_id &patch_id, - face_descriptor_set& unsorted_faces) const -{ - typename boost::property_map::type hif - = get(halfedge_is_feature,polyhedron); - // Initialize he_to_explore with halfedges of the starting facet - He_handle_set he_to_explore; - BOOST_FOREACH(halfedge_descriptor hd, - halfedges_around_face(halfedge(f,polyhedron), polyhedron)) - { - he_to_explore.insert(opposite(hd,polyhedron)); - } - - // While there is something to explore - while ( ! he_to_explore.empty() ) - { - // Get next halfedge to explore - halfedge_descriptor he = *(he_to_explore.begin()); - he_to_explore.erase(he_to_explore.begin()); - - // If we don't go through a border of the patch - if ( ! get(hif, he) && ! is_border(he,polyhedron) ) - { - face_descriptor explored_facet = face(he,polyhedron); - - // Mark facet and delete it from unsorted - put(pid_map, explored_facet, patch_id); - unsorted_faces.erase(explored_facet); - - // Add/Remove facet's halfedge to/from explore list - BOOST_FOREACH(halfedge_descriptor hd, - halfedges_around_face(halfedge(explored_facet,polyhedron), - polyhedron)) - { - halfedge_descriptor current_he = hd; - - // do not explore heh again - if ( current_he == he ) { continue; } - - // if current_he is not in to_explore set, add it, otherwise remove it - // (because we just explore the facet he_begin is pointing to) - if ( he_to_explore.erase(current_he) == 0 ) - { - he_to_explore.insert(opposite(current_he,polyhedron)); - } - } - } - } -} - } // end namespace PMP } // end namespace CGAL diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Detect_features_in_polygon_mesh_fwd.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Detect_features_in_polygon_mesh_fwd.h deleted file mode 100644 index c67cefd2cc6..00000000000 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Detect_features_in_polygon_mesh_fwd.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2017 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// -// -// Author(s) : Laurent Rineau, Stephane Tayeb, Maxime Gimeno -// -//****************************************************************************** -// File Description : -//****************************************************************************** - -#ifndef CGAL_POLYGON_MESH_PROCESSING_DETECT_FEATURES_IN_POLYGON_MESH_FWD_H -#define CGAL_POLYGON_MESH_PROCESSING_DETECT_FEATURES_IN_POLYGON_MESH_FWD_H - -#include - - -namespace CGAL { - template - class face_patch_id_t; -namespace Polygon_mesh_processing { - - template - class Detect_features_in_polygon_mesh; - - - template - void detect_features(Polyhedron& p, - FT angle_in_deg, - typename boost::property_map >::type); - -} // end namespace Polygon_mesh_processing - -} // end namespace CGAL - -#endif // CGAL_POLYGON_MESH_PROCESSING_DETECT_FEATURES_IN_POLYGON_MESH_FWD_H diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Detect_sharp_edges_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Detect_sharp_edges_plugin.cpp index fe1922ae5bc..0a42dd4d585 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Detect_sharp_edges_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Detect_sharp_edges_plugin.cpp @@ -130,9 +130,10 @@ void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdges(bool input_dial FaceGraph* pMesh = tuple.second; if (!pMesh) continue; typedef typename boost::property_map >::type PatchID; - PatchID dummy = get(CGAL::face_patch_id_t(), *pMesh); - CGAL::Polygon_mesh_processing::detect_features(*pMesh, angle, - CGAL::Polygon_mesh_processing::parameters::face_patch_id_map(dummy)); + PatchID pid = get(CGAL::face_patch_id_t(), *pMesh); + typedef typename boost::property_map >::type VIP; + VIP vip = get(CGAL::vertex_incident_patches_t(), *pMesh); + CGAL::Polygon_mesh_processing::detect_features(*pMesh, angle, pid, vip); //update item item->setItemIsMulticolor(true); item->invalidateOpenGLBuffers(); diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h index 5e39933e0e7..bb39be5681e 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h @@ -24,11 +24,13 @@ namespace CGAL reset_sharp_edges(pMesh); // Detect edges in current polyhedron - typedef typename boost::property_map >::type PatchID; - PatchID pid_map = get(face_patch_id_t(), *pMesh); + typedef typename boost::property_map >::type PIDMap; + typedef typename boost::property_map >::type VIPMap; + PIDMap pid_map = get(face_patch_id_t(), *pMesh); + VIPMap vip_map = get(vertex_incident_patches_t(), *pMesh); - CGAL::Polygon_mesh_processing::Detect_features_in_polygon_mesh features_detector(pid_map); - features_detector.detect_sharp_edges(*pMesh, angle); + + CGAL::Polygon_mesh_processing::detect_sharp_edges(*pMesh, angle); } }//end namespace CGAL