Merge pull request #1861 from maxGimeno/BGL_copy_face_graph_patch-GF

BGL: Connected_component_graph and copy_face_graph_patch
This commit is contained in:
Laurent Rineau 2017-06-22 16:06:14 +02:00 committed by GitHub
commit 4116d749d2
19 changed files with 1965 additions and 76 deletions

View File

@ -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}=<a href=\"http://www.boost.org/libs/graph/doc/\1.html\"><code>\1</code></a>"
ALIASES += "cgalNamedParamsBegin=<dl class=\"params\"><dt>Named Parameters</dt><dd> <table class=\"params\">"
# macros to be used inside the code
ALIASES += "cgalNamedParamsBegin=<dl class=\"params\"><dt>Named Parameters</dt><dd> <table class=\"params\">"
ALIASES += "cgalNamedParamsEnd=</table> </dd> </dl>"
ALIASES += "cgalParamBegin{1}=<tr><td class=\"paramname\">\1</td><td>"
ALIASES += "cgalParamEnd=</td></tr>"
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

View File

@ -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`

View File

@ -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
*/

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@
#include <CGAL/assertions.h>
#include <CGAL/boost/graph/properties.h>
#include <boost/graph/graph_traits.hpp>
#include <CGAL/boost/graph/iterator.h>
#include <boost/iterator/transform_iterator.hpp>
@ -325,8 +326,7 @@ edge(typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::ver
template <class Graph>
std::pair<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::vertex_iterator,
typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::vertex_iterator>
CGAL::Iterator_range<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::vertex_iterator>
vertices(const Graph_with_descriptor_with_graph<Graph> & w)
{
typename boost::graph_traits<Graph>::vertex_iterator b,e;
@ -336,8 +336,7 @@ vertices(const Graph_with_descriptor_with_graph<Graph> & w)
}
template <class Graph>
std::pair<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::edge_iterator,
typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::edge_iterator>
CGAL::Iterator_range<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::edge_iterator>
edges(const Graph_with_descriptor_with_graph<Graph> & w)
{
typename boost::graph_traits<Graph>::edge_iterator b,e;
@ -347,8 +346,7 @@ edges(const Graph_with_descriptor_with_graph<Graph> & w)
}
template <class Graph>
std::pair<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::out_edge_iterator,
typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::out_edge_iterator>
CGAL::Iterator_range<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::out_edge_iterator>
out_edges(typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::vertex_descriptor v,
const Graph_with_descriptor_with_graph<Graph> & w)
{
@ -360,8 +358,7 @@ out_edges(typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >
}
template <class Graph>
std::pair<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::in_edge_iterator,
typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::in_edge_iterator>
CGAL::Iterator_range<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::in_edge_iterator>
in_edges(typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::vertex_descriptor v,
const Graph_with_descriptor_with_graph<Graph> & w)
{
@ -630,8 +627,7 @@ prev(typename boost::graph_traits< Graph_with_descriptor_with_graph<Graph> >::ha
//
template <class Graph>
std::pair<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::halfedge_iterator,
typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::halfedge_iterator>
CGAL::Iterator_range<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::halfedge_iterator>
halfedges(const Graph_with_descriptor_with_graph<Graph> & w)
{
typename boost::graph_traits<Graph>::halfedge_iterator b,e;
@ -671,8 +667,7 @@ halfedge(typename boost::graph_traits< Graph_with_descriptor_with_graph<Graph> >
template <class Graph>
std::pair<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::face_iterator,
typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::face_iterator>
CGAL::Iterator_range<typename boost::graph_traits<Graph_with_descriptor_with_graph<Graph> >::face_iterator>
faces(const Graph_with_descriptor_with_graph<Graph> & w)
{
typename boost::graph_traits<Graph>::face_iterator b,e;

View File

@ -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<T,Tag,Base>
namespace CGAL {
namespace internal_np{
@ -162,6 +164,68 @@ using boost::visitor;
} // namespace parameters
//helper classes
template<typename PolygonMesh, typename PropertyTag>
class property_map_selector
{
public:
typedef typename boost::graph_has_property<PolygonMesh, PropertyTag>::type Has_internal_pmap;
typedef typename boost::mpl::if_c< Has_internal_pmap::value
, typename boost::property_map<PolygonMesh, PropertyTag>::type
, typename boost::cgal_no_property::type
>::type type;
typedef typename boost::mpl::if_c< Has_internal_pmap::value
, typename boost::property_map<PolygonMesh, PropertyTag>::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 PolygonMesh, typename PropertyTag>
typename property_map_selector<PolygonMesh, PropertyTag>::type
get_property_map(const PropertyTag& p, PolygonMesh& pmesh)
{
property_map_selector<PolygonMesh, PropertyTag> pms;
return pms.get_pmap(p, pmesh);
}
template<typename PolygonMesh, typename PropertyTag>
typename property_map_selector<PolygonMesh, PropertyTag>::const_type
get_const_property_map(const PropertyTag& p, const PolygonMesh& pmesh)
{
property_map_selector<PolygonMesh, PropertyTag> pms;
return pms.get_const_pmap(p, pmesh);
}
} //namespace CGAL
// partial specializations hate inheritance and we need to repeat

View File

@ -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()

View File

@ -0,0 +1,53 @@
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/Face_filtered_graph.h>
#include <CGAL/Simple_cartesian.h>
#include <boost/graph/graph_concepts.hpp>
#include <CGAL/boost/graph/graph_concepts.h>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> SM;
typedef CGAL::Face_filtered_graph<SM, SM::Property_map<boost::graph_traits<SM>::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<Adapter> >();
boost::function_requires< boost::VertexListGraphConcept<Adapter> >();
boost::function_requires< boost::EdgeListGraphConcept<Adapter> >();
boost::function_requires< boost::IncidenceGraphConcept<Adapter> >();
boost::function_requires< boost::AdjacencyMatrixConcept<Adapter> >();
boost::function_requires< boost::BidirectionalGraphConcept<Adapter> >();
boost::function_requires< CGAL::HalfedgeGraphConcept<Adapter> >();
boost::function_requires< CGAL::HalfedgeListGraphConcept<Adapter> >();
boost::function_requires< CGAL::FaceGraphConcept<Adapter> >();
boost::function_requires< CGAL::FaceListGraphConcept<Adapter> >();
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<Adapter>::null_vertex();
boost::graph_traits<Adapter>::null_face();
}
int main()
{
concept_check_adapter();
return 0;
}

View File

@ -0,0 +1,466 @@
#include <CGAL/boost/graph/Face_filtered_graph.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/boost/graph/copy_face_graph.h>
#include "test_Prefix.h"
#include <boost/numeric/conversion/cast.hpp>
#include <boost/foreach.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <CGAL/use.h>
#include <fstream>
typedef boost::unordered_set<std::size_t> id_map;
template <typename Graph>
void test_halfedge_around_vertex_iterator(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
boost::unordered_map<g_face_descriptor, std::size_t> 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<Adapter >::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 <typename Graph>
void test_halfedge_around_face_iterator(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<typename Graph>
void test_edge_iterators(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<edges_size_type>(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<id_map::iterator, bool> r = ids.insert(get(boost::edge_index, g, e));
// unique?
assert(r.second);
++count;
}
assert(count == num_edges(fg));
}
template<typename Graph>
void test_vertex_iterators(Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<id_map::iterator, bool> r = ids.insert(get(boost::vertex_index, g, *vb));
assert(r.second);
++count;
}
assert(count == num_vertices(fg));
}
template<typename Graph>
void test_out_edges(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<id_map::iterator, bool> r =
v_ids.insert(get(boost::vertex_index, g, target(*oeb, fg)));
assert(r.second);
}
}
}
template<typename Graph>
void test_in_edges(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<id_map::iterator, bool> r =
v_ids.insert(get(boost::vertex_index, g, source(*ieb, fg)));
assert(r.second);
}
}
}
template<typename Graph>
void test_in_out_edges(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<vertex_descriptor> in, out;
in_edge_iterator ieb, iee;
for(boost::tie(ieb, iee) = in_edges(*vb, fg); ieb != iee; ++ieb) {
std::pair<id_map::iterator, bool> 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<id_map::iterator, bool> 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<typename Graph>
void test_edge_find(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<edge_descriptor, bool> 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<typename Graph>
void test_faces(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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<typename Graph>
void test_read(const Graph& g)
{
typedef typename boost::graph_traits<Graph>::face_descriptor g_face_descriptor;
typedef CGAL::Face_filtered_graph<Graph> Adapter;
CGAL_GRAPH_TRAITS_MEMBERS(Adapter);
std::map<g_face_descriptor, std::size_t> 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 <typename Graph>
void
test(const std::vector<Graph>& 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<class Mesh, typename VertexPointPMap>
struct Constraint : public boost::put_get_helper<bool,Constraint<Mesh, VertexPointPMap> >
{
typedef typename boost::graph_traits<Mesh>::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<class Mesh, class FCCMAP, class Adapter>
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> SM_Adapter;
typedef SM::Property_map<boost::graph_traits<SM>::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<boost::graph_traits<SM>::face_descriptor, std::size_t>("f:CC").first;
SM::Property_map<boost::graph_traits<SM>::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<SM, SM::Property_map<boost::graph_traits<SM>::vertex_descriptor,
SM::Point> >(*sm, positions)));
boost::unordered_set<long unsigned int> pids;
pids.insert(0);
pids.insert(2);
SM_Adapter sm_adapter(*sm, pids, fccmap);
test_mesh<SM,SM_FCCMap, SM_Adapter>(sm_adapter);
typedef boost::graph_traits<Polyhedron> PolyTraits;
typedef boost::property_map<Polyhedron, boost::vertex_point_t>::type VPMap;
typedef PolyTraits::face_descriptor poly_face_descriptor;
typedef boost::associative_property_map< std::map<poly_face_descriptor,
PolyTraits::faces_size_type> > FCMap;
typedef boost::property_map<Polyhedron, CGAL::face_external_index_t>::type FIMap;
typedef boost::property_map<Polyhedron, CGAL::vertex_external_index_t>::type VIMap;
typedef boost::property_map<Polyhedron, CGAL::halfedge_external_index_t>::type HIMap;
typedef CGAL::Face_filtered_graph<Polyhedron, FIMap, VIMap, HIMap> 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<poly_face_descriptor,
PolyTraits::faces_size_type> 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<Polyhedron, VPMap >(*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<Polyhedron, FCMap, Poly_Adapter>(poly_adapter);
}

View File

@ -178,6 +178,14 @@ and <code>src/</code> directories).
<!-- Interpolation -->
<!-- Kinetic Data Structures -->
<!-- Support Library -->
<h3>CGAL and the Boost Graph Library (BGL)</h3>
<ul>
<li>
Add class <code>CGAL::Face_filtered_graph</code> that
wraps an existing graph and hide all simplices that are not
in the selected connected components.
</li>
</ul>
<!-- Visualization -->
<!-- end of the div for 4.10 -->

View File

@ -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.

View File

@ -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

View File

@ -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")

View File

@ -0,0 +1,63 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/boost/graph/Face_filtered_graph.h>
#include <boost/property_map/property_map.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <fstream>
#include <map>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Mesh;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef boost::graph_traits<Mesh>::faces_size_type faces_size_type;
typedef Mesh::Property_map<face_descriptor, faces_size_type> FCCmap;
typedef CGAL::Face_filtered_graph<Mesh> 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<face_descriptor, faces_size_type>("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<Filtered_graph>::face_descriptor f, faces(ffg)){
std::cout << f << std::endl;
}
if(num>1){
std::vector<faces_size_type> 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;
}

View File

@ -42,52 +42,6 @@ public:
typedef typename boost::property_traits<PMap>::value_type type;
};
template<typename PolygonMesh, typename PropertyTag>
class property_map_selector
{
public:
typedef typename boost::graph_has_property<PolygonMesh, PropertyTag>::type Has_internal_pmap;
typedef typename boost::mpl::if_c< Has_internal_pmap::value
, typename boost::property_map<PolygonMesh, PropertyTag>::type
, typename boost::cgal_no_property::type
>::type type;
typedef typename boost::mpl::if_c< Has_internal_pmap::value
, typename boost::property_map<PolygonMesh, PropertyTag>::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 PolygonMesh, typename NamedParameters>
class GetVertexPointMap
{
@ -138,22 +92,6 @@ public:
> ::type type;
};
template<typename PolygonMesh, typename PropertyTag>
typename property_map_selector<PolygonMesh, PropertyTag>::type
get_property_map(const PropertyTag& p, PolygonMesh& pmesh)
{
property_map_selector<PolygonMesh, PropertyTag> pms;
return pms.get_pmap(p, pmesh);
}
template<typename PolygonMesh, typename PropertyTag>
typename property_map_selector<PolygonMesh, PropertyTag>::const_type
get_const_property_map(const PropertyTag& p, const PolygonMesh& pmesh)
{
property_map_selector<PolygonMesh, PropertyTag> pms;
return pms.get_const_pmap(p, pmesh);
}
template<typename PolygonMesh, typename NamedParameters>
class GetFaceIndexMap
{

View File

@ -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}
<BR>
\section Performances Performances
<!-- \subsection SMSRuntime Runtime of the functions sdf_values() and segmentation_from_sdf_values() -->

View File

@ -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

View File

@ -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} )

View File

@ -0,0 +1,56 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/boost/graph/Face_filtered_graph.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/boost/graph/copy_face_graph.h>
#include <CGAL/mesh_segmentation.h>
#include <iostream>
#include <fstream>
#include <sstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Surface_mesh<Kernel::Point_3> SM;
typedef boost::graph_traits<SM>::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<face_descriptor,double> Facet_double_map;
Facet_double_map sdf_property_map;
sdf_property_map = mesh.add_property_map<face_descriptor,double>("f:sdf").first;
CGAL::sdf_values(mesh, sdf_property_map);
// create a property-map for segment-ids
typedef SM::Property_map<face_descriptor, std::size_t> Facet_int_map;
Facet_int_map segment_property_map = mesh.add_property_map<face_descriptor,std::size_t>("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<SM> 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 "<<id<<"'s area is : "<<CGAL::Polygon_mesh_processing::area(segment_mesh)<<std::endl;
SM out;
CGAL::copy_face_graph(segment_mesh, out);
std::ostringstream oss;
oss << "Segment_" << id<<".off";
std::ofstream os(oss.str().data());
os<<out;
}
}