// 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_Connected_components_graph_H #define CGAL_BOOST_GRAPH_Connected_components_graph_H #include #include #include #include #include #include #include #include #include #include namespace CGAL { /*! \ingroup PkgBGLHelper The class `Connected_components_graph` wraps a graph into another graph in such a way that only the specified connected components are seen from the outside. For example, calling `vertices(graph)` will return an iterator range of all but only the vertices that belong to the connected components whose ids in the `FaceComponentMap` are contained in the given set. \attention The functions `%num_vertices()`, `%num_edges()`, `%num_halfedges()`, `%num_faces()`, are forwarded from the underlying graph, which means that `num_vertices(graph)` is different from `std::distance(vertices(graph).first,vertices(graph).second)` Property maps can be wrapped with `Connected_components_graph_property_map`. \tparam Graph must be a model of a `FaceListGraph` and `HalfedgeListGraph`. \tparam FaceComponentMap a model of `WritablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and `graph_traits::faces_size_type` as value type. \cgalModels `FaceListGraph` \cgalModels `HalfedgeListGraph` */ template struct Connected_components_graph { typedef boost::graph_traits gt; typedef typename gt::vertex_descriptor vertex_descriptor; typedef typename gt::halfedge_descriptor halfedge_descriptor; typedef typename gt::edge_descriptor edge_descriptor; typedef typename gt::face_descriptor face_descriptor; typedef Connected_components_graph Self; /*! * \brief Creates a Connected_components_graph of the connected components of `graph` that are listed in `pids`. typedef unspecified_type Indices; * \param graph the graph containing the wanted patches. * \param fccmap the property_map that assigns a connected component to each face, with `boost::graph_traits::%face_descriptor` as key type and `graph_traits::faces_size_type` as value type. * \param ir the indices of the connected components of interest. */ template Connected_components_graph(const Graph& graph, FaceComponentMap fccmap, const IndexRange& ir) : _graph(graph), _property_map(fccmap), _patch_indices(ir.begin(),ir.end()) {} /*! * \brief Creates a Connected_components_graph of the connected component `id` of `graph`. * \param graph the graph containing the wanted patch. * \param fccmap the property_map that assigns a patch to each face * \param id the index of the connected component of interest. */ Connected_components_graph(const Graph& graph, FaceComponentMap fccmap, typename boost::property_traits::value_type pid) : _graph(graph), _property_map(fccmap) { _patch_indices.insert(pid); } ///returns the graph of the Connected_components_graph. const Graph& graph()const{ return _graph; } ///returns the property map of the Connected_components_graph. FaceComponentMap property_map()const{ return _property_map; } ///returns the unordered set of patch ids of the Connected_components_graph. #ifndef DOXYGEN_RUNNING const boost::unordered_set::value_type>& #else Index_range #endif indices()const{ return _patch_indices; } /// Replaces the current unordered set of patches by `pids` template void set_connected_components(const IndexRange& ir) { _patch_indices = boost::unordered_set::value_type>(ir.begin(), ir.end());} void set_connected_component(typename boost::property_traits::value_type pid) { _patch_indices.clear(); _patch_indices.insert(pid); } 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; }; private: const Graph& _graph; FaceComponentMap _property_map; boost::unordered_set::value_type> _patch_indices; }; } // namespace CGAL namespace boost { template struct graph_traits< CGAL::Connected_components_graph > { typedef CGAL::Connected_components_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 BGTG::vertices_size_type vertices_size_type; typedef typename BGTG::edges_size_type edges_size_type; typedef typename BGTG::halfedges_size_type halfedges_size_type; typedef typename BGTG::faces_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::Connected_components_graph > : public graph_traits< CGAL::Connected_components_graph > {}; } // namespace boost namespace CGAL { template bool in_CC(const typename boost::graph_traits< Connected_components_graph >::face_descriptor f, const Connected_components_graph & w) { return w.indices().find(boost::get(w.property_map(), f)) != w.indices().end(); } template bool in_CC(const typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { return in_CC(face(h, w.graph()), w) || in_CC(face(opposite(h, w.graph()), w.graph()), w); } template bool in_CC(const typename boost::graph_traits< Connected_components_graph >::edge_descriptor e, const Connected_components_graph & w) { return in_CC(halfedge(e, w.graph()), w); } template bool in_CC(const typename boost::graph_traits< Connected_components_graph >::vertex_descriptor v, const Connected_components_graph & w) { typename boost::graph_traits >::halfedge_descriptor h = halfedge(v, w.graph()); typename boost::graph_traits >::halfedge_descriptor hcirc = h; do { if(in_CC(face(hcirc, w.graph()), w)) return true; hcirc = opposite(next(hcirc, w.graph()), w.graph()); }while(hcirc != h); return false; } template typename boost::graph_traits::vertices_size_type num_vertices(const Connected_components_graph& w) { return num_vertices(w.graph()); } template typename boost::graph_traits::edges_size_type num_edges(const Connected_components_graph& w) { return num_edges(w.graph()); } template typename boost::graph_traits::degree_size_type degree(typename boost::graph_traits >::vertex_descriptor v, const Connected_components_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 Connected_components_graph& w) { CGAL_assertion(in_CC(v, w)); return 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 Connected_components_graph& w) { CGAL_assertion(in_CC(v, w)); return 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 Connected_components_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 Connected_components_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 Connected_components_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 Connected_components_graph & w) { typedef typename boost::graph_traits >::vertex_iterator vertex_iterator; typedef typename boost::graph_traits::vertex_iterator g_vertex_iterator; typename Connected_components_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 Connected_components_graph & w) { typedef typename boost::graph_traits >::edge_iterator edge_iterator; typedef typename boost::graph_traits::edge_iterator g_edge_iterator; typename Connected_components_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 Connected_components_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 Connected_components_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 Connected_components_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 Connected_components_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< Connected_components_graph >::edge_descriptor edge(typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { CGAL_assertion(CGAL::in_CC(h, w)); return edge(h, w.graph()); } template typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor halfedge(typename boost::graph_traits< Connected_components_graph >::edge_descriptor e, const Connected_components_graph & w) { CGAL_assertion(CGAL::in_CC(e, w)); return halfedge(e, w.graph()); } template typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor halfedge(typename boost::graph_traits< Connected_components_graph >::vertex_descriptor v, const Connected_components_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::Connected_components_graph >::null_halfedge(); } template std::pair >::halfedge_descriptor, bool> halfedge(typename boost::graph_traits< Connected_components_graph >::vertex_descriptor u, typename boost::graph_traits< Connected_components_graph >::vertex_descriptor v, const Connected_components_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< Connected_components_graph >::halfedge_descriptor opposite(typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { CGAL_assertion(in_CC(h, w) ); return opposite(h, w.graph()); } template typename boost::graph_traits< Connected_components_graph >::vertex_descriptor source(typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { CGAL_assertion(in_CC(h, w) ); return source(h, w.graph()); } template typename boost::graph_traits< Connected_components_graph >::vertex_descriptor target(typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { CGAL_assertion(in_CC(h, w) ); return target(h, w.graph()); } template typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor next(typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { CGAL_assertion(in_CC(h, w)); if(in_CC(face(h, w.graph()), w)) return next(h, w.graph()); //act as a border typename boost::graph_traits< Connected_components_graph >::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::Connected_components_graph >::null_halfedge(); } template typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor prev(typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { CGAL_assertion(in_CC(h, w)); if(in_CC(face(h, w.graph()), w)) return prev(h, w.graph()); //act as a border typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor hcirc = h; do { if(in_CC(hcirc, w)) { return hcirc; } hcirc = opposite(prev(hcirc,w.graph()), w.graph()); }while(hcirc != h); return boost::graph_traits< CGAL::Connected_components_graph >::null_halfedge(); } // // HalfedgeListGraph // template std::pair >::halfedge_iterator, typename boost::graph_traits >::halfedge_iterator> halfedges(const Connected_components_graph & w) { typedef typename boost::graph_traits >::halfedge_iterator halfedge_iterator; typedef typename boost::graph_traits::halfedge_iterator g_halfedge_iterator; typename Connected_components_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 boost::graph_traits::halfedges_size_type num_halfedges(const Connected_components_graph & w) { return num_halfedges(w.graph()); } // FaceGraph template typename boost::graph_traits< Connected_components_graph >::face_descriptor face(typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor h, const Connected_components_graph & w) { CGAL_assertion(CGAL::in_CC(h, w)); if(in_CC(face(h,w.graph()), w)) return face(h,w.graph()); else return boost::graph_traits< CGAL::Connected_components_graph >::null_face(); } template typename boost::graph_traits< Connected_components_graph >::halfedge_descriptor halfedge(typename boost::graph_traits< Connected_components_graph >::face_descriptor f, const Connected_components_graph & w) { CGAL_assertion(CGAL::in_CC(f, w)); return halfedge(f,w.graph()); } template Iterator_range >::face_iterator> faces(const Connected_components_graph & w) { typedef typename boost::graph_traits >::face_iterator face_iterator; typedef typename boost::graph_traits::face_iterator g_face_iterator; typename Connected_components_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 boost::graph_traits::vertices_size_type num_faces(const Connected_components_graph & w) { return num_faces(w.graph()); } template bool in_CC(const Connected_components_graph & w, bool verbose = false) { return in_CC(w.graph(),verbose); } template typename boost::property_map::type get(PropertyTag ptag, const Connected_components_graph& w) { return get(ptag, w.graph()); } template typename boost::property_traits::type>::value_type get(PropertyTag ptag, const Connected_components_graph& w, const typename boost::property_traits::type>::key_type& k) { return get(ptag, w.graph(), k); } template void put(PropertyTag ptag, const Connected_components_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 {}; }// namespace boost #endif // CGAL_BOOST_GRAPH_Connected_components_graph_H