mirror of https://github.com/CGAL/cgal
Merge pull request #604 from bo0ts/BGL-add_clear-pmoeller
Add BGL helper CGAL::clear
This commit is contained in:
commit
4c4b191209
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 -->
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue