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() { ...@@ -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) { void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
/* /*
* This is not a real garbage collection in its conventional * This is not a real garbage collection in its conventional
* sense. What happens in this routine are the following steps: * sense. What happens in this routine are the following steps:
* *
* 1. Delete all entities marked as deleted from bottom to top. * 1. If an entity of dimension n is marked to be deleted,
* 2. Preserve manifoldness (optionally) by deleting all * also mark all incident entities of dimension n + 1
* isolated entities in a top-down fashion afterwards. * 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()) { std::vector<int> vertexIndexMap(kernel_.n_vertices(), -1);
++v_it; int curIdx = 0;
} else {
v_it = kernel_.delete_vertex(*v_it); // 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()) { for(FaceIter f_it = kernel_.faces_begin(); f_it != kernel_.faces_end(); ++f_it, ++tag_it) {
++e_it; *tag_it = f_status_[f_it->idx()].deleted();
} else {
e_it = kernel_.delete_edge(*e_it);
}
} }
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()) { for(EdgeIter e_it = kernel_.edges_begin(); e_it != kernel_.edges_end(); ++e_it, ++tag_it) {
++f_it; *tag_it = e_status_[e_it->idx()].deleted();
} else {
f_it = kernel_.delete_face(*f_it);
}
} }
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()) { for(VertexIter v_it = kernel_.vertices_begin(); v_it != kernel_.vertices_end(); ++v_it, ++tag_it) {
++c_it; *tag_it = v_status_[v_it->idx()].deleted();
} else {
c_it = kernel_.delete_cell(*c_it);
}
} }
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 // Step 6
if(_preserveManifoldness) { if(_preserveManifoldness) {
...@@ -118,7 +224,7 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) { ...@@ -118,7 +224,7 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
// Go over all faces and find those // Go over all faces and find those
// that are not incident to any cell // 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 // Get half-faces
HalfFaceHandle hf0 = kernel_.halfface_handle(*f_it, 0); HalfFaceHandle hf0 = kernel_.halfface_handle(*f_it, 0);
...@@ -128,50 +234,66 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) { ...@@ -128,50 +234,66 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
if(kernel_.incident_cell(hf0) == TopologyKernel::InvalidCellHandle && if(kernel_.incident_cell(hf0) == TopologyKernel::InvalidCellHandle &&
kernel_.incident_cell(hf1) == TopologyKernel::InvalidCellHandle) { kernel_.incident_cell(hf1) == TopologyKernel::InvalidCellHandle) {
f_it = kernel_.delete_face(*f_it); f_status_[f_it->idx()].set_deleted(true);
} else {
++f_it;
} }
} }
// Go over all edges and find those // Go over all edges and find those
// whose half-edges are not incident to any half-face // 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 // Get half-edges
HalfEdgeHandle he0 = kernel_.halfedge_handle(*e_it, 0); HalfEdgeHandle he = kernel_.halfedge_handle(*e_it, 0);
HalfEdgeHandle he1 = kernel_.halfedge_handle(*e_it, 1);
// If neither of the half-edges is incident to a half-face, delete edge // If the half-edge isn't incident to a half-face, delete edge
HalfEdgeHalfFaceIter he0hf_it = kernel_.hehf_iter(he0); HalfEdgeHalfFaceIter hehf_it = kernel_.hehf_iter(he);
HalfEdgeHalfFaceIter he1hf_it = kernel_.hehf_iter(he1);
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 { } 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 // Go over all vertices and find those
// that are not incident to any edge // 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 // If neither of the half-edges is incident to a half-face, delete edge
VertexOHalfEdgeIter voh_it = kernel_.voh_iter(*v_it); VertexOHalfEdgeIter voh_it = kernel_.voh_iter(*v_it);
if(!voh_it.valid()) { if(!voh_it.valid()) {
v_it = kernel_.delete_vertex(*v_it); v_status_[v_it->idx()].set_deleted(true);
} else { } 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 { } else {
std::cerr << "Preservation of three-manifoldness in garbage_collection() " std::cerr << "Preservation of three-manifoldness in garbage_collection() "
<< "requires bottom-up incidences!" << std::endl; << "requires bottom-up incidences!" << std::endl;
......
...@@ -229,6 +229,8 @@ public: ...@@ -229,6 +229,8 @@ public:
private: private:
void mark_higher_dim_entities();
TopologyKernel& kernel_; TopologyKernel& kernel_;
VertexPropertyT<OpenVolumeMeshStatus> v_status_; VertexPropertyT<OpenVolumeMeshStatus> v_status_;
......
...@@ -79,6 +79,8 @@ public: ...@@ -79,6 +79,8 @@ public:
protected: protected:
virtual void delete_multiple_entries(const std::vector<bool>& _tags) = 0;
virtual void resize(unsigned int /*_size*/) = 0; virtual void resize(unsigned int /*_size*/) = 0;
virtual void set_handle(const OpenVolumeMeshHandle& /*_handle*/) = 0; virtual void set_handle(const OpenVolumeMeshHandle& /*_handle*/) = 0;
......
...@@ -99,6 +99,34 @@ public: ...@@ -99,6 +99,34 @@ public:
return nV; 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) { virtual void clear(bool _clearProps = true) {
vertices_.clear(); vertices_.clear();
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <limits> #include <limits>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <vector>
#include "OpenVolumeMeshHandle.hh" #include "OpenVolumeMeshHandle.hh"
...@@ -63,6 +64,9 @@ namespace OpenVolumeMesh { ...@@ -63,6 +64,9 @@ namespace OpenVolumeMesh {
class OpenVolumeMeshBaseProperty { class OpenVolumeMeshBaseProperty {
public: public:
friend class ResourceManager;
template <class PropT, class HandleT> friend class PropertyPtr;
/// Indicates an error when a size is returned by a member. /// Indicates an error when a size is returned by a member.
static const size_t UnknownSize; static const size_t UnknownSize;
...@@ -101,8 +105,6 @@ public: ...@@ -101,8 +105,6 @@ public:
/// Return a deep copy of self. /// Return a deep copy of self.
virtual OpenVolumeMeshBaseProperty* clone() const = 0; virtual OpenVolumeMeshBaseProperty* clone() const = 0;
public:
/// Return the name of the property /// Return the name of the property
const std::string& name() const { const std::string& name() const {
return name_; return name_;
...@@ -115,8 +117,6 @@ public: ...@@ -115,8 +117,6 @@ public:
// Function to deserialize a property // Function to deserialize a property
virtual void deserialize(std::istream& /*_istr*/) {} virtual void deserialize(std::istream& /*_istr*/) {}
public:
// I/O support // I/O support
void set_persistent(bool _persistent) { persistent_ = _persistent; } void set_persistent(bool _persistent) { persistent_ = _persistent; }
...@@ -145,6 +145,11 @@ public: ...@@ -145,6 +145,11 @@ public:
void set_handle(const OpenVolumeMeshHandle& _handle) { handle_.idx(_handle.idx()); } 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: private:
std::string name_; std::string name_;
......
...@@ -70,6 +70,8 @@ template<class T> ...@@ -70,6 +70,8 @@ template<class T>
class OpenVolumeMeshPropertyT: public OpenVolumeMeshBaseProperty { class OpenVolumeMeshPropertyT: public OpenVolumeMeshBaseProperty {
public: public:
template <class PropT, class HandleT> friend class PropertyPtr;
typedef T Value; typedef T Value;
typedef std::vector<T> vector_type; typedef std::vector<T> vector_type;
typedef T value_type; typedef T value_type;
...@@ -200,6 +202,24 @@ public: ...@@ -200,6 +202,24 @@ public:
typename vector_type::iterator end() { return data_.end(); } 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: private:
vector_type data_; vector_type data_;
...@@ -215,6 +235,8 @@ template<> ...@@ -215,6 +235,8 @@ template<>
class OpenVolumeMeshPropertyT<bool> : public OpenVolumeMeshBaseProperty { class OpenVolumeMeshPropertyT<bool> : public OpenVolumeMeshBaseProperty {
public: public:
template <class PropT, class HandleT> friend class PropertyPtr;
typedef std::vector<bool> vector_type; typedef std::vector<bool> vector_type;
typedef bool value_type; typedef bool value_type;
typedef vector_type::reference reference; typedef vector_type::reference reference;
...@@ -296,6 +318,24 @@ public: ...@@ -296,6 +318,24 @@ public:
vector_type::iterator end() { return data_.end(); } 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: private:
vector_type data_; vector_type data_;
...@@ -311,6 +351,8 @@ template<> ...@@ -311,6 +351,8 @@ template<>
class OpenVolumeMeshPropertyT<std::string> : public OpenVolumeMeshBaseProperty { class OpenVolumeMeshPropertyT<std::string> : public OpenVolumeMeshBaseProperty {
public: public:
template <class PropT, class HandleT> friend class PropertyPtr;
typedef std::string Value; typedef std::string Value;
typedef std::vector<std::string> vector_type; typedef std::vector<std::string> vector_type;
typedef std::string value_type; typedef std::string value_type;
...@@ -405,6 +447,24 @@ public: ...@@ -405,6 +447,24 @@ public:
vector_type::iterator end() { return data_.end(); } 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: private:
vector_type data_; vector_type data_;
......
...@@ -106,6 +106,8 @@ public: ...@@ -106,6 +106,8 @@ public:
protected: