cgal/BGL/test/BGL/test_Properties.cpp

462 lines
16 KiB
C++

#include "test_Prefix.h"
#include <CGAL/boost/graph/Euler_operations.h>
#include <unordered_set>
// #define CGAL_TEST_PROPERTIES_DEBUG
namespace CGAL {
template <typename Key, typename Value, typename Container>
struct Non_mutable_property_map
{
typedef Key key_type;
typedef Value value_type;
typedef const value_type& reference;
typedef boost::readable_property_map_tag category;
Non_mutable_property_map(const Container& c) : m_c(c) { }
friend reference get(const Non_mutable_property_map<Key, Value, Container>& pmap, const key_type& k)
{
return pmap.m_c.at(k);
}
private:
const Container& m_c;
};
template <typename Key, typename Value, typename Container>
struct RW_property_map
{
typedef Key key_type;
typedef Value value_type;
typedef value_type& reference;
typedef boost::read_write_property_map_tag category;
RW_property_map(Container& c) : m_c(c) { }
friend void put(RW_property_map<Key, Value, Container>& pmap, const key_type& k, const value_type& val)
{
pmap.m_c[k] = val;
}
friend reference get(const RW_property_map<Key, Value, Container>& pmap, const key_type& k)
{
return pmap.m_c[k];
}
private:
Container& m_c;
};
} // namespace CGAL
template<typename Graph,
typename ForwardRange,
typename IndexPropertyMap>
void test_uniqueness(const Graph&,
const ForwardRange& range,
IndexPropertyMap index_map)
{
#ifdef CGAL_TEST_PROPERTIES_DEBUG
std::cout << std::endl
<< "Checking the uniqueness of the property map of type: "
<< typeid(IndexPropertyMap).name() << std::endl;
std::cout << "Element type: " << typeid(typename boost::range_value<ForwardRange>::type).name() << std::endl;
#endif
typename boost::range_iterator<ForwardRange>::type
begin = std::begin(range),
begin2 = std::begin(range),
end = std::end(range);
typedef std::unordered_set<typename IndexPropertyMap::value_type> id_map;
typedef std::pair<typename id_map::iterator, bool> resultp;
id_map m;
while(begin != end)
{
resultp r = m.insert(get(index_map, *begin));
#ifdef CGAL_TEST_PROPERTIES_DEBUG
std::cout << "id: " << get(index_map, *begin) << std::endl;
#endif
++begin;
assert(r.second); // already seen that id
}
assert(std::distance(begin2, end) == static_cast<std::ptrdiff_t>(m.size()));
}
template<typename Graph,
typename NamedParameters>
void test_vertex_index_map_uniqueness(const Graph& g,
const NamedParameters& np)
{
typedef typename CGAL::GetInitializedVertexIndexMap<Graph, NamedParameters>::type VIM;
typedef typename CGAL::GetInitializedVertexIndexMap<Graph, NamedParameters>::const_type CVIM;
// in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not
static_assert(std::is_same<VIM, CVIM>::value, "VIM, CVIM must be the same type");
VIM ivim = CGAL::get_initialized_vertex_index_map(g, np);
return test_uniqueness(g, vertices(g), ivim);
}
template<typename Graph,
typename NamedParameters>
void test_halfedge_index_map_uniqueness(const Graph& g,
const NamedParameters& np)
{
typedef typename CGAL::GetInitializedHalfedgeIndexMap<Graph, NamedParameters>::type HIM;
typedef typename CGAL::GetInitializedHalfedgeIndexMap<Graph, NamedParameters>::const_type CHIM;
// in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not
static_assert(std::is_same<HIM, CHIM>::value, "HIM, CHIM must be the same type");
HIM ihim = CGAL::get_initialized_halfedge_index_map(g, np);
return test_uniqueness(g, halfedges(g), ihim);
}
template<typename Graph,
typename NamedParameters>
void test_edge_index_map_uniqueness(const Graph& g,
const NamedParameters& np)
{
typedef typename CGAL::GetInitializedEdgeIndexMap<Graph, NamedParameters>::type EIM;
typedef typename CGAL::GetInitializedEdgeIndexMap<Graph, NamedParameters>::const_type CEIM;
// in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not
static_assert(std::is_same<EIM, CEIM>::value, "EIM, CEIM must be the same type");
EIM ieim = CGAL::get_initialized_edge_index_map(g, np);
return test_uniqueness(g, edges(g), ieim);
}
template<typename Graph,
typename NamedParameters>
void test_face_index_map_uniqueness(const Graph& g,
const NamedParameters& np)
{
typedef typename CGAL::GetInitializedFaceIndexMap<Graph, NamedParameters>::type FIM;
typedef typename CGAL::GetInitializedFaceIndexMap<Graph, NamedParameters>::const_type CFIM;
// in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not
static_assert(std::is_same<FIM, CFIM>::value, "FIM, CFIM must be the same type");
FIM ifim = CGAL::get_initialized_face_index_map(g, np);
return test_uniqueness(g, faces(g), ifim);
}
////////////////////////////////////////// const ///////////////////////////////////////////////////
template <typename Graph>
void test_internal_index_maps_const(const Graph& g)
{
test_uniqueness(g, vertices(g), get(boost::vertex_index, g));
test_uniqueness(g, halfedges(g), get(boost::halfedge_index, g));
test_uniqueness(g, edges(g) , get(boost::edge_index, g));
test_uniqueness(g, faces(g), get(boost::face_index, g));
}
template <typename Graph>
void test_initialized_index_maps_const(const Graph& g)
{
typedef typename CGAL::GetInitializedVertexIndexMap<Graph>::const_type VIM;
VIM ivim = CGAL::get_initialized_vertex_index_map(g);
test_uniqueness(g, vertices(g), ivim);
typedef typename CGAL::GetInitializedHalfedgeIndexMap<Graph>::const_type HIM;
HIM ihim = CGAL::get_initialized_halfedge_index_map(g);
test_uniqueness(g, halfedges(g), ihim);
typedef typename CGAL::GetInitializedEdgeIndexMap<Graph>::const_type EIM;
EIM ieim = CGAL::get_initialized_edge_index_map(g);
test_uniqueness(g, edges(g), ieim);
typedef typename CGAL::GetInitializedFaceIndexMap<Graph>::const_type FIM;
FIM ifim = CGAL::get_initialized_face_index_map(g);
test_uniqueness(g, faces(g), ifim);
// Passing an index map via NP
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef std::map<vertex_descriptor, int> VertexIndexMap;
typedef boost::associative_property_map<VertexIndexMap> VertexIdPropertyMap; // lvalue_pmap
int vi = static_cast<int>(num_vertices(g));
VertexIndexMap vim;
VertexIdPropertyMap external_vertex_index_map(vim);
for(vertex_descriptor v : vertices(g))
put(external_vertex_index_map, v, --vi);
test_vertex_index_map_uniqueness(g, CGAL::parameters::vertex_index_map(external_vertex_index_map));
// Read-only pmap
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
typedef std::map<halfedge_descriptor, int> HalfedgeIndexMap;
typedef CGAL::Non_mutable_property_map<halfedge_descriptor, int,
HalfedgeIndexMap> HalfedgeIdPropertyMap;
int hi = 0;
HalfedgeIndexMap him;
HalfedgeIdPropertyMap external_halfedge_index_map(him);
// this should complain that the map is not writable (commented because it does assert)
// CGAL::BGL::internal::initialize_halfedge_index_map(external_halfedge_index_map, g);
// forced to initialize the underlying map
for(halfedge_descriptor h : halfedges(g))
him[h] = hi++;
test_halfedge_index_map_uniqueness(g, CGAL::parameters::halfedge_index_map(external_halfedge_index_map));
// Writable pmap
typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef std::unordered_map<edge_descriptor, int,
boost::hash<edge_descriptor>> EdgeIndexMap;
typedef CGAL::RW_property_map<edge_descriptor, int, EdgeIndexMap> EdgeIdPropertyMap;
EdgeIndexMap eim;
EdgeIdPropertyMap external_edge_index_map(eim);
CGAL::BGL::internal::initialize_edge_index_map(external_edge_index_map, g);
test_edge_index_map_uniqueness(g, CGAL::parameters::edge_index_map(external_edge_index_map));
// Just so face_index_map don't feel excluded
typedef typename boost::graph_traits<Graph>::face_descriptor face_descriptor;
typedef std::map<face_descriptor, int> FaceIndexMap;
typedef boost::const_associative_property_map<FaceIndexMap> FaceIdPropertyMap;
FaceIndexMap fim;
FaceIdPropertyMap external_face_index_map(fim);
// 'const_associative_pmap' has category 'lvalue_property_map_tag' but it's not writable
// so below should complain (commented because it does assert)
// CGAL::BGL::internal::initialize_face_index_map(external_face_index_map, g);
// gotta initialize the underlying map
int fi = 0;
for(face_descriptor f : faces(g))
fim[f] = fi++;
test_face_index_map_uniqueness(g, CGAL::parameters::face_index_map(external_face_index_map));
}
template <typename Graph>
void test_all_index_maps_const(const Graph& g)
{
#ifdef CGAL_TEST_PROPERTIES_DEBUG
std::cout << " ---------------------------- Const graph tests" << std::endl;
#endif
test_internal_index_maps_const(g);
test_initialized_index_maps_const(g);
}
///////////////////////////////////// non-const ////////////////////////////////////////////////////
template <typename Graph>
void test_internal_index_maps(Graph& g)
{
test_uniqueness(g, vertices(g), get(boost::vertex_index, g));
test_uniqueness(g, halfedges(g), get(boost::halfedge_index, g));
test_uniqueness(g, edges(g) , get(boost::edge_index, g));
test_uniqueness(g, faces(g), get(boost::face_index, g));
}
template <typename Graph>
void test_initialized_index_maps(Graph& g)
{
typedef typename CGAL::GetInitializedVertexIndexMap<Graph>::type VIM;
VIM ivim = CGAL::get_initialized_vertex_index_map(g);
test_uniqueness(g, vertices(g), ivim);
typedef typename CGAL::GetInitializedHalfedgeIndexMap<Graph>::type HIM;
HIM ihim = CGAL::get_initialized_halfedge_index_map(g);
test_uniqueness(g, halfedges(g), ihim);
typedef typename CGAL::GetInitializedEdgeIndexMap<Graph>::type EIM;
EIM ieim = CGAL::get_initialized_edge_index_map(g);
test_uniqueness(g, edges(g), ieim);
typedef typename CGAL::GetInitializedFaceIndexMap<Graph>::type FIM;
FIM ifim = CGAL::get_initialized_face_index_map(g);
test_uniqueness(g, faces(g), ifim);
// Passing an index map via NP
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef std::map<vertex_descriptor, int> VertexIndexMap;
typedef boost::associative_property_map<VertexIndexMap> VertexIdPropertyMap; // lvalue_pmap
int vi = static_cast<int>(num_vertices(g));
VertexIndexMap vim;
VertexIdPropertyMap external_vertex_index_map(vim);
for(vertex_descriptor v : vertices(g))
put(external_vertex_index_map, v, --vi);
test_vertex_index_map_uniqueness(g, CGAL::parameters::vertex_index_map(external_vertex_index_map));
// Read-only pmap
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
typedef std::map<halfedge_descriptor, int> HalfedgeIndexMap;
typedef CGAL::Non_mutable_property_map<halfedge_descriptor, int,
HalfedgeIndexMap> HalfedgeIdPropertyMap;
int hi = 0;
HalfedgeIndexMap him;
HalfedgeIdPropertyMap external_halfedge_index_map(him);
// this should complain that the map is not writable (commented because it does assert)
// CGAL::BGL::internal::initialize_halfedge_index_map(external_halfedge_index_map, g);
// forced to initialize the underlying map
for(halfedge_descriptor h : halfedges(g))
him[h] = hi++;
test_halfedge_index_map_uniqueness(g, CGAL::parameters::halfedge_index_map(external_halfedge_index_map));
// Writable pmap
typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef std::unordered_map<edge_descriptor, int, boost::hash<edge_descriptor>>
EdgeIndexMap;
typedef CGAL::RW_property_map<edge_descriptor, int, EdgeIndexMap> EdgeIdPropertyMap;
EdgeIndexMap eim;
EdgeIdPropertyMap external_edge_index_map(eim);
CGAL::BGL::internal::initialize_edge_index_map(external_edge_index_map, g);
test_edge_index_map_uniqueness(g, CGAL::parameters::edge_index_map(external_edge_index_map));
// Just so face_index_map don't feel excluded
typedef typename boost::graph_traits<Graph>::face_descriptor face_descriptor;
typedef std::map<face_descriptor, int> FaceIndexMap;
typedef boost::const_associative_property_map<FaceIndexMap> FaceIdPropertyMap;
FaceIndexMap fim;
FaceIdPropertyMap external_face_index_map(fim);
// 'const_associative_pmap' has category 'lvalue_property_map_tag' but it's not writable
// so below should complain (commented because it does assert)
// CGAL::BGL::internal::initialize_face_index_map(external_face_index_map, g);
// gotta initialize the underlying map
int fi = 0;
for(face_descriptor f : faces(g))
fim[f] = fi++;
test_face_index_map_uniqueness(g, CGAL::parameters::face_index_map(external_face_index_map));
}
template <typename Graph>
void test_all_index_maps(Graph& g)
{
#ifdef CGAL_TEST_PROPERTIES_DEBUG
std::cout << " ---------------------------- Non-const graph tests" << std::endl;
#endif
test_internal_index_maps(g);
test_initialized_index_maps(g);
}
template <typename Graph>
void test_graph(Graph& g)
{
#ifdef CGAL_TEST_PROPERTIES_DEBUG
std::cout << "Graph has:" << std::endl
<< "\t" << num_vertices(g) << " vertices (actual: " << vertices(g).size() << ")" << std::endl
<< "\t" << num_halfedges(g) << " halfedges (actual: " << halfedges(g).size() << ")" << std::endl
<< "\t" << num_edges(g) << " edges (actual: " << edges(g).size() << ")" << std::endl
<< "\t" << num_faces(g) << " faces (actual: " << faces(g).size() << ")" << std::endl;
#endif
test_all_index_maps(g);
test_all_index_maps_const(g);
}
void test_poly(Polyhedron& g)
{
test_graph(g);
test_uniqueness(g, edges(g) , get(boost::edge_external_index, g));
test_uniqueness(g, vertices(g), get(boost::vertex_external_index, g));
test_uniqueness(g, faces(g), get(boost::face_external_index, g));
test_uniqueness(g, halfedges(g), get(boost::halfedge_external_index, g));
}
int main(int, char**)
{
std::cout << "testing Polyhedron\n";
std::vector<Polyhedron> polys = poly_data();
for(Polyhedron& p : polys)
test_poly(p);
std::cout << "testing Linear_cell_complex\n";
std::vector<LCC> lccs = lcc_data();
for(LCC& p : lccs)
test_graph(p);
std::cout << "testing Surface_mesh\n";
std::vector<SM> sms = sm_data();
for(SM& sm : sms)
{
assert(!CGAL::is_empty(sm));
// Add some garbage
CGAL::Euler::join_vertex(*(halfedges(sm).begin()), sm);
test_graph(sm);
// Test on a mesh with no internal index maps
Seam_edge_pmap seam_edges = sm.add_property_map<SM::Edge_index, bool>("e:on_seam", false).first;
Seam_vertex_pmap seam_vertices = sm.add_property_map<SM::Vertex_index, bool>("v:on_seam", false).first;
Seam_mesh seam_mesh(sm, seam_edges, seam_vertices);
test_initialized_index_maps(seam_mesh);
test_initialized_index_maps_const(seam_mesh);
}
#if defined(CGAL_USE_OPENMESH)
std::cout << "testing OpenMesh\n";
std::vector<OMesh> omeshs = omesh_data();
for(OMesh& p : omeshs)
test_graph(p);
#endif
std::cout << "testing Triangulations\n";
Triangulation_2 t2 = t2_data();
test_graph(t2);
Delaunay_triangulation_2 dt2 = dt2_data();
test_graph(dt2);
Regular_triangulation_2 rt2 = rt2_data();
test_graph(rt2);
Constrained_triangulation_2 ct2 = ct2_data();
test_graph(ct2);
Constrained_Delaunay_triangulation_2 cdt2 = cdt2_data();
test_graph(cdt2);
CDT_P2 cdtp2 = cdtp2_data();
test_graph(cdtp2);
Triangulation_hierarchy_2 t2h = t2h_data();
test_graph(t2h);
// no dynamic pmaps in triangulations (yet)
// Triangulation_no_id_2 t2_no_id = t2_no_id_data();
// test_initialized_index_maps(t2_no_id);
// test_initialized_index_maps_const(t2_no_id);
std::cout << "Done!" << std::endl;
return EXIT_SUCCESS;
}