diff --git a/BGL/doc/BGL/Doxyfile.in b/BGL/doc/BGL/Doxyfile.in index 6fccfa0fda7..d70296e8886 100644 --- a/BGL/doc/BGL/Doxyfile.in +++ b/BGL/doc/BGL/Doxyfile.in @@ -8,12 +8,28 @@ INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/Euler_operations.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/split_graph_into_polylines.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/copy_face_graph.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/Graph_with_descriptor_with_graph.h \ + ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/Face_filtered_graph.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/Dual.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h EXAMPLE_PATH = ${CGAL_Surface_mesh_skeletonization_EXAMPLE_DIR} \ + ${CGAL_Surface_mesh_segmentation_EXAMPLE_DIR} \ + ${CGAL_Polygon_mesh_processing_EXAMPLE_DIR} \ ${CGAL_BGL_EXAMPLE_DIR} ALIASES += "bgllink{1}=\1" +ALIASES += "cgalNamedParamsBegin=
Named Parameters
" +# macros to be used inside the code +ALIASES += "cgalNamedParamsBegin=
Named Parameters
" +ALIASES += "cgalNamedParamsEnd=
" +ALIASES += "cgalParamBegin{1}=\1" +ALIASES += "cgalParamEnd=" + + EXTRACT_ALL=NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +EXPAND_AS_DEFINED = CGAL_BGL_NP_TEMPLATE_PARAMETERS \ + CGAL_BGL_NP_CLASS diff --git a/BGL/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index cba2f490e72..42397587333 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -316,6 +316,7 @@ user might encounter. - `CGAL::Dual` - `CGAL::Graph_with_descriptor_with_graph` - `CGAL::Graph_with_descriptor_with_graph_property_map` +- `CGAL::Face_filtered_graph` ## Helper Functions ## - `CGAL::is_border()` @@ -342,7 +343,6 @@ user might encounter. - `CGAL::clear()` - `CGAL::copy_face_graph()` -- `CGAL::reserve()` ## Iterators ## - `CGAL::Halfedge_around_source_iterator` diff --git a/BGL/doc/BGL/examples.txt b/BGL/doc/BGL/examples.txt index c84dda9d44c..a700c3cf217 100644 --- a/BGL/doc/BGL/examples.txt +++ b/BGL/doc/BGL/examples.txt @@ -17,4 +17,6 @@ \example BGL_surface_mesh/prim.cpp \example BGL_surface_mesh/surface_mesh_dual.cpp \example Surface_mesh_skeletonization/simple_mcfskel_example.cpp +\example Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp +\example Polygon_mesh_processing/face_filtered_graph_example.cpp */ diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h new file mode 100644 index 00000000000..5e375a9fe80 --- /dev/null +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -0,0 +1,1204 @@ +// 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 Lesser 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) : Maxime Gimeno + +#ifndef CGAL_BOOST_GRAPH_FACE_FILTERED_GRAPH_H +#define CGAL_BOOST_GRAPH_FACE_FILTERED_GRAPH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DOXYGEN_RUNNING +#define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters +#define CGAL_BGL_NP_CLASS NamedParameters +#endif + +namespace CGAL +{ + + /*! + * \ingroup PkgBGLHelper + * + * The class `Face_filtered_graph` is an adaptor that creates a filtered view of a graph + * by restricting it to a subset of faces. Contrary to + * boost::filtered_graph, + * this class only requires a way to access the selected faces and will automatically select the + * edges/halfedges and vertices present in the adapted graph. A vertex is selected if it is incident to at least one + * selected face. A edge is selected if it is incident to at least a selected face. A halfedge is selected if its edge + * is selected. + * + * Since this class is a model of the `FaceGraph` concept, there is a restriction on the set of selected faces: + * the adapted graph must define a manifold mesh. In order to check that this condition is verified, you can + * use the function `is_selection_valid()`. + * + * There are two different ways to initialize this class. You can directly provide the set of faces selected, or + * if you have a face patch map, select the patches of faces. The latter option is convenient if you want to access + * some connected components of a graph after having called `CGAL::Polygon_mesh_processing::connected_components()`. + * + * The documented interface of this class is limited on purpose and free functions of the concept + * this class is a model of must be used to manipulate it. + * + * A BGL-like named parameter mechanism is used in the constructors of this class. %Default values are available but if you need + * to set them, you can pass for `np` `CGAL::parameters::face_index_map(fim).halfedge_index_map(him).vertex_index_map(vim)` + * where `fim`, `him`, and `vim` are the respective index maps. The order of the arguments is not important and any of them can be + * missing if the default is fine. + * + * \tparam Graph must be a model of a `FaceListGraph`, `HalfedgeListGraph`, and \bgllink{VertexListGraph}. + * \tparam FIMap a model of `ReadablePropertyMap` with `face_descriptor` as key and `graph_traits::%faces_size_type` as value + * \tparam VIMap a model of `ReadablePropertyMap` with `vertex_descriptor` as key and `graph_traits::%vertices_size_type` as value + * \tparam HIMap a model of `ReadablePropertyMap` with `halfedge_descriptor` as key and `graph_traits::%halfedges_size_type` as value + * + * \cgalModels `FaceListGraph` + * \cgalModels `HalfedgeListGraph` + * \cgalModels \bgllink{VertexListGraph} + */ +template::type, + typename VIMap = typename boost::property_map::type, + typename HIMap = typename boost::property_map::type> +struct Face_filtered_graph +{ + typedef boost::graph_traits gt; + /// Vertex descriptor type + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + /// Halfedge descriptor type + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + /// Edge descriptor type + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + /// Face descriptor type + typedef typename boost::graph_traits::face_descriptor face_descriptor; + /// Size type + #ifndef DOXYGEN_RUNNING + typedef boost::dynamic_bitset<>::size_type size_type; + #else + typedef unspecified_type size_type; + #endif + + // non documented types + typedef typename boost::property_traits< FIMap >::value_type face_index_type; + typedef typename boost::property_traits< VIMap >::value_type vertex_index_type; + typedef typename boost::property_traits< HIMap >::value_type halfedge_index_type; + typedef Face_filtered_graph Self; + + /*! + * \brief Constructor where the set of selected faces is specified as a range of patch ids. + * + * \tparam FacePatchIndexMap a model of `ReadablePropertyMap` with + `face_descriptor` as key type and + `graph_traits::%faces_size_type` as value type. + * \tparam FacePatchIndexRange a model of `ConstRange` with `boost::property_traits::%value_type` as value type. + * \tparam NamedParameters a sequence of named parameters + * + * \param graph the underlying graph. + * \param face_patch_index_map the property_map that assigns a patch index to each face, with + `face_descriptor` as key type and `boost::graph_traits::%faces_size_type` as value type. + * \param selected_face_patch_indices a range of the face patch indices to select. + * \param np optional sequence of named parameters among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{face_index_map} + * a property map containing an index for each face initialized from 0 to `num_vertices(graph)` + * \cgalParamEnd + * \cgalParamBegin{vertex_index_map} + * a property map containing an index for each vertex initialized 0 to `num_vertices(vertex)` + * \cgalParamEnd + * \cgalParamBegin{halfedge_index_map} + * a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)` + * \cgalParamEnd + * \cgalNamedParamsEnd + */ + template + Face_filtered_graph(const Graph& graph, + const FacePatchIndexRange& selected_face_patch_indices, + FacePatchIndexMap face_patch_index_map, + const CGAL_BGL_NP_CLASS& np + #ifndef DOXYGEN_RUNNING + , typename boost::enable_if< + typename boost::has_range_const_iterator::type + >::type* = 0 + #endif + ) + : _graph(const_cast(graph)) + , fimap(boost::choose_param(get_param(np, internal_np::face_index), get_const_property_map(face_index, graph))) + , vimap(boost::choose_param(get_param(np, boost::vertex_index), get_const_property_map(boost::vertex_index, graph))) + , himap(boost::choose_param(get_param(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + { + set_selected_faces(selected_face_patch_indices, face_patch_index_map); + } + + template + Face_filtered_graph(const Graph& graph, + const FacePatchIndexRange& selected_face_patch_indices, + FacePatchIndexMap face_patch_index_map) + : _graph(const_cast(graph)) + , fimap(get(CGAL::face_index, graph)) + , vimap(get(boost::vertex_index, graph)) + , himap(get(CGAL::halfedge_index, graph)) + { + set_selected_faces(selected_face_patch_indices, face_patch_index_map); + } + /*! + * \brief Constructor where the set of selected faces is specified as a patch id. + * + * \tparam FacePatchIndexMap a model of `ReadablePropertyMap` with + `face_descriptor` as key type and + `graph_traits::%faces_size_type` as value type. + * \tparam NamedParameters a sequence of named parameters + * \param graph the underlying graph. + * \param face_patch_index_map the property_map that assigns a patch index to each face, with + `face_descriptor` as key type and + `graph_traits::%faces_size_type` as value type. + * \param selected_face_patch_index the index of the face patch selected. + * \param np optional sequence of named parameters among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{face_index_map} + * a property map containing an index for each face initialized from 0 to `num_vertices(graph)` + * \cgalParamEnd + * \cgalParamBegin{vertex_index_map} + * a property map containing an index for each vertex initialized 0 to `num_vertices(vertex)` + * \cgalParamEnd + * \cgalParamBegin{halfedge_index_map} + * a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)` + * \cgalParamEnd + * \cgalNamedParamsEnd + */ + template + Face_filtered_graph(const Graph& graph, + typename boost::property_traits::value_type selected_face_patch_index, + FacePatchIndexMap face_patch_index_map, + const CGAL_BGL_NP_CLASS& np + ) + : _graph(const_cast(graph)) + , fimap(boost::choose_param(get_param(np, internal_np::face_index), get_const_property_map(face_index, graph))) + , vimap(boost::choose_param(get_param(np, boost::vertex_index), get_const_property_map(boost::vertex_index, graph))) + , himap(boost::choose_param(get_param(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + { + set_selected_faces(selected_face_patch_index, face_patch_index_map); + } + + template + Face_filtered_graph(const Graph& graph, + typename boost::property_traits::value_type pid, + FacePatchIndexMap face_patch_index_map) + : _graph(const_cast(graph)) + , fimap(get(CGAL::face_index, graph)) + , vimap(get(boost::vertex_index, graph)) + , himap(get(CGAL::halfedge_index, graph)) + { + set_selected_faces(face_patch_index_map, pid); + } + + /*! + * \brief Constructor where the set of selected faces is specified as a range of face descriptors. + * + * \tparam FaceRange a model of `ConstRange` with `face_descriptor` as value type. + * \tparam NamedParameters a sequence of named parameters + * \param graph the graph containing the wanted patch. + * \param selected_faces the set of selected faces. + * \param np optional sequence of named parameters among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{face_index_map} + * a property map containing an index for each face initialized from 0 to `num_vertices(graph)` + * \cgalParamEnd + * \cgalParamBegin{vertex_index_map} + * a property map containing an index for each vertex initialized 0 to `num_vertices(vertex)` + * \cgalParamEnd + * \cgalParamBegin{halfedge_index_map} + * a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)` + * \cgalParamEnd + * \cgalNamedParamsEnd + */ + template + Face_filtered_graph(const Graph& graph, + const FaceRange& selected_faces, + const CGAL_BGL_NP_CLASS& np) + : _graph(const_cast(graph)) + , fimap(boost::choose_param(get_param(np, internal_np::face_index), get_const_property_map(face_index, graph))) + , vimap(boost::choose_param(get_param(np, boost::vertex_index), get_const_property_map(boost::vertex_index, graph))) + , himap(boost::choose_param(get_param(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + { + set_selected_faces(selected_faces); + } + + template + Face_filtered_graph(const Graph& graph, + const FaceRange& selected_faces) + : _graph(const_cast(graph)) + , fimap(get(CGAL::face_index, graph)) + , vimap(get(boost::vertex_index, graph)) + , himap(get(CGAL::halfedge_index, graph)) + { + set_selected_faces(selected_faces); + } + + ///returns a const reference to the underlying graph. + const Graph& graph()const{ return _graph; } + ///returns a reference to the underlying graph. + Graph& graph(){ return _graph; } + + ///change the set of selected faces using a patch id + template + void set_selected_faces(typename boost::property_traits::value_type face_patch_id, + FacePatchIndexMap face_patch_index_map) + { + face_indices.clear(); + vertex_indices.clear(); + halfedge_indices.clear(); + + selected_faces.resize(num_faces(_graph)); + selected_vertices.resize(num_vertices(_graph)); + selected_halfedges.resize(num_halfedges(_graph)); + BOOST_FOREACH(face_descriptor fd, faces(_graph) ) + { + if(get(face_patch_index_map, fd) == face_patch_id) + { + selected_faces.set(get(fimap, fd)); + BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, _graph), _graph)) + { + selected_halfedges.set(get(himap, hd)); + selected_halfedges.set(get(himap, opposite(hd, _graph))); + selected_vertices.set(get(vimap, target(hd, _graph))); + } + } + } + } + /// change the set of selected faces using a range of patch ids + template + void set_selected_faces(const FacePatchIndexRange& selected_face_patch_indices, + FacePatchIndexMap face_patch_index_map + #ifndef DOXYGEN_RUNNING + , typename boost::enable_if< + typename boost::has_range_const_iterator::type + >::type* = 0 + #endif + ) + { + face_indices.clear(); + vertex_indices.clear(); + halfedge_indices.clear(); + + selected_faces.resize(num_faces(_graph)); + selected_vertices.resize(num_vertices(_graph)); + selected_halfedges.resize(num_halfedges(_graph)); + typedef typename boost::property_traits::value_type Patch_index; + boost::unordered_set pids(boost::begin(selected_face_patch_indices), + boost::end(selected_face_patch_indices)); + + BOOST_FOREACH(face_descriptor fd, faces(_graph) ) + { + if(pids.count(get(face_patch_index_map, fd)) != 0) + { + selected_faces.set(get(fimap, fd)); + BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, _graph), _graph)) + { + selected_halfedges.set(get(himap, hd)); + selected_halfedges.set(get(himap, opposite(hd, _graph))); + selected_vertices.set(get(vimap, target(hd, _graph))); + } + } + } + } + /// change the set of selected faces using a range of face descriptors + template + void set_selected_faces(const FaceRange& selected_faces) + { + face_indices.clear(); + vertex_indices.clear(); + halfedge_indices.clear(); + + selected_faces.resize(num_faces(_graph)); + selected_vertices.resize(num_vertices(_graph)); + selected_halfedges.resize(num_halfedges(_graph)); + BOOST_FOREACH(face_descriptor fd, selected_faces) + { + selected_faces.set(get(fimap, fd)); + BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, _graph), _graph)) + { + selected_halfedges.set(get(himap, hd)); + selected_halfedges.set(get(himap, opposite(hd, _graph))); + selected_vertices.set(get(vimap, target(hd, _graph))); + } + } + } + + struct Is_simplex_valid + { + Is_simplex_valid(const Self* graph) + :adapter(graph) + {} + + Is_simplex_valid() + :adapter(NULL) + {} + template + bool operator()(Simplex s) + { + CGAL_assertion(adapter!=NULL); + return (in_CC(s, *adapter)); + } + const Self* adapter; + }; + + bool is_in_cc(face_descriptor f) const + { + return selected_faces[get(fimap, f)]; + } + + bool is_in_cc(vertex_descriptor v) const + { + return selected_vertices[get(vimap, v)]; + } + + bool is_in_cc(halfedge_descriptor h) const + { + return selected_halfedges[get(himap, h)]; + } + ///returns the number of selected faces + size_type number_of_faces()const + { + return selected_faces.count(); + } +///returns the number of selected vertices. + size_type number_of_vertices()const + { + return selected_vertices.count(); + } +///returns the number of selected halfedges. + size_type number_of_halfedges()const + { + return selected_halfedges.count(); + } + + Property_map_binder< FIMap, typename Pointer_property_map< typename boost::property_traits< FIMap >::value_type >::type > + get_face_index_map() const + { + if (face_indices.empty()) + { + face_index_type index = 0; + face_indices.resize(num_faces(_graph)); + for (std::size_t i=selected_faces.find_first(); i < selected_faces.npos; i = selected_faces.find_next(i)) + { + face_indices[i] = index++; + } + } + return bind_property_maps(fimap, make_property_map(face_indices) ); + } + + Property_map_binder< VIMap, typename Pointer_property_map< typename boost::property_traits< VIMap >::value_type >::type > + get_vertex_index_map() const + { + if (vertex_indices.empty()) + { + vertex_index_type index = 0; + vertex_indices.resize(num_vertices(_graph)); + for (std::size_t i=selected_vertices.find_first(); i < selected_vertices.npos; i = selected_vertices.find_next(i)) + { + vertex_indices[i] = index++; + } + } + return bind_property_maps(vimap, make_property_map(vertex_indices) ); + } + + Property_map_binder< HIMap, typename Pointer_property_map< typename boost::property_traits< HIMap >::value_type >::type > + get_halfedge_index_map() const + { + if (halfedge_indices.empty()) + { + halfedge_index_type index = 0; + halfedge_indices.resize(num_halfedges(_graph)); + for (std::size_t i=selected_halfedges.find_first(); i < selected_halfedges.npos; i = selected_halfedges.find_next(i)) + { + halfedge_indices[i] = index++; + } + } + return bind_property_maps(himap, make_property_map(halfedge_indices) ); + } + + /// returns `true` if around any vertex of a selected face, + /// there is at most one connected set of selected faces. + bool is_selection_valid() + { + BOOST_FOREACH(vertex_descriptor vd, vertices(*this) ) + { + face_descriptor first_selected = boost::graph_traits::null_face(); + bool first_unselected_found(false), + second_unselected_found(false); + + //find an unselected face, then find the first selected face. + //Find another unselected face, the next selected face must be the first; + //else this is not valid. + halfedge_descriptor hd = halfedge(vd, _graph); + face_descriptor first_tested = boost::graph_traits::null_face(); + while(1) //will break if valid, return false if not valid + { + face_descriptor fd = face(hd, _graph); + + if(first_tested == boost::graph_traits::null_face()) + first_tested = fd; + else if(fd == first_tested ) + { + //if there is no unselected face, break + if(selected_faces[get(fimap, fd)] && !first_unselected_found) + break; + //if there is no selected face, break + else if(!selected_faces[get(fimap, fd)] && + first_selected == boost::graph_traits::null_face()) + break; + } + + if(fd != boost::graph_traits::null_face()) + { + if(selected_faces[get(fimap, fd)]) + { + if(first_unselected_found && + first_selected == boost::graph_traits::null_face()) + { + first_selected = fd; + } + else if(second_unselected_found) + { + if(fd == first_selected) + break; + else + return false; + } + } + else + { + if(first_selected == boost::graph_traits::null_face()) + first_unselected_found = true; + else + second_unselected_found = true; + } + } + hd = next(opposite(hd, _graph), _graph); + } + } + return true; + } + +private: + Graph& _graph; + FIMap fimap; + VIMap vimap; + HIMap himap; + boost::dynamic_bitset<> selected_faces; + boost::dynamic_bitset<> selected_vertices; + boost::dynamic_bitset<> selected_halfedges; + mutable std::vector face_indices; + mutable std::vector vertex_indices; + mutable std::vector halfedge_indices; +}; + +} // namespace CGAL + +namespace boost +{ + +template +struct graph_traits< CGAL::Face_filtered_graph > +{ + typedef CGAL::Face_filtered_graph G; + typedef boost::graph_traits BGTG; + typedef typename BGTG::vertex_descriptor vertex_descriptor; + typedef typename BGTG::halfedge_descriptor halfedge_descriptor; + typedef typename BGTG::edge_descriptor edge_descriptor; + typedef typename BGTG::face_descriptor face_descriptor; + + typedef boost::filter_iterator vertex_iterator; + typedef boost::filter_iterator halfedge_iterator; + typedef boost::filter_iterator edge_iterator; + typedef boost::filter_iterator face_iterator; + + typedef boost::filter_iterator out_edge_iterator; + typedef boost::filter_iterator in_edge_iterator; + + typedef typename BGTG::directed_category directed_category; + typedef typename BGTG::edge_parallel_category edge_parallel_category; + typedef typename BGTG::traversal_category traversal_category; + typedef typename boost::dynamic_bitset<>::size_type vertices_size_type; + typedef typename boost::dynamic_bitset<>::size_type edges_size_type; + typedef typename boost::dynamic_bitset<>::size_type halfedges_size_type; + typedef typename boost::dynamic_bitset<>::size_type faces_size_type; + typedef typename BGTG::degree_size_type degree_size_type; + + static vertex_descriptor null_vertex() + { + return BGTG::null_vertex(); + } + + static halfedge_descriptor null_halfedge() + { + return BGTG::null_halfedge(); + } + + static edge_descriptor null_edge() + { + return edge_descriptor(BGTG::null_halfedge()); + } + + static face_descriptor null_face() + { + return BGTG::null_face(); + } +}; + +template +struct graph_traits< const CGAL::Face_filtered_graph > + : public graph_traits< CGAL::Face_filtered_graph > +{}; + + +} // namespace boost + + +namespace CGAL { +template +bool +in_CC(const typename boost::graph_traits< Face_filtered_graph >::face_descriptor f, + const Face_filtered_graph & w) +{ + return w.is_in_cc(f); +} + +template +bool +in_CC(const typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + return w.is_in_cc(h); +} + +template +bool +in_CC(const typename boost::graph_traits< Face_filtered_graph >::edge_descriptor e, + const Face_filtered_graph & w) +{ + return w.is_in_cc(halfedge(e, w.graph())); +} + +template +bool +in_CC(const typename boost::graph_traits< Face_filtered_graph >::vertex_descriptor v, + const Face_filtered_graph & w) +{ + return w.is_in_cc(v); +} + + +template +typename Face_filtered_graph::size_type +num_vertices(const Face_filtered_graph& w) +{ + return w.number_of_vertices(); +} + +template +typename Face_filtered_graph::size_type +num_edges(const Face_filtered_graph& w) +{ + return w.number_of_halfedges()/2; +} + +template +typename boost::graph_traits::degree_size_type +degree(typename boost::graph_traits >::vertex_descriptor v, + const Face_filtered_graph& w) +{ + CGAL_assertion(in_CC(v, w)); + typename boost::graph_traits::degree_size_type v_deg = 0; + typename boost::graph_traits >::halfedge_descriptor h = halfedge(v, w); + typename boost::graph_traits >::halfedge_descriptor hcirc = h; + do + { + if(in_CC(hcirc, w)) + ++v_deg; + hcirc = opposite(next(hcirc, w.graph()), w.graph()); + }while(hcirc != h); + return v_deg; +} + +template +typename boost::graph_traits::degree_size_type +out_degree(typename boost::graph_traits >::vertex_descriptor v, + const Face_filtered_graph& w) +{ + CGAL_assertion(in_CC(v, w)); + return static_cast::degree_size_type>( + std::distance(out_edges(v, w).first ,out_edges(v, w).second) ); +} + +template +typename boost::graph_traits::degree_size_type +in_degree(typename boost::graph_traits >::vertex_descriptor v, + const Face_filtered_graph& w) +{ + CGAL_assertion(in_CC(v, w)); + return static_cast::degree_size_type>( + std::distance(in_edges(v, w).first ,in_edges(v, w).second) ); +} + +template +typename boost::graph_traits >::vertex_descriptor +source(typename boost::graph_traits >::edge_descriptor e, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(e, w)); + return source(e, w.graph()); +} + +template +typename boost::graph_traits >::vertex_descriptor +target(typename boost::graph_traits >::edge_descriptor e, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(e, w)); + return target(e, w.graph()); +} + +template +std::pair >::edge_descriptor, bool> +edge(typename boost::graph_traits >::vertex_descriptor u, + typename boost::graph_traits >::vertex_descriptor v, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(u, w) && in_CC(v, w)); + typename boost::graph_traits >::edge_descriptor e = edge(u, v, w.graph()).first; + bool res = in_CC(e, w); + return std::make_pair(e, res); +} + + +template +CGAL::Iterator_range >::vertex_iterator> +vertices(const Face_filtered_graph & w) +{ + typedef typename boost::graph_traits >::vertex_iterator vertex_iterator; + typedef typename boost::graph_traits::vertex_iterator g_vertex_iterator; + + typename Face_filtered_graph ::Is_simplex_valid predicate(&w); + g_vertex_iterator b,e; + boost::tie(b,e) = vertices(w.graph()); + return make_range(vertex_iterator(predicate, b, e), + vertex_iterator(predicate, e, e)); +} + +template +CGAL::Iterator_range >::edge_iterator> +edges(const Face_filtered_graph & w) +{ + typedef typename boost::graph_traits >::edge_iterator edge_iterator; + typedef typename boost::graph_traits::edge_iterator g_edge_iterator; + + typename Face_filtered_graph ::Is_simplex_valid predicate(&w); + g_edge_iterator b,e; + boost::tie(b,e) = edges(w.graph()); + return make_range(edge_iterator(predicate, b, e), + edge_iterator(predicate, e, e)); +} + +template +CGAL::Iterator_range >::out_edge_iterator> +out_edges(typename boost::graph_traits >::vertex_descriptor v, + const Face_filtered_graph & w) +{ + + typedef typename boost::graph_traits >::out_edge_iterator out_edge_iterator; + typedef typename boost::graph_traits::out_edge_iterator g_out_edge_iterator; + + typename Face_filtered_graph ::Is_simplex_valid predicate(&w); + g_out_edge_iterator b,e; + boost::tie(b,e) = out_edges(v, w.graph()); + return make_range(out_edge_iterator(predicate, b, e), + out_edge_iterator(predicate, e, e)); +} + +template +CGAL::Iterator_range >::in_edge_iterator> +in_edges(typename boost::graph_traits >::vertex_descriptor v, + const Face_filtered_graph & w) +{ + + typedef typename boost::graph_traits >::in_edge_iterator in_edge_iterator; + typedef typename boost::graph_traits::in_edge_iterator g_in_edge_iterator; + + typename Face_filtered_graph ::Is_simplex_valid predicate(&w); + g_in_edge_iterator b,e; + boost::tie(b,e) = in_edges(v, w.graph()); + return make_range(in_edge_iterator(predicate, b, e), + in_edge_iterator(predicate, e, e)); +} + +// +// HalfedgeGraph +// +template +typename boost::graph_traits< Face_filtered_graph >::edge_descriptor +edge(typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + CGAL_assertion(CGAL::in_CC(h, w)); + return edge(h, w.graph()); +} + +template +typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor +halfedge(typename boost::graph_traits< Face_filtered_graph >::edge_descriptor e, + const Face_filtered_graph & w) +{ + CGAL_assertion(CGAL::in_CC(e, w)); + return halfedge(e, w.graph()); +} + +template +typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor +halfedge(typename boost::graph_traits< Face_filtered_graph >::vertex_descriptor v, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(v, w)); + typename boost::graph_traits >::halfedge_descriptor h = halfedge(v, w.graph()); + typename boost::graph_traits >::halfedge_descriptor hcirc = h; + do + { + if(in_CC(hcirc, w)) + return hcirc; + hcirc = opposite(next(hcirc, w.graph()), w.graph()); + }while(hcirc != h); + return boost::graph_traits< CGAL::Face_filtered_graph >::null_halfedge(); +} + + +template +std::pair >::halfedge_descriptor, bool> +halfedge(typename boost::graph_traits< Face_filtered_graph >::vertex_descriptor u, + typename boost::graph_traits< Face_filtered_graph >::vertex_descriptor v, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(u, w) && in_CC(v, w)); + typename boost::graph_traits >::halfedge_descriptor h = halfedge(u, v, w.graph()).first; + return std::make_pair(h, in_CC(h, w)); +} + + +template +typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor +opposite(typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(h, w) ); + return opposite(h, w.graph()); +} + +template +typename boost::graph_traits< Face_filtered_graph >::vertex_descriptor +source(typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(h, w) ); + return source(h, w.graph()); +} + +template +typename boost::graph_traits< Face_filtered_graph >::vertex_descriptor +target(typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(h, w) ); + return target(h, w.graph()); +} + +template +typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor +next(typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + CGAL_assertion(in_CC(h, w)); + if(in_CC(next(h, w.graph()), w)) + return next(h, w.graph()); + //act as a border + typedef typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h_d; + BOOST_FOREACH( h_d hcirc, + CGAL::halfedges_around_target(target(h, w.graph()), w.graph())) + { + if(hcirc != h && in_CC(hcirc, w)) + { + return opposite(hcirc, w.graph()); + } + } + return boost::graph_traits< CGAL::Face_filtered_graph >::null_halfedge(); +} + +template +typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor +prev(typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + + CGAL_assertion(in_CC(h, w)); + if(in_CC(prev(h, w.graph()), w)) + return prev(h, w.graph()); + + //act as a border + typedef typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h_d; + BOOST_FOREACH(h_d hcirc, + CGAL::halfedges_around_source(source(h, w.graph()), w.graph())) + { + if(hcirc != h && in_CC(hcirc, w)) + { + return opposite(hcirc, w.graph()); + } + } + return boost::graph_traits< CGAL::Face_filtered_graph >::null_halfedge(); +} + +// +// HalfedgeListGraph +// + +template +std::pair >::halfedge_iterator, +typename boost::graph_traits >::halfedge_iterator> +halfedges(const Face_filtered_graph & w) +{ + typedef typename boost::graph_traits >::halfedge_iterator halfedge_iterator; + typedef typename boost::graph_traits::halfedge_iterator g_halfedge_iterator; + + typename Face_filtered_graph ::Is_simplex_valid predicate(&w); + std::pair original_halfedges = halfedges(w.graph()); + + return make_range(halfedge_iterator(predicate, original_halfedges.first, original_halfedges.second), + halfedge_iterator(predicate, original_halfedges.second, original_halfedges.second)); +} + + +template +typename Face_filtered_graph::size_type +num_halfedges(const Face_filtered_graph & w) +{ + return w.number_of_halfedges(); +} + +// FaceGraph +template +typename boost::graph_traits< Face_filtered_graph >::face_descriptor +face(typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor h, + const Face_filtered_graph & w) +{ + CGAL_assertion(CGAL::in_CC(h, w)); + if(face(h, w.graph()) == boost::graph_traits::null_face()) // h is a border hafedge + return boost::graph_traits< CGAL::Face_filtered_graph >::null_face(); + else if(in_CC(face(h,w.graph()), w)) + return face(h,w.graph()); + else + return boost::graph_traits< CGAL::Face_filtered_graph >::null_face(); +} + +template +typename boost::graph_traits< Face_filtered_graph >::halfedge_descriptor +halfedge(typename boost::graph_traits< Face_filtered_graph >::face_descriptor f, + const Face_filtered_graph & w) +{ + CGAL_assertion(CGAL::in_CC(f, w)); + return halfedge(f,w.graph()); +} + + +template +Iterator_range >::face_iterator> +faces(const Face_filtered_graph & w) +{ + typedef typename boost::graph_traits >::face_iterator face_iterator; + typedef typename boost::graph_traits::face_iterator g_face_iterator; + + typename Face_filtered_graph ::Is_simplex_valid predicate(&w); + std::pair original_faces = faces(w.graph()); + + return make_range(face_iterator(predicate, original_faces.first, original_faces.second), + face_iterator(predicate, original_faces.second, original_faces.second)); +} + + + +template +typename Face_filtered_graph::size_type +num_faces(const Face_filtered_graph & w) +{ + return w.number_of_faces(); +} + + +template +bool +in_CC(const Face_filtered_graph & w, bool verbose = false) +{ + return in_CC(w.graph(),verbose); +} + +template +typename boost::property_map::const_type +get(PropertyTag ptag, const Face_filtered_graph& w) +{ + return get(ptag, w.graph()); +} + +template +typename boost::property_map::type +get(PropertyTag ptag, Face_filtered_graph& w) +{ + return get(ptag, w.graph()); +} + +//specializations for indices +template +typename boost::property_map, CGAL::face_index_t >::type +get(CGAL::face_index_t, const Face_filtered_graph& w) +{ + return w.get_face_index_map(); +} + + +template +typename boost::property_map, boost::vertex_index_t >::type +get(boost::vertex_index_t, const Face_filtered_graph& w) +{ + return w.get_vertex_index_map(); +} + + +template +typename boost::property_map, CGAL::halfedge_index_t >::type +get(CGAL::halfedge_index_t, const Face_filtered_graph& w) +{ + return w.get_halfedge_index_map(); +} + + +template +typename boost::property_traits::type>::value_type +get(PropertyTag ptag, + const Face_filtered_graph& w, + const typename boost::property_traits::type>::key_type& k) +{ + return get(ptag, w.graph(), k); +} + + +template +void +put(PropertyTag ptag, const Face_filtered_graph& w, + const typename boost::property_traits::type>::key_type& k, + typename boost::property_traits::type>::value_type& v) +{ + put(ptag, w.graph(), k, v); +} + +}//end namespace CGAL + +namespace boost { +template +struct property_map,PropertyTag> { + typedef typename boost::property_map::type type; + typedef typename boost::property_map::const_type const_type; +}; + +template +struct graph_has_property, PropertyTag> + : graph_has_property {}; + + +//specializations for indices +template +struct property_map, CGAL::face_index_t>{ + typedef typename CGAL::Property_map_binder< FIMap, + typename CGAL::Pointer_property_map< typename boost::property_traits< FIMap >::value_type >::type > type; + typedef type const_type; +}; + +template +struct property_map, boost::vertex_index_t>{ + typedef typename CGAL::Property_map_binder< VIMap, + typename CGAL::Pointer_property_map< typename boost::property_traits< VIMap >::value_type >::type > type; + typedef type const_type; +}; + +template + +struct property_map, CGAL::halfedge_index_t>{ + typedef typename CGAL::Property_map_binder< HIMap, + typename CGAL::Pointer_property_map< typename boost::property_traits< HIMap >::value_type >::type > type; + typedef type const_type; +}; +}// namespace boost +#endif // CGAL_BOOST_GRAPH_FACE_FILTERED_GRAPH_H diff --git a/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h b/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h index 41301dfdcc6..8e95d30f858 100644 --- a/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h +++ b/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -325,8 +326,7 @@ edge(typename boost::graph_traits >::ver template -std::pair >::vertex_iterator, - typename boost::graph_traits >::vertex_iterator> +CGAL::Iterator_range >::vertex_iterator> vertices(const Graph_with_descriptor_with_graph & w) { typename boost::graph_traits::vertex_iterator b,e; @@ -336,8 +336,7 @@ vertices(const Graph_with_descriptor_with_graph & w) } template -std::pair >::edge_iterator, - typename boost::graph_traits >::edge_iterator> +CGAL::Iterator_range >::edge_iterator> edges(const Graph_with_descriptor_with_graph & w) { typename boost::graph_traits::edge_iterator b,e; @@ -347,8 +346,7 @@ edges(const Graph_with_descriptor_with_graph & w) } template -std::pair >::out_edge_iterator, - typename boost::graph_traits >::out_edge_iterator> +CGAL::Iterator_range >::out_edge_iterator> out_edges(typename boost::graph_traits >::vertex_descriptor v, const Graph_with_descriptor_with_graph & w) { @@ -360,8 +358,7 @@ out_edges(typename boost::graph_traits > } template -std::pair >::in_edge_iterator, - typename boost::graph_traits >::in_edge_iterator> +CGAL::Iterator_range >::in_edge_iterator> in_edges(typename boost::graph_traits >::vertex_descriptor v, const Graph_with_descriptor_with_graph & w) { @@ -630,8 +627,7 @@ prev(typename boost::graph_traits< Graph_with_descriptor_with_graph >::ha // template -std::pair >::halfedge_iterator, - typename boost::graph_traits >::halfedge_iterator> +CGAL::Iterator_range >::halfedge_iterator> halfedges(const Graph_with_descriptor_with_graph & w) { typename boost::graph_traits::halfedge_iterator b,e; @@ -671,8 +667,7 @@ halfedge(typename boost::graph_traits< Graph_with_descriptor_with_graph > template -std::pair >::face_iterator, - typename boost::graph_traits >::face_iterator> +CGAL::Iterator_range >::face_iterator> faces(const Graph_with_descriptor_with_graph & w) { typename boost::graph_traits::face_iterator b,e; diff --git a/BGL/include/CGAL/boost/graph/named_function_params.h b/BGL/include/CGAL/boost/graph/named_function_params.h index e54eefb81a8..eaab2e76b2c 100644 --- a/BGL/include/CGAL/boost/graph/named_function_params.h +++ b/BGL/include/CGAL/boost/graph/named_function_params.h @@ -101,6 +101,8 @@ namespace boost{ } //end of namespace boost #endif +#define CGAL_BGL_NP_TEMPLATE_PARAMETERS T, typename Tag, typename Base +#define CGAL_BGL_NP_CLASS CGAL::cgal_bgl_named_params namespace CGAL { namespace internal_np{ @@ -162,6 +164,68 @@ using boost::visitor; } // namespace parameters + //helper classes + template + class property_map_selector + { + public: + typedef typename boost::graph_has_property::type Has_internal_pmap; + typedef typename boost::mpl::if_c< Has_internal_pmap::value + , typename boost::property_map::type + , typename boost::cgal_no_property::type + >::type type; + typedef typename boost::mpl::if_c< Has_internal_pmap::value + , typename boost::property_map::const_type + , typename boost::cgal_no_property::const_type + >::type const_type; + + type get_pmap(const PropertyTag& p, PolygonMesh& pmesh) + { + return get_impl(p, pmesh, Has_internal_pmap()); + } + + const_type get_const_pmap(const PropertyTag& p, const PolygonMesh& pmesh) + { + return get_const_pmap_impl(p, pmesh, Has_internal_pmap()); + } + + private: + type get_impl(const PropertyTag&, PolygonMesh&, CGAL::Tag_false) + { + return type(); //boost::cgal_no_property::type + } + type get_impl(const PropertyTag& p, PolygonMesh& pmesh, CGAL::Tag_true) + { + return get(p, pmesh); + } + + const_type get_const_pmap_impl(const PropertyTag& + , const PolygonMesh&, CGAL::Tag_false) + { + return const_type(); //boost::cgal_no_property::type + } + const_type get_const_pmap_impl(const PropertyTag& p + , const PolygonMesh& pmesh, CGAL::Tag_true) + { + return get(p, pmesh); + } + }; + + template + typename property_map_selector::type + get_property_map(const PropertyTag& p, PolygonMesh& pmesh) + { + property_map_selector pms; + return pms.get_pmap(p, pmesh); + } + + template + typename property_map_selector::const_type + get_const_property_map(const PropertyTag& p, const PolygonMesh& pmesh) + { + property_map_selector pms; + return pms.get_const_pmap(p, pmesh); + } } //namespace CGAL // partial specializations hate inheritance and we need to repeat diff --git a/BGL/test/BGL/CMakeLists.txt b/BGL/test/BGL/CMakeLists.txt index 8b92375ef40..551b40ec2ca 100644 --- a/BGL/test/BGL/CMakeLists.txt +++ b/BGL/test/BGL/CMakeLists.txt @@ -88,8 +88,14 @@ create_single_source_cgal_program( "test_Has_member_id.cpp" ) create_single_source_cgal_program( "test_cgal_bgl_named_params.cpp" ) +create_single_source_cgal_program( "graph_concept_Face_filtered_graph.cpp" ) +create_single_source_cgal_program( "test_Face_filtered_graph.cpp" ) +if(OpenMesh_FOUND) + target_link_libraries( test_Face_filtered_graph ${OPENMESH_LIBRARIES}) +endif() + if(OpenMesh_FOUND) target_link_libraries( test_clear ${OPENMESH_LIBRARIES}) endif() diff --git a/BGL/test/BGL/graph_concept_Face_filtered_graph.cpp b/BGL/test/BGL/graph_concept_Face_filtered_graph.cpp new file mode 100644 index 00000000000..ab8957bfb60 --- /dev/null +++ b/BGL/test/BGL/graph_concept_Face_filtered_graph.cpp @@ -0,0 +1,53 @@ + +#include +#include +#include + +#include +#include + +typedef CGAL::Simple_cartesian K; +typedef CGAL::Surface_mesh SM; +typedef CGAL::Face_filtered_graph::face_descriptor , std::size_t> > Adapter; +typedef boost::graph_traits< Adapter > Traits; +typedef Traits::edge_descriptor edge_descriptor; +typedef Traits::halfedge_descriptor halfedge_descriptor; +typedef Traits::vertex_descriptor vertex_descriptor; +typedef Traits::face_descriptor face_descriptor; + +void concept_check_adapter() +{ + boost::function_requires< boost::GraphConcept >(); + boost::function_requires< boost::VertexListGraphConcept >(); + boost::function_requires< boost::EdgeListGraphConcept >(); + boost::function_requires< boost::IncidenceGraphConcept >(); + boost::function_requires< boost::AdjacencyMatrixConcept >(); + boost::function_requires< boost::BidirectionalGraphConcept >(); + boost::function_requires< CGAL::HalfedgeGraphConcept >(); + boost::function_requires< CGAL::HalfedgeListGraphConcept >(); + boost::function_requires< CGAL::FaceGraphConcept >(); + boost::function_requires< CGAL::FaceListGraphConcept >(); + + boost::function_requires< boost::concepts::ReadablePropertyGraph< + Adapter, halfedge_descriptor, CGAL::halfedge_index_t> >(); + boost::function_requires< boost::concepts::ReadablePropertyGraph< + Adapter, edge_descriptor, boost::edge_index_t> >(); + boost::function_requires< boost::concepts::ReadablePropertyGraph< + Adapter, edge_descriptor, boost::edge_weight_t> >(); + boost::function_requires< boost::concepts::PropertyGraph< + Adapter, vertex_descriptor, CGAL::vertex_point_t> >(); + boost::function_requires< boost::concepts::ReadablePropertyGraph< + Adapter, vertex_descriptor, boost::vertex_index_t> >(); + boost::function_requires< boost::concepts::ReadablePropertyGraph< + Adapter, face_descriptor, CGAL::face_index_t> >(); + + // null + boost::graph_traits::null_vertex(); + boost::graph_traits::null_face(); +} + +int main() +{ + concept_check_adapter(); + return 0; +} diff --git a/BGL/test/BGL/test_Face_filtered_graph.cpp b/BGL/test/BGL/test_Face_filtered_graph.cpp new file mode 100644 index 00000000000..75427a24292 --- /dev/null +++ b/BGL/test/BGL/test_Face_filtered_graph.cpp @@ -0,0 +1,466 @@ +#include +#include +#include +#include "test_Prefix.h" +#include +#include +#include +#include +#include +#include + +typedef boost::unordered_set id_map; + +template +void test_halfedge_around_vertex_iterator(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + boost::unordered_map map(num_faces(g)); + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + + + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + typename boost::graph_traits::vertex_iterator vit, vend; + for(boost::tie(vit, vend) = vertices(fg); vit != vend; ++vit) { + halfedge_around_target_iterator havit, havend; + for(boost::tie(havit, havend) = CGAL::halfedges_around_target(halfedge(*vit, fg), fg); + havit != havend; ++havit) { + assert(target(*havit, fg) == *vit); + + // check if we are really moving clockwise + halfedge_around_target_iterator step = boost::next(havit); + if(step != havend) { + halfedge_descriptor stepd = *step; + assert(stepd == opposite(next(*havit, fg), fg)); + } + } + } +} + +template +void test_halfedge_around_face_iterator(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + face_iterator fit, fend; + for(boost::tie(fit, fend) = faces(fg); fit != fend; ++fit) { + halfedge_around_face_iterator hafit, hafend; + boost::tie(hafit, hafend) = CGAL::halfedges_around_face(halfedge(*fit, fg), fg); + assert(std::distance(hafit, hafend) != 0); + for(boost::tie(hafit, hafend) = CGAL::halfedges_around_face(halfedge(*fit, fg), fg); hafit != hafend; ++hafit) { + assert(face(*hafit, fg) == *fit); + } + } +} + +template +void test_edge_iterators(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + + // do we iterate as many as that? + edge_iterator eb, ee; + boost::tie(eb, ee) = edges(fg); + assert(boost::numeric_cast(std::distance(eb, ee)) == num_edges(g)); + id_map ids; + unsigned int count = 0; + for(boost::tie(eb, ee) = edges(fg); eb != ee; ++eb) { + edge_descriptor e = *eb; + std::pair r = ids.insert(get(boost::edge_index, g, e)); + // unique? + assert(r.second); + ++count; + } + assert(count == num_edges(fg)); +} + +template +void test_vertex_iterators(Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + vertex_iterator vb, ve; + std::size_t count = 0; + for(boost::tie(vb, ve) = vertices(fg); vb != ve; ++vb){ + ++count; + } + + assert(count == num_vertices(fg)); + + // check that the iterators reach uniques + id_map ids; + + count = 0; + for(boost::tie(vb, ve) = vertices(fg); vb != ve; ++vb) { + std::pair r = ids.insert(get(boost::vertex_index, g, *vb)); + assert(r.second); + ++count; + } + assert(count == num_vertices(fg)); +} + + +template +void test_out_edges(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + + vertex_iterator vb, ve; + for(boost::tie(vb, ve) = vertices(fg); vb != ve; ++vb) { + id_map v_ids; + + vertex_descriptor around = *vb; + out_edge_iterator oeb, oee; + for(boost::tie(oeb, oee) = out_edges(*vb, fg); oeb != oee; ++oeb) { + vertex_descriptor t = target(*oeb, fg); + vertex_descriptor s = source(*oeb, fg); + assert(s != t); + assert(s == around); + assert(t != around); + std::pair r = + v_ids.insert(get(boost::vertex_index, g, target(*oeb, fg))); + assert(r.second); + } + } +} + +template +void test_in_edges(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + + vertex_iterator vb, ve; + for(boost::tie(vb, ve) = vertices(fg); vb != ve; ++vb) { + id_map v_ids; + vertex_descriptor around = *vb; + in_edge_iterator ieb, iee; + for(boost::tie(ieb, iee) = in_edges(*vb, fg); ieb != iee; ++ieb) { + vertex_descriptor t = target(*ieb, fg); + vertex_descriptor s = source(*ieb, fg); + assert(t == around); + assert(s != around); + std::pair r = + v_ids.insert(get(boost::vertex_index, g, source(*ieb, fg))); + assert(r.second); + } + } +} + +template +void test_in_out_edges(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + + // check that the sets of in out edges are the same + vertex_iterator vb, ve; + for(boost::tie(vb, ve) = vertices(fg); vb != ve; ++vb) { + id_map v_ids; + std::vector in, out; + in_edge_iterator ieb, iee; + for(boost::tie(ieb, iee) = in_edges(*vb, fg); ieb != iee; ++ieb) { + std::pair r = + v_ids.insert(get(boost::vertex_index, g, source(*ieb, fg))); + assert(r.second); + in.push_back(source(*ieb, fg)); + } + out_edge_iterator oeb, oee; + for(boost::tie(oeb, oee) = out_edges(*vb, fg); oeb != oee; ++oeb) { + std::pair r = + v_ids.insert(get(boost::vertex_index, g, target(*oeb, fg))); + // insertion must fail + assert(!r.second); + out.push_back(target(*oeb, fg)); + } + // did we walk the vertices in the same order? + assert(in.size() == out.size()); + assert(std::equal(in.begin(), in.end(), out.begin())); + assert(in.size() == in_degree(*vb, fg)); + assert(out.size() == out_degree(*vb, fg)); + assert(in.size() == degree(*vb, fg)); + assert(degree(*vb, fg) == in_degree(*vb, fg)); + assert(degree(*vb, fg) == out_degree(*vb, fg)); + } +} + +// check that every edge can be found through edge(u, v, g) +template +void test_edge_find(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + typedef std::pair ret; + + edge_iterator eb, ee; + for(boost::tie(eb, ee) = edges(fg); eb != ee; ++eb) { + vertex_descriptor s = source(*eb, fg); + vertex_descriptor t = target(*eb, fg); + ret found = edge(s, t, fg); + ret found2 = edge(t, s, fg); + assert(found.second); + assert(found2.second); + assert(found.first == *eb); + assert(found2.first == *eb); + } +} + +template +void test_faces(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + + unsigned int count = 0; + face_iterator fb, fe; + for(boost::tie(fb, fe) = faces(fg); fb != fe; ++fb) { + ++count; + // reverse look-up + halfedge_descriptor assoc = halfedge(*fb, fg); + assert(face(assoc, fg) == *fb); + // check the enclosure + halfedge_around_face_iterator encb, ence; + for(boost::tie(encb, ence) = CGAL::halfedges_around_face(halfedge(*fb, fg), fg); encb != ence; ++encb) { + assert(face(*encb, fg) == *fb); + } + } + assert(count == num_faces(fg)); +} + +template +void test_read(const Graph& g) +{ + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + std::map map; + CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + assert(CGAL::is_valid(fg)); +} + +template +void +test(const std::vector& graphs) +{ + BOOST_FOREACH(Graph p, graphs){ + test_read(p); + test_vertex_iterators(p); + test_out_edges(p); + test_in_edges(p); + test_in_out_edges(p); + test_edge_find(p); + test_faces(p); + test_edge_iterators(p); + test_halfedge_around_face_iterator(p); + test_halfedge_around_vertex_iterator(p); + } +} + + +typedef SM::Point Point_3; + +template +struct Constraint : public boost::put_get_helper > +{ + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::readable_property_map_tag category; + typedef bool value_type; + typedef bool reference; + typedef edge_descriptor key_type; + + + Constraint() + :g_(NULL) + {} + + Constraint(Mesh& g, VertexPointPMap vpp) + : g_(&g), vppmap(vpp) + {} + + bool operator[](edge_descriptor e) const + { + const Mesh& g = *g_; + if( + ((boost::get(vppmap, target(e, g)) == Point_3(1,1,1) || + boost::get(vppmap, source(e, g)) == Point_3(1,1,1)) && + (boost::get(vppmap, target(e, g)) == Point_3(0,0,0) || + boost::get(vppmap, source(e, g)) == Point_3(0,0,0))) + || + ((boost::get(vppmap, target(e, g)) == Point_3(1,1,1) || + boost::get(vppmap, source(e, g)) == Point_3(1,1,1)) && + (boost::get(vppmap, target(e, g)) == Point_3(0,0,1) || + boost::get(vppmap, source(e, g)) == Point_3(0,0,1))) + || + ((boost::get(vppmap, target(e, g)) == Point_3(0,0,1) || + boost::get(vppmap, source(e, g)) == Point_3(0,0,1)) && + (boost::get(vppmap, target(e, g)) == Point_3(0,0,0) || + boost::get(vppmap, source(e, g)) == Point_3(0,0,0))) + || + ((boost::get(vppmap, target(e, g)) == Point_3(1,0,1) || + boost::get(vppmap, source(e, g)) == Point_3(1,0,1)) && + (boost::get(vppmap, target(e, g)) == Point_3(0,0,0) || + boost::get(vppmap, source(e, g)) == Point_3(0,0,0))) + || + ((boost::get(vppmap, target(e, g)) == Point_3(1,1,1) || + boost::get(vppmap, source(e, g)) == Point_3(1,1,1)) && + (boost::get(vppmap, target(e, g)) == Point_3(1,0,1) || + boost::get(vppmap, source(e, g)) == Point_3(1,0,1))) + ) + return true; + else + return false; + } + + const Mesh* g_; + VertexPointPMap vppmap; +}; +template +void test_mesh(Adapter fga) +{ + + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + //check that there is the right number of simplices in fga + CGAL_assertion(CGAL::is_valid(fga)); + CGAL_assertion(num_faces(fga) == 2); + CGAL_assertion(num_edges(fga) == 5); + CGAL_assertion(num_halfedges(fga) == 10); + CGAL_assertion(num_vertices(fga) == 4); + halfedge_descriptor h = halfedge(*faces(fga).first, fga); + CGAL_assertion_code( vertex_descriptor v = source(h, fga) ); + //check that next() works inside the patch + CGAL_assertion( + next(next(next(h, fga), fga), fga) == h + ); + //check that next() works on bordure of the patch + h = opposite(h, fga); + CGAL_assertion( + next(next(next(next(h, fga), fga), fga), fga) == h + ); + //check that prev() works inside the patch + h = halfedge(*faces(fga).first, fga); + CGAL_assertion( + prev(prev(prev(h, fga), fga), fga) == h + ); + //check that prev() works on bordure of the patch + h = opposite(h, fga); + CGAL_assertion( + prev(prev(prev(prev(h, fga), fga), fga), fga) == h + ); + //check degree + CGAL_assertion(degree(v, fga) == 3); + //check in_edges and out_edges + CGAL_assertion(std::distance(in_edges(v, fga).first ,in_edges(v, fga).second) == 3 ); + CGAL_assertion(std::distance(out_edges(v, fga).first ,out_edges(v, fga).second) == 3 ); + + Mesh copy; + CGAL::copy_face_graph(fga, copy); +} + + +int +main() +{ + test(sm_data()); +#ifdef CGAL_USE_OPENMESH + test(omesh_data()); +#endif + //Make a tetrahedron and test the adapter for a patch that only contains 2 faces + typedef CGAL::Face_filtered_graph SM_Adapter; + typedef SM::Property_map::face_descriptor , std::size_t> SM_FCCMap; + SM* sm = new SM(); + CGAL::make_tetrahedron( + Point_3(1,1,1), + Point_3(0,0,0), + Point_3(0,0,1), + Point_3(1,0,1), + *sm); + SM_FCCMap fccmap = + sm->add_property_map::face_descriptor, std::size_t>("f:CC").first; + SM::Property_map::vertex_descriptor, SM::Point> positions = + sm->points(); + CGAL::Polygon_mesh_processing::connected_components(*sm, fccmap, CGAL::Polygon_mesh_processing::parameters:: + edge_is_constrained_map(Constraint::vertex_descriptor, + SM::Point> >(*sm, positions))); + boost::unordered_set pids; + pids.insert(0); + pids.insert(2); + SM_Adapter sm_adapter(*sm, pids, fccmap); + test_mesh(sm_adapter); + + + + + typedef boost::graph_traits PolyTraits; + typedef boost::property_map::type VPMap; + typedef PolyTraits::face_descriptor poly_face_descriptor; + typedef boost::associative_property_map< std::map > FCMap; + typedef boost::property_map::type FIMap; + typedef boost::property_map::type VIMap; + typedef boost::property_map::type HIMap; + typedef CGAL::Face_filtered_graph Poly_Adapter; + Polyhedron *poly = new Polyhedron(); + CGAL::make_tetrahedron( + Point_3(1,1,1), + Point_3(0,0,0), + Point_3(0,0,1), + Point_3(1,0,1), + *poly); + + + FIMap poly_fimap = get(CGAL::face_external_index, *poly); + VIMap poly_vimap = get(CGAL::vertex_external_index, *poly); + HIMap poly_himap = get(CGAL::halfedge_external_index, *poly); + std::map fc_map; + FCMap poly_fccmap(fc_map); + + VPMap vpmap = get(boost::vertex_point, *poly); + CGAL::Polygon_mesh_processing::connected_components(*poly, poly_fccmap, CGAL::Polygon_mesh_processing::parameters:: + edge_is_constrained_map(Constraint(*poly, vpmap)). + face_index_map(poly_fimap)); + Poly_Adapter poly_adapter(*poly, + pids, + poly_fccmap, + CGAL::parameters::face_index_map(poly_fimap). + vertex_index_map(poly_vimap). + halfedge_index_map(poly_himap)); + test_mesh(poly_adapter); +} diff --git a/Installation/changes.html b/Installation/changes.html index 55f6a05be02..f333407b38d 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -178,6 +178,14 @@ and src/ directories). +

