Commit a5e72d7b authored by Mike Kremer's avatar Mike Kremer

Implemented efficient garbage_collection() function.

git-svn-id: http://www.openvolumemesh.org/svnrepo/OpenVolumeMesh/trunk@198 66977474-1d4b-4f09-8fe9-267525286df2
parent 65d0be26
......@@ -65,52 +65,158 @@ StatusAttrib::~StatusAttrib() {
}
//========================================================================================
void StatusAttrib::mark_higher_dim_entities() {
// Edges
if(kernel_.has_vertex_bottom_up_incidences()) {
for(VertexIter v_it = kernel_.vertices_begin(); v_it != kernel_.vertices_end(); ++v_it) {
if(v_status_[v_it->idx()].deleted()) {
for(VertexOHalfEdgeIter voh_it = kernel_.voh_iter(*v_it);
voh_it.valid(); ++voh_it) {
e_status_[kernel_.edge_handle(*voh_it).idx()].set_deleted(true);
}
}
}
} else {
for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end(); ++e_it) {
if(v_status_[kernel_.edge(*e_it).from_vertex().idx()].deleted() ||
v_status_[kernel_.edge(*e_it).to_vertex().idx()].deleted()) {
e_status_[e_it->idx()].set_deleted(true);
}
}
}
// Faces
if(kernel_.has_edge_bottom_up_incidences()) {
for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end(); ++e_it) {
if(e_status_[e_it->idx()].deleted()) {
for(HalfEdgeHalfFaceIter hehf_it = kernel_.hehf_iter(kernel_.halfedge_handle(*e_it, 0));
hehf_it.valid(); ++hehf_it) {
f_status_[kernel_.face_handle(*hehf_it).idx()].set_deleted(true);
}
}
}
} else {
for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end(); ++f_it) {
const std::vector<HalfEdgeHandle>& hes = kernel_.face(*f_it).halfedges();
for(std::vector<HalfEdgeHandle>::const_iterator he_it = hes.begin(),
he_end = hes.end(); he_it != he_end; ++he_it) {
if(e_status_[kernel_.edge_handle(*he_it)].deleted()) {
f_status_[*f_it].set_deleted(true);
break;
}
}
}
}
// Cells
if(kernel_.has_face_bottom_up_incidences()) {
for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end(); ++f_it) {
if(f_status_[f_it->idx()].deleted()) {
CellHandle c0 = kernel_.incident_cell(kernel_.halfface_handle(*f_it, 0));
CellHandle c1 = kernel_.incident_cell(kernel_.halfface_handle(*f_it, 1));
if(c0.is_valid()) {
c_status_[c0].set_deleted(true);
}
if(c1.is_valid()) {
c_status_[c1].set_deleted(true);
}
}
}
} else {
for(CellIter c_it = kernel_.cells_begin(); c_it != kernel_.cells_end(); ++c_it) {
const std::vector<HalfFaceHandle>& hfs = kernel_.cell(*c_it).halffaces();
for(std::vector<HalfFaceHandle>::const_iterator hf_it = hfs.begin(),
hf_end = hfs.end(); hf_it != hf_end; ++hf_it) {
if(f_status_[kernel_.face_handle(*hf_it)].deleted()) {
c_status_[*c_it].set_deleted(true);
break;
}
}
}
}
}
//========================================================================================
void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
/*
* This is not a real garbage collection in its conventional
* sense. What happens in this routine are the following steps:
*
* 1. Delete all entities marked as deleted from bottom to top.
* 2. Preserve manifoldness (optionally) by deleting all
* isolated entities in a top-down fashion afterwards.
* 1. If an entity of dimension n is marked to be deleted,
* also mark all incident entities of dimension n + 1
* for deletion. Do this in a bottom-up fashion.
* 2. Then delete all entities in top-down manner, so that
* no invalid incident higher-dimensional entity is generated.
* 3. If desired, search for all isolated entities and mark
* them deleted in a top-down manner.
* 4. Delete all entities marked deleted in step 4 in order
* to prevent manifoldness.
*/
for(VertexIter v_it = kernel_.vertices_begin(); v_it != kernel_.vertices_end();) {
// Mark all higher-dimensional entities incident to
// entities marked as deleted from bottom to top
mark_higher_dim_entities();
if(!v_status_[v_it->idx()].deleted()) {
++v_it;
} else {
v_it = kernel_.delete_vertex(*v_it);
}
std::vector<int> vertexIndexMap(kernel_.n_vertices(), -1);
int curIdx = 0;
// Turn off bottom-up incidences
bool v_bu = kernel_.has_vertex_bottom_up_incidences();
bool e_bu = kernel_.has_edge_bottom_up_incidences();
bool f_bu = kernel_.has_face_bottom_up_incidences();
kernel_.enable_bottom_up_incidences(false);
std::vector<bool> tags(kernel_.n_cells(), false);
std::vector<bool>::iterator tag_it = tags.begin();
for(CellIter c_it = kernel_.cells_begin(); c_it != kernel_.cells_end(); ++c_it, ++tag_it) {
*tag_it = c_status_[c_it->idx()].deleted();
}
kernel_.delete_multiple_cells(tags);
for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end();) {
tags.resize(kernel_.n_faces(), false);
tag_it = tags.begin();
if(!e_status_[e_it->idx()].deleted()) {
++e_it;
} else {
e_it = kernel_.delete_edge(*e_it);
}
for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end(); ++f_it, ++tag_it) {
*tag_it = f_status_[f_it->idx()].deleted();
}
kernel_.delete_multiple_faces(tags);
for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end();) {
tags.resize(kernel_.n_edges(), false);
tag_it = tags.begin();
if(!f_status_[f_it->idx()].deleted()) {
++f_it;
} else {
f_it = kernel_.delete_face(*f_it);
}
for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end(); ++e_it, ++tag_it) {
*tag_it = e_status_[e_it->idx()].deleted();
}
kernel_.delete_multiple_edges(tags);
for(CellIter c_it = kernel_.cells_begin(); c_it != kernel_.cells_end();) {
tags.resize(kernel_.n_vertices(), false);
tag_it = tags.begin();
if(!c_status_[c_it->idx()].deleted()) {
++c_it;
} else {
c_it = kernel_.delete_cell(*c_it);
}
for(VertexIter v_it = kernel_.vertices_begin(); v_it != kernel_.vertices_end(); ++v_it, ++tag_it) {
*tag_it = v_status_[v_it->idx()].deleted();
}
kernel_.delete_multiple_vertices(tags);
// Todo: Resize props
if(v_bu) kernel_.enable_vertex_bottom_up_incidences(true);
if(e_bu) kernel_.enable_edge_bottom_up_incidences(true);
if(f_bu) kernel_.enable_face_bottom_up_incidences(true);
// Step 6
if(_preserveManifoldness) {
......@@ -118,7 +224,7 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
// Go over all faces and find those
// that are not incident to any cell
for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end();) {
for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end(); ++f_it) {
// Get half-faces
HalfFaceHandle hf0 = kernel_.halfface_handle(*f_it, 0);
......@@ -128,50 +234,66 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
if(kernel_.incident_cell(hf0) == TopologyKernel::InvalidCellHandle &&
kernel_.incident_cell(hf1) == TopologyKernel::InvalidCellHandle) {
f_it = kernel_.delete_face(*f_it);
} else {
++f_it;
f_status_[f_it->idx()].set_deleted(true);
}
}
// Go over all edges and find those
// whose half-edges are not incident to any half-face
for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end();) {
for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end(); ++e_it) {
// Get half-edges
HalfEdgeHandle he0 = kernel_.halfedge_handle(*e_it, 0);
HalfEdgeHandle he1 = kernel_.halfedge_handle(*e_it, 1);
HalfEdgeHandle he = kernel_.halfedge_handle(*e_it, 0);
// If neither of the half-edges is incident to a half-face, delete edge
HalfEdgeHalfFaceIter he0hf_it = kernel_.hehf_iter(he0);
HalfEdgeHalfFaceIter he1hf_it = kernel_.hehf_iter(he1);
// If the half-edge isn't incident to a half-face, delete edge
HalfEdgeHalfFaceIter hehf_it = kernel_.hehf_iter(he);
if(!he0hf_it.valid() && !he1hf_it.valid()) {
if(!hehf_it.valid()) {
e_it = kernel_.delete_edge(*e_it);
e_status_[e_it->idx()].set_deleted(true);
} else {
++e_it;
bool validFace = false;
for(; hehf_it.valid(); ++hehf_it) {
if(!f_status_[kernel_.face_handle(*hehf_it).idx()].deleted()) {
validFace = true;
break;
}
}
if(!validFace) {
e_status_[e_it->idx()].set_deleted(true);
}
}
}
// Go over all vertices and find those
// that are not incident to any edge
for(VertexIter v_it = kernel_.vertices_begin(); v_it != kernel_.vertices_end();) {
for(VertexIter v_it = kernel_.vertices_begin(); v_it != kernel_.vertices_end(); ++v_it) {
// If neither of the half-edges is incident to a half-face, delete edge
VertexOHalfEdgeIter voh_it = kernel_.voh_iter(*v_it);
if(!voh_it.valid()) {
v_it = kernel_.delete_vertex(*v_it);
v_status_[v_it->idx()].set_deleted(true);
} else {
++v_it;
bool validEdge = false;
for(; voh_it.valid(); ++voh_it) {
if(!e_status_[kernel_.edge_handle(voh_it->idx())].deleted()) {
validEdge = true;
break;
}
}
if(!validEdge) {
v_status_[v_it->idx()].set_deleted(true);
}
}
}
// Recursive call
garbage_collection(false);
} else {
std::cerr << "Preservation of three-manifoldness in garbage_collection() "
<< "requires bottom-up incidences!" << std::endl;
......
......@@ -229,6 +229,8 @@ public:
private:
void mark_higher_dim_entities();
TopologyKernel& kernel_;
VertexPropertyT<OpenVolumeMeshStatus> v_status_;
......
......@@ -79,6 +79,8 @@ public:
protected:
virtual void delete_multiple_entries(const std::vector<bool>& _tags) = 0;
virtual void resize(unsigned int /*_size*/) = 0;
virtual void set_handle(const OpenVolumeMeshHandle& /*_handle*/) = 0;
......
......@@ -99,6 +99,34 @@ public:
return nV;
}
protected:
virtual void delete_multiple_vertices(const std::vector<bool>& _tag) {
assert(_tag.size() == TopologyKernelT::n_vertices());
std::vector<VecT> newVertices;
typename std::vector<VecT>::const_iterator v_it = vertices_.begin();
for(std::vector<bool>::const_iterator t_it = _tag.begin(),
t_end = _tag.end(); t_it != t_end; ++t_it, ++v_it) {
if(!(*t_it)) {
// Not marked as deleted
newVertices.push_back(*v_it);
}
}
// Swap vertices
vertices_.swap(newVertices);
TopologyKernelT::delete_multiple_vertices(_tag);
}
public:
virtual void clear(bool _clearProps = true) {
vertices_.clear();
......
......@@ -47,6 +47,7 @@
#include <limits>
#include <string>
#include <iostream>
#include <vector>
#include "OpenVolumeMeshHandle.hh"
......@@ -63,6 +64,9 @@ namespace OpenVolumeMesh {
class OpenVolumeMeshBaseProperty {
public:
friend class ResourceManager;
template <class PropT, class HandleT> friend class PropertyPtr;
/// Indicates an error when a size is returned by a member.
static const size_t UnknownSize;
......@@ -101,8 +105,6 @@ public:
/// Return a deep copy of self.
virtual OpenVolumeMeshBaseProperty* clone() const = 0;
public:
/// Return the name of the property
const std::string& name() const {
return name_;
......@@ -115,8 +117,6 @@ public:
// Function to deserialize a property
virtual void deserialize(std::istream& /*_istr*/) {}
public:
// I/O support
void set_persistent(bool _persistent) { persistent_ = _persistent; }
......@@ -145,6 +145,11 @@ public:
void set_handle(const OpenVolumeMeshHandle& _handle) { handle_.idx(_handle.idx()); }
protected:
/// Delete multiple entries in list
virtual void delete_multiple_entries(const std::vector<bool>&) = 0;
private:
std::string name_;
......
......@@ -70,6 +70,8 @@ template<class T>
class OpenVolumeMeshPropertyT: public OpenVolumeMeshBaseProperty {
public:
template <class PropT, class HandleT> friend class PropertyPtr;
typedef T Value;
typedef std::vector<T> vector_type;
typedef T value_type;
......@@ -200,6 +202,24 @@ public:
typename vector_type::iterator end() { return data_.end(); }
protected:
/// Delete multiple entries in list
virtual void delete_multiple_entries(const std::vector<bool>& _tags) {
assert(_tags.size() == data_.size());
vector_type new_data;
typename vector_type::iterator d_it = data_.begin();
std::vector<bool>::const_iterator t_it = _tags.begin();
std::vector<bool>::const_iterator t_end = _tags.end();
for(; t_it != t_end; ++t_it, ++d_it) {
if(!*t_it) {
new_data.push_back(*d_it);
}
}
data_.swap(new_data);
}
private:
vector_type data_;
......@@ -215,6 +235,8 @@ template<>
class OpenVolumeMeshPropertyT<bool> : public OpenVolumeMeshBaseProperty {
public:
template <class PropT, class HandleT> friend class PropertyPtr;
typedef std::vector<bool> vector_type;
typedef bool value_type;
typedef vector_type::reference reference;
......@@ -296,6 +318,24 @@ public:
vector_type::iterator end() { return data_.end(); }
protected:
/// Delete multiple entries in list
virtual void delete_multiple_entries(const std::vector<bool>& _tags) {
assert(_tags.size() == data_.size());
vector_type new_data;
typename vector_type::iterator d_it = data_.begin();
std::vector<bool>::const_iterator t_it = _tags.begin();
std::vector<bool>::const_iterator t_end = _tags.end();
for(; t_it != t_end; ++t_it, ++d_it) {
if(!*t_it) {
new_data.push_back(*d_it);
}
}
data_.swap(new_data);
}
private:
vector_type data_;
......@@ -311,6 +351,8 @@ template<>
class OpenVolumeMeshPropertyT<std::string> : public OpenVolumeMeshBaseProperty {
public:
template <class PropT, class HandleT> friend class PropertyPtr;
typedef std::string Value;
typedef std::vector<std::string> vector_type;
typedef std::string value_type;
......@@ -405,6 +447,24 @@ public:
vector_type::iterator end() { return data_.end(); }
protected:
/// Delete multiple entries in list
virtual void delete_multiple_entries(const std::vector<bool>& _tags) {
assert(_tags.size() == data_.size());
vector_type new_data;
typename vector_type::iterator d_it = data_.begin();
std::vector<bool>::const_iterator t_it = _tags.begin();
std::vector<bool>::const_iterator t_end = _tags.end();
for(; t_it != t_end; ++t_it, ++d_it) {
if(!*t_it) {
new_data.push_back(*d_it);
}
}
data_.swap(new_data);
}
private:
vector_type data_;
......
......@@ -106,6 +106,8 @@ public:
protected:
virtual void delete_multiple_entries(const std::vector<bool>& _tags);
virtual void resize(unsigned int _size);
virtual void set_handle(const OpenVolumeMeshHandle& _handle);
......
......@@ -93,4 +93,9 @@ OpenVolumeMeshHandle PropertyPtr<PropT,HandleT>::handle() const {
return ptr::shared_ptr<PropT>::get()->handle();
}
template <class PropT, class HandleT>
void PropertyPtr<PropT,HandleT>::delete_multiple_entries(const std::vector<bool>& _tags) {
ptr::shared_ptr<PropT>::get()->delete_multiple_entries(_tags);
}
} // Namespace OpenVolumeMesh
......@@ -141,4 +141,64 @@ void ResourceManager::release_property(MeshPropHandle _handle) {
remove_property(mesh_props_, _handle.idx());
}
void ResourceManager::delete_multiple_vertex_props(const std::vector<bool>& _tags) {
Properties::iterator vp_it = vertex_props_.begin();
Properties::iterator vp_end = vertex_props_.end();
for(; vp_it != vp_end; ++vp_it) {
(*vp_it)->delete_multiple_entries(_tags);
}
}
void ResourceManager::delete_multiple_edge_props(const std::vector<bool>& _tags) {
Properties::iterator ep_it = edge_props_.begin();
Properties::iterator ep_end = edge_props_.end();
for(; ep_it != ep_end; ++ep_it) {
(*ep_it)->delete_multiple_entries(_tags);
}
// Create tags vector for halfedges
std::vector<bool> hetags;
for(std::vector<bool>::const_iterator t_it = _tags.begin(),
t_end = _tags.end(); t_it != t_end; ++t_it) {
hetags.push_back(*t_it);
hetags.push_back(*t_it);
}
Properties::iterator hep_it = halfedge_props_.begin();
Properties::iterator hep_end = halfedge_props_.end();
for(; hep_it != hep_end; ++hep_it) {
(*hep_it)->delete_multiple_entries(hetags);
}
}
void ResourceManager::delete_multiple_face_props(const std::vector<bool>& _tags) {
Properties::iterator fp_it = face_props_.begin();
Properties::iterator fp_end = face_props_.end();
for(; fp_it != fp_end; ++fp_it) {
(*fp_it)->delete_multiple_entries(_tags);
}
// Create tags vector for halffaces
std::vector<bool> hftags;
for(std::vector<bool>::const_iterator t_it = _tags.begin(),
t_end = _tags.end(); t_it != t_end; ++t_it) {
hftags.push_back(*t_it);
hftags.push_back(*t_it);
}
Properties::iterator hfp_it = halfface_props_.begin();
Properties::iterator hfp_end = halfface_props_.end();
for(; hfp_it != hfp_end; ++hfp_it) {
(*hfp_it)->delete_multiple_entries(hftags);
}
}
void ResourceManager::delete_multiple_cell_props(const std::vector<bool>& _tags) {
Properties::iterator cp_it = cell_props_.begin();
Properties::iterator cp_end = cell_props_.end();
for(; cp_it != cp_end; ++cp_it) {
(*cp_it)->delete_multiple_entries(_tags);
}
}
} // Namespace OpenVolumeMesh
......@@ -218,6 +218,16 @@ public:
Properties::const_iterator mesh_props_end() const { return mesh_props_.end(); }
protected:
void delete_multiple_vertex_props(const std::vector<bool>& _tags);
void delete_multiple_edge_props(const std::vector<bool>& _tags);
void delete_multiple_face_props(const std::vector<bool>& _tags);
void delete_multiple_cell_props(const std::vector<bool>& _tags);
private:
template<class StdVecT>
......
......@@ -895,6 +895,136 @@ CellIter TopologyKernel::delete_cell(const CellHandle& _h) {
//========================================================================================
void TopologyKernel::delete_multiple_vertices(const std::vector<bool>& _tag) {
assert(_tag.size() == n_vertices_);
std::vector<int> newIndices(n_vertices(), -1);
int curIdx = 0;
std::vector<int>::iterator idx_it = newIndices.begin();
for(std::vector<bool>::const_iterator t_it = _tag.begin(),
t_end = _tag.end(); t_it != t_end; ++t_it, ++idx_it) {
if(!(*t_it)) {
// Not marked as deleted
*idx_it = curIdx;
++curIdx;
} else {
--n_vertices_;
}
}
// Delete properties accordingly
delete_multiple_vertex_props(_tag);
EdgeCorrector corrector(newIndices);
std::for_each(edges_.begin(), edges_.end(), corrector);
}
//========================================================================================