Merge pull request #604 from bo0ts/BGL-add_clear-pmoeller

Add BGL helper CGAL::clear
This commit is contained in:
Sébastien Loriot 2016-01-23 09:18:56 +01:00
commit 4c4b191209
10 changed files with 207 additions and 4 deletions

View File

@ -150,6 +150,8 @@ user might encounter.
- `CGAL::make_quad()`
- `CGAL::make_hexahedron()`
- `CGAL::clear()`
## Iterators ##
- `CGAL::Halfedge_around_source_iterator`
- `CGAL::Halfedge_around_target_iterator`

View File

@ -654,6 +654,25 @@ bool is_valid(OpenMesh::PolyMesh_ArrayKernelT<K>& sm, bool /* verbose */ = false
} // namespace OpenMesh
namespace CGAL {
// Overload CGAL::clear function. PolyMesh_ArrayKernel behaves
// differently from other meshes. Calling clear does not affect the
// number of vertices, edges, or faces in the mesh. To get actual
// numbers it is necessary to first collect garbage. We add an
// overlaod to get consistent behavior.
template<typename K>
void clear(OpenMesh::PolyMesh_ArrayKernelT<K>& sm)
{
sm.clear();
sm.garbage_collection(true, true, true);
CGAL_postcondition(num_edges(sm) == 0);
CGAL_postcondition(num_vertices(sm) == 0);
CGAL_postcondition(num_faces(sm) == 0);
}
}
#ifndef CGAL_NO_DEPRECATED_CODE
#include <CGAL/boost/graph/backward_compatibility_functions.h>

View File

@ -24,7 +24,7 @@
#include <boost/foreach.hpp>
#include <CGAL/boost/graph/iterator.h>
#include <CGAL/boost/graph/properties.h>
#include <CGAL/boost/graph/internal/Has_member_clear.h>
namespace CGAL {
@ -663,6 +663,60 @@ make_tetrahedron(const P& p0, const P& p1, const P& p2, const P& p3, Graph& g)
}
namespace internal {
template<typename FaceGraph>
inline
typename boost::enable_if<Has_member_clear<FaceGraph>, void>::type
clear_impl(FaceGraph& g)
{ g.clear(); }
template<typename FaceGraph>
inline
typename boost::disable_if<Has_member_clear<FaceGraph>, void>::type
clear_impl(FaceGraph& g)
{
typedef typename boost::graph_traits<FaceGraph>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
BOOST_FOREACH(edge_descriptor ed, edges(g)) {
remove_edge(ed, g);
}
BOOST_FOREACH(vertex_descriptor vd, vertices(g)) {
remove_vertex(vd, g);
}
BOOST_FOREACH(face_descriptor fd, faces(g)) {
remove_face(fd, g);
}
}
}
/**
* \ingroup PkgBGLHelperFct
*
* removes all vertices, faces and halfedges from a graph. Calls
* `remove_edge()`, `remove_vertex()`, and `remove_face()` for each
* edge, vertex or face.
*
* If the graph has a member function `clear`, it will be called
* instead.
*
* @tparam FaceGraph model of `MutableHalfedgeGraph` and `MutableFaceGraph`
*
* @param g the graph to clear
*
**/
template<typename FaceGraph>
void clear(FaceGraph& g)
{
internal::clear_impl(g);
CGAL_postcondition(num_edges(g) == 0);
CGAL_postcondition(num_vertices(g) == 0);
CGAL_postcondition(num_faces(g) == 0);
}
} // namespace CGAL
#endif // CGAL_BOOST_GRAPH_HELPERS_H

View File

@ -0,0 +1,26 @@
#ifndef CGAL_HAS_MEMBER_CLEAR_H
#define CGAL_HAS_MEMBER_CLEAR_H
namespace CGAL {
namespace internal {
template<class T>
class Has_member_clear
{
private:
template<class U, U>
class check {};
template<class C>
static char f(check<void(C::*)(void), &C::clear>*);
template<class C>
static int f(...);
public:
static const bool value = (sizeof(f<T>(0)) == sizeof(char));
};
} // internal
} // cgal
#endif /* CGAL_HAS_MEMBER_CLEAR_H */

View File

@ -67,16 +67,24 @@ create_single_source_cgal_program( "graph_concept_Polyhedron_3.cpp" )
create_single_source_cgal_program( "graph_concept_Triangulation_2.cpp" )
create_single_source_cgal_program( "test_clear.cpp" )
create_single_source_cgal_program( "test_graph_geometry.cpp" )
create_single_source_cgal_program( "test_helpers.cpp" )
create_single_source_cgal_program( "test_Has_member_clear.cpp" )
create_single_source_cgal_program( "test_cgal_bgl_named_params.cpp" )
if(OpenMesh_FOUND)
target_link_libraries( test_graph_geometry ${OPENMESH_LIBRARIES})
endif()
if(OpenMesh_FOUND)
target_link_libraries( test_clear ${OPENMESH_LIBRARIES})
endif()
create_single_source_cgal_program( "test_Euler_operations.cpp" )
if(OpenMesh_FOUND)
target_link_libraries( test_Euler_operations ${OPENMESH_LIBRARIES})

View File

@ -0,0 +1,27 @@
#include <CGAL/assertions.h>
#include <CGAL/boost/graph/internal/Has_member_clear.h>
struct with_clear {
void clear() {}
};
struct wo_clear { };
struct with_clear_but_args {
void clear(int) {}
};
struct with_clear_but_const {
void clear() const {}
};
int main()
{
using namespace CGAL::internal;
CGAL_static_assertion(Has_member_clear<with_clear>::value);
CGAL_static_assertion(!Has_member_clear<wo_clear>::value);
CGAL_static_assertion(!Has_member_clear<with_clear_but_args>::value);
CGAL_static_assertion(!Has_member_clear<with_clear_but_const>::value);
return 0;
}

View File

@ -0,0 +1,28 @@
#include "test_Prefix.h"
#include <CGAL/boost/graph/helpers.h>
template<typename Mesh>
void test() {
const std::string fname = "data/7_faces_triangle.off";
Mesh m;
if(!read_a_mesh(m, fname)) {
std::cout << "Error reading file: " << fname << std::endl;
}
CGAL::clear(m);
assert(num_vertices(m) == 0);
assert(num_faces(m) == 0);
assert(num_edges(m) == 0);
assert(is_valid(m));
}
int main()
{
test<SM>();
test<Polyhedron>();
#if defined(CGAL_USE_OPENMESH)
test<OMesh>();
#endif
return 0;
}

View File

@ -289,6 +289,10 @@ and <code>src/</code> directories).
<code>CGAL::expand_vertex_selection()</code>, <code>CGAL::reduce_vertex_selection()</code>
and <code>CGAL::select_incident_faces()</code>.
</li>
<li>
Add a helper function <code>CGAL::clear</code> which clears a
MutableFaceGraph efficiently and generically.
</li>
</ul>
<!-- Visualization -->

View File

@ -607,6 +607,14 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh
boost::vector_property_map<std::size_t, FaceIndexMap> face_cc(fim);
std::size_t num = connected_components(pmesh, face_cc, np);
// Even even we do not want to keep anything we need to first
// calculate the number of existing connected_components to get the
// correct return value.
if(nb_components_to_keep == 0) {
CGAL::clear(pmesh);
return num;
}
if((num == 1)|| (nb_components_to_keep > num) )
return 0;

View File

@ -53,9 +53,9 @@ void mesh_with_id(const char* argv1)
PMP::keep_largest_connected_components(sm,2);
std::ofstream ofile("blobby_2cc_id.off");
ofile << sm << std::endl;
ofile.close();
std::ofstream ofile("blobby_2cc_id.off");
ofile << sm << std::endl;
ofile.close();
}
void mesh_no_id(const char* argv1)
@ -150,11 +150,38 @@ void test_border_cases()
assert(num_vertices(copy)==0);
}
void keep_nothing(const char* argv1)
{
typedef boost::graph_traits<Mesh_with_id>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Mesh_with_id>::face_descriptor face_descriptor;
Mesh_with_id sm;
std::ifstream in(argv1);
if(!(in >> sm)) {
std::cerr << "ERROR reading file: " << argv1 << std::endl;
return;
}
int i=0;
BOOST_FOREACH(face_descriptor f, faces(sm)){
f->id() = i++;
}
i=0;
BOOST_FOREACH(vertex_descriptor v, vertices(sm)){
v->id() = i++;
}
PMP::keep_largest_connected_components(sm, 0);
assert(num_vertices(sm) == 0);
assert(num_edges(sm) == 0);
assert(num_faces(sm) == 0);
}
int main(int argc, char* argv[])
{
const char* filename = (argc > 1) ? argv[1] : "data/blobby_3cc.off";
mesh_with_id(filename);
mesh_no_id(filename);
test_border_cases();
keep_nothing(filename);
return 0;
}