CGAL and the Boost Graph Library (BGL)

+
    +
  • + Add class CGAL::Face_filtered_graph that + wraps an existing graph and hide all simplices that are not + in the selected connected components. +
  • +
diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 4dfac665d86..c87dd1a0a3e 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -598,7 +598,7 @@ should be discarded in favour of major connected components. \subsection CCExample Connected Components Example -The following example shows how to record the connected +The first example shows how to record the connected components of a polygon mesh. In particular, we provide an example for the optional parameter \c EdgeConstraintMap, a property map that returns information about an edge being a \e constraint or not. @@ -607,6 +607,12 @@ the propagation of a connected component index to cross it. \cgalExample{Polygon_mesh_processing/connected_components_example.cpp} +The second example shows how to use the class template `Face_filtered_graph` +which enables to treat one or several connected components as a face graph. + +\cgalExample{Polygon_mesh_processing/face_filtered_graph_example.cpp} + + \section PMPDistance Approximate Hausdorff Distance This package provides methods to compute (approximate) distances between meshes and point sets. diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt index f47ca95cac6..c48fdb07ad1 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt @@ -7,6 +7,7 @@ \example Polygon_mesh_processing/point_inside_example.cpp \example Polygon_mesh_processing/triangulate_faces_example.cpp \example Polygon_mesh_processing/connected_components_example.cpp +\example Polygon_mesh_processing/face_filtered_graph_example.cpp \example Polygon_mesh_processing/polygon_soup_example.cpp \example Polygon_mesh_processing/triangulate_polyline_example.cpp \example Polygon_mesh_processing/refine_fair_example.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 8560602f720..f45f1a02ba4 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -90,6 +90,7 @@ create_single_source_cgal_program( "compute_normals_example.cpp" CXX_FEATURES cx create_single_source_cgal_program( "point_inside_example.cpp") create_single_source_cgal_program( "triangulate_faces_example.cpp") create_single_source_cgal_program( "connected_components_example.cpp") +create_single_source_cgal_program( "face_filtered_graph_example.cpp") create_single_source_cgal_program( "polygon_soup_example.cpp") create_single_source_cgal_program( "triangulate_polyline_example.cpp") create_single_source_cgal_program( "mesh_slicer_example.cpp") diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/face_filtered_graph_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/face_filtered_graph_example.cpp new file mode 100644 index 00000000000..f9b4b46c932 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/face_filtered_graph_example.cpp @@ -0,0 +1,63 @@ +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::Point_3 Point; + +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::face_descriptor face_descriptor; +typedef boost::graph_traits::faces_size_type faces_size_type; + +typedef Mesh::Property_map FCCmap; + typedef CGAL::Face_filtered_graph Filtered_graph; + +namespace PMP = CGAL::Polygon_mesh_processing; + + +int main(int argc, char* argv[]) +{ + std::ifstream input((argc > 1) ? argv[1] : "data/blobby_3cc.off"); + + Mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid off file." << std::endl; + return 1; + } + + FCCmap fccmap = mesh.add_property_map("f:CC").first; + + faces_size_type num = PMP::connected_components(mesh,fccmap); + + std::cerr << "- The graph has " << num << " connected components (face connectivity)" << std::endl; + + Filtered_graph ffg(mesh, 0, fccmap); + + std::cout << "The faces in component 0 are:" << std::endl; + BOOST_FOREACH(boost::graph_traits::face_descriptor f, faces(ffg)){ + std::cout << f << std::endl; + } + + if(num>1){ + std::vector components; + components.push_back(0); + components.push_back(1); + + ffg.set_selected_faces(components, fccmap); + + std::cout << "The faces in components 0 and 1 are:" << std::endl; + BOOST_FOREACH(Filtered_graph::face_descriptor f, faces(ffg)){ + std::cout << f << std::endl; + } + } + return 0; +} + diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_params_helper.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_params_helper.h index 50daf1c47a7..30cc2b5e7df 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_params_helper.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_params_helper.h @@ -42,52 +42,6 @@ public: typedef typename boost::property_traits::value_type type; }; -template -class property_map_selector -{ -public: - typedef typename boost::graph_has_property::type Has_internal_pmap; - typedef typename boost::mpl::if_c< Has_internal_pmap::value - , typename boost::property_map::type - , typename boost::cgal_no_property::type - >::type type; - typedef typename boost::mpl::if_c< Has_internal_pmap::value - , typename boost::property_map::const_type - , typename boost::cgal_no_property::const_type - >::type const_type; - - type get_pmap(const PropertyTag& p, PolygonMesh& pmesh) - { - return get_impl(p, pmesh, Has_internal_pmap()); - } - - const_type get_const_pmap(const PropertyTag& p, const PolygonMesh& pmesh) - { - return get_const_pmap_impl(p, pmesh, Has_internal_pmap()); - } - -private: - type get_impl(const PropertyTag&, PolygonMesh&, CGAL::Tag_false) - { - return type(); //boost::cgal_no_property::type - } - type get_impl(const PropertyTag& p, PolygonMesh& pmesh, CGAL::Tag_true) - { - return get(p, pmesh); - } - - const_type get_const_pmap_impl(const PropertyTag& - , const PolygonMesh&, CGAL::Tag_false) - { - return const_type(); //boost::cgal_no_property::type - } - const_type get_const_pmap_impl(const PropertyTag& p - , const PolygonMesh& pmesh, CGAL::Tag_true) - { - return get(p, pmesh); - } -}; - template class GetVertexPointMap { @@ -138,22 +92,6 @@ public: > ::type type; }; -template -typename property_map_selector::type -get_property_map(const PropertyTag& p, PolygonMesh& pmesh) -{ - property_map_selector pms; - return pms.get_pmap(p, pmesh); -} - -template -typename property_map_selector::const_type -get_const_property_map(const PropertyTag& p, const PolygonMesh& pmesh) -{ - property_map_selector pms; - return pms.get_const_pmap(p, pmesh); -} - template class GetFaceIndexMap { diff --git a/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/Surface_Mesh_Segmentation.txt b/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/Surface_Mesh_Segmentation.txt index 506ec1a5dfb..3646fc34818 100644 --- a/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/Surface_Mesh_Segmentation.txt +++ b/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/Surface_Mesh_Segmentation.txt @@ -200,11 +200,17 @@ The main advantage is to decrease from log to constant the complexity for access \cgalExample{Surface_mesh_segmentation/segmentation_with_facet_ids_example.cpp} + \subsection Surface_mesh_segmentationUsingapolyhedron Using a Surface_mesh When using a `Surface_mesh`, you can use the built-in property mechanism. \cgalExample{Surface_mesh_segmentation/segmentation_from_sdf_values_SM_example.cpp} +\subsection Surface_mesh_segmentationIndependantmeshpersegment Independant TriangleMesh per Segment + It is possible to consider each segment as an independant triangle mesh, like in the following example, where the area of each segment is computed. + +\cgalExample{Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp} +
\section Performances Performances diff --git a/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/examples.txt b/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/examples.txt index 20ebc1fe599..4dca4c1a63a 100644 --- a/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/examples.txt +++ b/Surface_mesh_segmentation/doc/Surface_mesh_segmentation/examples.txt @@ -3,3 +3,4 @@ /// \example Surface_mesh_segmentation/segmentation_from_sdf_values_SM_example.cpp /// \example Surface_mesh_segmentation/segmentation_via_sdf_values_example.cpp /// \example Surface_mesh_segmentation/segmentation_with_facet_ids_example.cpp +/// \example Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp diff --git a/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/CMakeLists.txt b/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/CMakeLists.txt index 95d98601c9b..581a03e756b 100644 --- a/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/CMakeLists.txt +++ b/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/CMakeLists.txt @@ -64,8 +64,11 @@ create_single_source_cgal_program( "segmentation_from_sdf_values_example.cpp" ) create_single_source_cgal_program( "segmentation_via_sdf_values_example.cpp" ) create_single_source_cgal_program( "segmentation_with_facet_ids_example.cpp" ) + create_single_source_cgal_program( "segmentation_from_sdf_values_SM_example.cpp") +create_single_source_cgal_program( "extract_segmentation_into_mesh_example.cpp") + if(OpenMesh_FOUND) create_single_source_cgal_program( "segmentation_from_sdf_values_OpenMesh_example.cpp" ) target_link_libraries( segmentation_from_sdf_values_OpenMesh_example ${OPENMESH_LIBRARIES} ) diff --git a/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp b/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp new file mode 100644 index 00000000000..c226c867b5a --- /dev/null +++ b/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef CGAL::Surface_mesh SM; +typedef boost::graph_traits::face_descriptor face_descriptor; + +int main(int argc, char** argv ) +{ + SM mesh; + if (argc==2){ + std::ifstream input(argv[1]); + input >> mesh; + } else { + std::ifstream cactus("data/cactus.off"); + cactus >> mesh; + } + typedef SM::Property_map Facet_double_map; + Facet_double_map sdf_property_map; + + sdf_property_map = mesh.add_property_map("f:sdf").first; + + CGAL::sdf_values(mesh, sdf_property_map); + + // create a property-map for segment-ids + typedef SM::Property_map Facet_int_map; + Facet_int_map segment_property_map = mesh.add_property_map("f:sid").first;; + + // segment the mesh using default parameters for number of levels, and smoothing lambda + // Any other scalar values can be used instead of using SDF values computed using the CGAL function + std::size_t number_of_segments = CGAL::segmentation_from_sdf_values(mesh, sdf_property_map, segment_property_map); + + typedef CGAL::Face_filtered_graph Filtered_graph; + //print area of each segment and then put it in a Mesh and print it in an OFF file + Filtered_graph segment_mesh(mesh, 0, segment_property_map); + for(std::size_t id = 0; id < number_of_segments; ++id) + { + if(id > 0) + segment_mesh.set_selected_faces(id, segment_property_map); + std::cout << "Segment "<