Commit 1e3907d1 authored by Isaak Lim's avatar Isaak Lim

added garbage collection with handle tracking and corresponding unittests

git-svn-id: http://www.openvolumemesh.org/svnrepo/OpenVolumeMesh/trunk@239 66977474-1d4b-4f09-8fe9-267525286df2
parent b1f19282
......@@ -45,6 +45,8 @@
#include "../Core/TopologyKernel.hh"
#include "../Core/PropertyDefines.hh"
#include <map>
namespace OpenVolumeMesh {
StatusAttrib::StatusAttrib(TopologyKernel& _kernel) :
......@@ -150,6 +152,25 @@ void StatusAttrib::mark_higher_dim_entities() {
//========================================================================================
void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
std::vector<VertexHandle*> vh_empty;
std::vector<HalfEdgeHandle*> hh_empty;
std::vector<HalfFaceHandle*> hfh_empty;
std::vector<CellHandle*> ch_empty;
garbage_collection(vh_empty, hh_empty, hfh_empty, ch_empty, _preserveManifoldness);
}
//========================================================================================
template<typename std_API_Container_VHandlePointer,
typename std_API_Container_HHandlePointer,
typename std_API_Container_HFHandlePointer,
typename std_API_Container_CHandlePointer>
void StatusAttrib::garbage_collection(std_API_Container_VHandlePointer &vh_to_update,
std_API_Container_HHandlePointer &hh_to_update,
std_API_Container_HFHandlePointer &hfh_to_update,
std_API_Container_CHandlePointer &ch_to_update,
bool _preserveManifoldness) {
/*
* This is not a real garbage collection in its conventional
......@@ -166,6 +187,55 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
* to prevent manifoldness.
*/
// setup tracking so we can update the given handles
bool track_vh = !vh_to_update.empty();
bool track_hh = !hh_to_update.empty();
bool track_hfh = !hfh_to_update.empty();
bool track_ch = !ch_to_update.empty();
int offset_vh = 0;
int offset_hh = 0;
int offset_hfh = 0;
int offset_ch = 0;
std::map<int,int> vh_map;
std::map<int,int> hh_map;
std::map<int,int> hfh_map;
std::map<int,int> ch_map;
// initialise the maps
if (track_vh) {
typename std_API_Container_VHandlePointer::iterator it = vh_to_update.begin();
typename std_API_Container_VHandlePointer::iterator end = vh_to_update.end();
for (it; it != end; ++it) {
vh_map[(*it)->idx()] = (*it)->idx();
}
}
if (track_hh) {
typename std_API_Container_HHandlePointer::iterator it = hh_to_update.begin();
typename std_API_Container_HHandlePointer::iterator end = hh_to_update.end();
for (it; it != end; ++it) {
hh_map[(*it)->idx()] = (*it)->idx();
}
}
if (track_hfh) {
typename std_API_Container_HFHandlePointer::iterator it = hfh_to_update.begin();
typename std_API_Container_HFHandlePointer::iterator end = hfh_to_update.end();
for (it; it != end; ++it) {
hfh_map[(*it)->idx()] = (*it)->idx();
}
}
if (track_ch) {
typename std_API_Container_CHandlePointer::iterator it = ch_to_update.begin();
typename std_API_Container_CHandlePointer::iterator end = ch_to_update.end();
for (it; it != end; ++it) {
ch_map[(*it)->idx()] = (*it)->idx();
}
}
// Mark all higher-dimensional entities incident to
// entities marked as deleted from bottom to top
mark_higher_dim_entities();
......@@ -184,6 +254,17 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
for(CellIter c_it = kernel_.cells_begin(); c_it != kernel_.cells_end(); ++c_it, ++tag_it) {
*tag_it = c_status_[c_it->idx()].deleted();
if (track_ch) {
if (c_status_[c_it->idx()].deleted()) {
++offset_ch;
if (ch_map.find(c_it->idx()) != ch_map.end())
ch_map[c_it->idx()] = -1;
} else {
if (ch_map.find(c_it->idx()) != ch_map.end())
ch_map[c_it->idx()] = c_it->idx() - offset_ch;
}
}
}
kernel_.delete_multiple_cells(tags);
......@@ -192,6 +273,26 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end(); ++f_it, ++tag_it) {
*tag_it = f_status_[f_it->idx()].deleted();
if (track_hfh) {
int halfface_idx = f_it->idx() * 2;
if (f_status_[f_it->idx()].deleted()) {
offset_hfh += 2;
if (hfh_map.find(halfface_idx) != hfh_map.end()) {
hfh_map[halfface_idx] = -1;
}
if (hfh_map.find(halfface_idx + 1) != hfh_map.end()) {
hfh_map[halfface_idx + 1] = -1;
}
} else {
if (hfh_map.find(halfface_idx) != hfh_map.end()) {
hfh_map[halfface_idx] = halfface_idx - offset_hfh;
}
if (hfh_map.find(halfface_idx + 1) != hfh_map.end()) {
hfh_map[halfface_idx + 1] = halfface_idx + 1 - offset_hfh;
}
}
}
}
kernel_.delete_multiple_faces(tags);
......@@ -200,6 +301,26 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end(); ++e_it, ++tag_it) {
*tag_it = e_status_[e_it->idx()].deleted();
if (track_hh) {
int halfedge_idx = e_it->idx() * 2;
if (e_status_[e_it->idx()].deleted()) {
offset_hh += 2;
if (hh_map.find(halfedge_idx) != hh_map.end()) {
hh_map[halfedge_idx] = -1;
}
if (hh_map.find(halfedge_idx + 1) != hh_map.end()) {
hh_map[halfedge_idx + 1] = -1;
}
} else {
if (hh_map.find(halfedge_idx) != hh_map.end()) {
hh_map[halfedge_idx] = halfedge_idx - offset_hh;
}
if (hh_map.find(halfedge_idx + 1) != hh_map.end()) {
hh_map[halfedge_idx + 1] = halfedge_idx + 1 - offset_hh;
}
}
}
}
kernel_.delete_multiple_edges(tags);
......@@ -208,9 +329,56 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
for(VertexIter v_it = kernel_.vertices_begin(); v_it != kernel_.vertices_end(); ++v_it, ++tag_it) {
*tag_it = v_status_[v_it->idx()].deleted();
if (track_vh) {
if (v_status_[v_it->idx()].deleted()) {
if (vh_map.find(v_it->idx()) != vh_map.end()) {
++offset_vh;
vh_map[v_it->idx()] = -1;
}
} else {
if (vh_map.find(v_it->idx()) != vh_map.end()) {
vh_map[v_it->idx()] = v_it->idx() - offset_vh;
}
}
}
}
kernel_.delete_multiple_vertices(tags);
// update given handles
if (track_vh) {
typename std_API_Container_VHandlePointer::iterator it = vh_to_update.begin();
typename std_API_Container_VHandlePointer::iterator end = vh_to_update.end();
for (it; it != end; ++it) {
*(*it) = VertexHandle( vh_map[(*it)->idx()] );
}
}
if (track_hh) {
typename std_API_Container_HHandlePointer::iterator it = hh_to_update.begin();
typename std_API_Container_HHandlePointer::iterator end = hh_to_update.end();
for (it; it != end; ++it) {
*(*it) = HalfEdgeHandle( hh_map[(*it)->idx()] );
}
}
if (track_hfh) {
typename std_API_Container_HFHandlePointer::iterator it = hfh_to_update.begin();
typename std_API_Container_HFHandlePointer::iterator end = hfh_to_update.end();
for (it; it != end; ++it) {
*(*it) = HalfFaceHandle( hfh_map[(*it)->idx()] );
}
}
if (track_ch) {
typename std_API_Container_CHandlePointer::iterator it = ch_to_update.begin();
typename std_API_Container_CHandlePointer::iterator end = ch_to_update.end();
for (it; it != end; ++it) {
*(*it) = CellHandle( ch_map[(*it)->idx()] );
}
}
// Todo: Resize props
if(v_bu) kernel_.enable_vertex_bottom_up_incidences(true);
......@@ -291,7 +459,7 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
}
// Recursive call
garbage_collection(false);
garbage_collection(vh_to_update, hh_to_update, hfh_to_update, ch_to_update, false);
} else {
std::cerr << "Preservation of three-manifoldness in garbage_collection() "
......
......@@ -227,6 +227,41 @@ public:
*/
void garbage_collection(bool _preserveManifoldness = false);
/**
* \brief garbage collection with handle tracking
*
* This function deletes all entities that have been marked as deleted.
* It proceeds bottom-up, starting with the vertices. All higher
* dimensional entities that are incident to a deleted entity are
* automatically marked deleted, too. Once this first pass is through,
* one can additionally delete all resulting non-manifold configurations
* in a second pass (triggered by the parameter of this function).
* This step proceeds as follows: Delete all n-dimensional entities
* (starting with n = 2), that are not incident to at least one
* entity of dimension n + 1. Note that the second pass requires bottom-up
* incidences to be available. Compute them by calling update_incidences().
*
* \note Garbage collection invalidates all handles. If you need to keep track of
* a set of handles, you can pass them to this function. The handles that the
* given pointers point to are updated in place.
*
* @param vh_to_update Pointers to vertex handles that should get updated
* @param hh_to_update Pointers to halfedge handles that should get updated
* @param hfh_to_update Pointers to halfface handles that should get updated
* @param ch_to_update Pointers to cell handles that should get updated
* @param _preserveManifoldness Pass true if the mesh is required to stay three-manifold
*/
template<typename std_API_Container_VHandlePointer,
typename std_API_Container_HHandlePointer,
typename std_API_Container_HFHandlePointer,
typename std_API_Container_CHandlePointer>
void garbage_collection(
std_API_Container_VHandlePointer& vh_to_update,
std_API_Container_HHandlePointer& hh_to_update,
std_API_Container_HFHandlePointer& hfh_to_update,
std_API_Container_CHandlePointer& ch_to_update,
bool _preserveManifoldness = false);
private:
void mark_higher_dim_entities();
......
......@@ -1467,6 +1467,156 @@ TEST_F(HexahedralMeshBase, GarbageCollectionTestManifoldness5) {
EXPECT_EQ(0u, mesh_.n_vertices());
}
TEST_F(HexahedralMeshBase, GarbageCollectionTestTrackVertexHandles) {
generateHexahedralMesh(mesh_);
EXPECT_EQ(12u, mesh_.n_vertices());
EXPECT_EQ(20u, mesh_.n_edges());
EXPECT_EQ(11u, mesh_.n_faces());
EXPECT_EQ(2u, mesh_.n_cells());
StatusAttrib status(mesh_);
status[VertexHandle(0)].set_deleted(true);
std::vector<VertexHandle> vhs;
std::vector<VertexHandle*> track_vhs;
std::vector<HalfEdgeHandle*> hh_empty;
std::vector<HalfFaceHandle*> hfh_empty;
std::vector<CellHandle*> ch_empty;
OpenVolumeMesh::VertexIter v_it = mesh_.vertices_begin();
for (v_it; v_it != mesh_.vertices_end(); ++v_it)
vhs.push_back(*v_it);
for (std::vector<VertexHandle>::iterator it = vhs.begin(); it != vhs.end(); ++it)
track_vhs.push_back(&(*it));
status.garbage_collection(track_vhs, hh_empty, hfh_empty, ch_empty, false);
EXPECT_EQ(vhs[0], -1);
EXPECT_EQ(vhs[11], 10u);
EXPECT_EQ(1u, mesh_.n_cells());
EXPECT_EQ(11u, mesh_.n_vertices());
EXPECT_EQ(17u, mesh_.n_edges());
EXPECT_EQ(8u, mesh_.n_faces());
}
TEST_F(HexahedralMeshBase, GarbageCollectionTestTrackHalfedgeHandles) {
generateHexahedralMesh(mesh_);
StatusAttrib status(mesh_);
status[EdgeHandle(5)].set_deleted(true);
std::vector<HalfEdgeHandle> hhs;
std::vector<VertexHandle*> vh_empty;
std::vector<HalfEdgeHandle*> track_hh;
std::vector<HalfFaceHandle*> hfh_empty;
std::vector<CellHandle*> ch_empty;
OpenVolumeMesh::HalfEdgeIter hh_it = mesh_.halfedges_begin();
for (hh_it; hh_it != mesh_.halfedges_end(); ++hh_it)
hhs.push_back(*hh_it);
for (std::vector<HalfEdgeHandle>::iterator it = hhs.begin(); it != hhs.end(); ++it)
track_hh.push_back(&(*it));
status.garbage_collection(vh_empty, track_hh, hfh_empty, ch_empty, false);
EXPECT_EQ(hhs[9], 9u);
EXPECT_EQ(hhs[10], -1);
EXPECT_EQ(hhs[11], -1);
EXPECT_EQ(hhs[12], 10u);
EXPECT_EQ(hhs[39], 37u);
EXPECT_EQ(0u, mesh_.n_cells());
EXPECT_EQ(8u, mesh_.n_faces());
EXPECT_EQ(19u, mesh_.n_edges());
EXPECT_EQ(12u, mesh_.n_vertices());
status.garbage_collection(vh_empty, track_hh, hfh_empty, ch_empty, true);
for (std::vector<HalfEdgeHandle>::iterator it = hhs.begin(); it != hhs.end(); ++it)
EXPECT_EQ(it->idx(), -1);
EXPECT_EQ(0u, mesh_.n_cells());
EXPECT_EQ(0u, mesh_.n_faces());
EXPECT_EQ(0u, mesh_.n_edges());
EXPECT_EQ(0u, mesh_.n_vertices());
}
TEST_F(HexahedralMeshBase, GarbageCollectionTestTrackHalffaceHandles) {
generateHexahedralMesh(mesh_);
StatusAttrib status(mesh_);
status[FaceHandle(0)].set_deleted(true);
std::vector<HalfFaceHandle> hfhs;
std::vector<VertexHandle*> vh_empty;
std::vector<HalfEdgeHandle*> hh_empty;
std::vector<HalfFaceHandle*> track_hfh;
std::vector<CellHandle*> ch_empty;
OpenVolumeMesh::HalfFaceIter hfh_it = mesh_.halffaces_begin();
for (hfh_it; hfh_it != mesh_.halffaces_end(); ++hfh_it)
hfhs.push_back(*hfh_it);
for (std::vector<HalfFaceHandle>::iterator it = hfhs.begin(); it != hfhs.end(); ++it)
track_hfh.push_back(&(*it));
status.garbage_collection(vh_empty, hh_empty, track_hfh, ch_empty, true);
EXPECT_EQ(hfhs[0], -1);
EXPECT_EQ(hfhs[1], -1);
EXPECT_EQ(hfhs[2], 0u);
EXPECT_EQ(hfhs[3], 1u);
EXPECT_EQ(hfhs[21], 11u);
EXPECT_EQ(1u, mesh_.n_cells());
EXPECT_EQ(6u, mesh_.n_faces());
EXPECT_EQ(12u, mesh_.n_edges());
EXPECT_EQ(8u, mesh_.n_vertices());
}
TEST_F(HexahedralMeshBase, GarbageCollectionTestTrackCellHandles) {
generateHexahedralMesh(mesh_);
StatusAttrib status(mesh_);
status[CellHandle(0)].set_deleted(true);
std::vector<CellHandle> chs;
std::vector<VertexHandle*> vh_empty;
std::vector<HalfEdgeHandle*> hh_empty;
std::vector<HalfFaceHandle*> hfh_empty;
std::vector<CellHandle*> track_ch;
OpenVolumeMesh::CellIter c_it = mesh_.cells_begin();
for (c_it; c_it != mesh_.cells_end(); ++c_it)
chs.push_back(*c_it);
for (std::vector<CellHandle>::iterator it = chs.begin(); it != chs.end(); ++it)
track_ch.push_back(&(*it));
status.garbage_collection(vh_empty, hh_empty, hfh_empty, track_ch, true);
EXPECT_EQ(chs[0], -1);
EXPECT_EQ(chs[1], 0u);
EXPECT_EQ(1u, mesh_.n_cells());
EXPECT_EQ(6u, mesh_.n_faces());
EXPECT_EQ(12u, mesh_.n_edges());
EXPECT_EQ(8u, mesh_.n_vertices());
}
TEST_F(HexahedralMeshBase, GarbageCollectionTestProps1) {
generateHexahedralMesh(mesh_);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment