Commit d2d3162c authored by Mike Kremer's avatar Mike Kremer
Browse files

Refactored bottom-up adjacencies:

Bottom-up adjacencies are now computed automatically on-the-fly when adding/deleting
entities. For this only a minimal subset of affected entities is recomputed.

Refactored delete functions and normal attrib class.

git-svn-id: http://www.openvolumemesh.org/svnrepo/OpenVolumeMesh/trunk@169 66977474-1d4b-4f09-8fe9-267525286df2
parent 81588995
......@@ -66,7 +66,7 @@ NormalAttrib<GeomKernelT>::~NormalAttrib() {
template <class GeomKernelT>
void NormalAttrib<GeomKernelT>::update_vertex_normals() {
if(!kernel_.has_bottom_up_adjacencies()) {
if(!kernel_.has_face_bottom_up_adjacencies()) {
std::cerr << "Error: update_vertex_normals() needs bottom-up adjacencies!" << std::endl;
return;
}
......@@ -82,6 +82,11 @@ void NormalAttrib<GeomKernelT>::update_vertex_normals() {
template <class GeomKernelT>
void NormalAttrib<GeomKernelT>::update_face_normals() {
if(!kernel_.has_face_bottom_up_adjacencies()) {
std::cerr << "Error: update_normals() needs bottom-up adjacencies!" << std::endl;
return;
}
for(FaceIter f_it = kernel_.f_iter(); f_it.valid(); ++f_it) {
// Assume the face is planar, so just take the
// first two edges
......@@ -134,7 +139,7 @@ void NormalAttrib<GeomKernelT>::compute_face_normal(const FaceHandle& _fh) {
++he_it;
typename GeomKernelT::PointT p3 = kernel_.vertex(kernel_.halfedge(*he_it).to_vertex());
typename GeomKernelT::PointT n = (p3 - p2) % (p1 - p2);
typename GeomKernelT::PointT n = (p1 - p2) % (p3 - p2);
n.normalize();
f_normals_[_fh.idx()] = n;
......
......@@ -112,14 +112,9 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
}
}
// Step 5
if(kernel_.has_bottom_up_adjacencies()) {
kernel_.update_adjacencies();
}
// Step 6
if(_preserveManifoldness) {
if(kernel_.has_bottom_up_adjacencies()) {
if(kernel_.has_full_bottom_up_adjacencies()) {
// Go over all faces and find those
// that are not incident to any cell
......@@ -135,15 +130,11 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
f_it = kernel_.delete_face(*f_it);
kernel_.update_face_adjacencies();
} else {
++f_it;
}
}
kernel_.update_edge_adjacencies();
// 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();) {
......@@ -160,17 +151,11 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
e_it = kernel_.delete_edge(*e_it);
kernel_.update_edge_adjacencies();
} else {
++e_it;
}
}
// Vertex caches have to be re-computed because the face/half-face
// indices have changed since the last deletions
kernel_.update_vertex_adjacencies();
// 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();) {
......@@ -182,10 +167,8 @@ void StatusAttrib::garbage_collection(bool _preserveManifoldness) {
v_it = kernel_.delete_vertex(*v_it);
kernel_.update_vertex_adjacencies();
} else {
++v_it;
++v_it;
}
}
......
......@@ -72,11 +72,8 @@ public:
// Store vertex in list
vertices_.push_back(_p);
// Resize vertex props
KernelT::resize_vprops(vertices_.size());
// Get handle of recently created vertex
return VertexHandle(vertices_.size() - 1);
return KernelT::add_vertex();
}
/// Set the coordinates of point _vh
......
......@@ -59,7 +59,7 @@ VertexOHalfEdgeIter::VertexOHalfEdgeIter(const VertexHandle& _ref_h,
BaseIter(_mesh, _ref_h),
cur_index_(0) {
if(!_mesh->has_vertex_adjacencies()) {
if(!_mesh->has_vertex_bottom_up_adjacencies()) {
std::cerr << "This iterator needs bottom-up adjacencies!" << std::endl;
BaseIter::valid(false);
return;
......@@ -121,7 +121,7 @@ HalfEdgeHalfFaceIter::HalfEdgeHalfFaceIter(const HalfEdgeHandle& _ref_h,
BaseIter(_mesh, _ref_h),
cur_index_(0) {
if(!_mesh->has_edge_adjacencies()) {
if(!_mesh->has_edge_bottom_up_adjacencies()) {
std::cerr << "This iterator needs bottom-up adjacencies!" << std::endl;
BaseIter::valid(false);
return;
......@@ -182,7 +182,7 @@ VertexCellIter::VertexCellIter(const VertexHandle& _ref_h,
const TopologyKernel* _mesh) :
BaseIter(_mesh, _ref_h) {
if(!_mesh->has_bottom_up_adjacencies()) {
if(!_mesh->has_full_bottom_up_adjacencies()) {
std::cerr << "This iterator needs bottom-up adjacencies!" << std::endl;
BaseIter::valid(false);
return;
......@@ -250,7 +250,7 @@ HalfEdgeCellIter::HalfEdgeCellIter(const HalfEdgeHandle& _ref_h,
BaseIter(_mesh, _ref_h),
cur_index_(0) {
if(!_mesh->has_edge_adjacencies() || !_mesh->has_face_adjacencies()) {
if(!_mesh->has_edge_bottom_up_adjacencies() || !_mesh->has_face_bottom_up_adjacencies()) {
std::cerr << "This iterator needs bottom-up adjacencies!" << std::endl;
BaseIter::valid(false);
return;
......@@ -367,7 +367,7 @@ CellCellIter::CellCellIter(const CellHandle& _ref_h,
const TopologyKernel* _mesh) :
BaseIter(_mesh, _ref_h) {
if(!_mesh->has_face_adjacencies()) {
if(!_mesh->has_face_bottom_up_adjacencies()) {
std::cerr << "This iterator needs bottom-up adjacencies!" << std::endl;
BaseIter::valid(false);
return;
......@@ -469,16 +469,20 @@ HalfFaceVertexIter& HalfFaceVertexIter::operator++() {
BoundaryFaceIter::BoundaryFaceIter(const TopologyKernel* _mesh) :
BaseIter(_mesh, TopologyKernel::InvalidFaceHandle) {
BaseIter(_mesh, TopologyKernel::InvalidFaceHandle),
bf_it_(_mesh->faces_begin()) {
if(!_mesh->has_face_adjacencies()) {
if(!_mesh->has_face_bottom_up_adjacencies()) {
std::cerr << "This iterator needs bottom-up adjacencies!" << std::endl;
BaseIter::valid(false);
return;
}
bf_it_ = BaseIter::mesh()->boundary_faces_.begin();
BaseIter::valid(bf_it_ != BaseIter::mesh()->boundary_faces_.end());
while(bf_it_ != BaseIter::mesh()->faces_end() &&
!BaseIter::mesh()->is_boundary(*bf_it_)) {
++bf_it_;
}
BaseIter::valid(bf_it_ != BaseIter::mesh()->faces_end());
if(BaseIter::valid()) {
BaseIter::cur_handle(*bf_it_);
}
......@@ -487,8 +491,12 @@ BaseIter(_mesh, TopologyKernel::InvalidFaceHandle) {
BoundaryFaceIter& BoundaryFaceIter::operator--() {
--bf_it_;
if(bf_it_ >= BaseIter::mesh()->boundary_faces_.begin()) {
--bf_it_;
while(bf_it_ >= BaseIter::mesh()->faces_begin() &&
!BaseIter::mesh()->is_boundary(*bf_it_)) {
--bf_it_;
}
if(bf_it_ >= BaseIter::mesh()->faces_begin()) {
BaseIter::cur_handle(*bf_it_);
} else {
BaseIter::valid(false);
......@@ -500,7 +508,11 @@ BoundaryFaceIter& BoundaryFaceIter::operator--() {
BoundaryFaceIter& BoundaryFaceIter::operator++() {
++bf_it_;
if(bf_it_ != BaseIter::mesh()->boundary_faces_.end()) {
while(bf_it_ != BaseIter::mesh()->faces_end() &&
!BaseIter::mesh()->is_boundary(*bf_it_)) {
++bf_it_;
}
if(bf_it_ != BaseIter::mesh()->faces_end()) {
BaseIter::cur_handle(*bf_it_);
} else {
BaseIter::valid(false);
......
......@@ -567,62 +567,6 @@ private:
//===========================================================================
class BoundaryFaceIter : public BaseIterator<FaceHandle,FaceHandle> {
public:
typedef BaseIterator<
FaceHandle,
FaceHandle> BaseIter;
BoundaryFaceIter(const TopologyKernel* _mesh);
// Post increment/decrement operator
BoundaryFaceIter operator++(int) {
BoundaryFaceIter cpy = *this;
++(*this);
return cpy;
}
BoundaryFaceIter operator--(int) {
BoundaryFaceIter cpy = *this;
--(*this);
return cpy;
}
BoundaryFaceIter operator+(int _n) {
BoundaryFaceIter cpy = *this;
for(int i = 0; i < _n; ++i) {
++cpy;
}
return cpy;
}
BoundaryFaceIter operator-(int _n) {
BoundaryFaceIter cpy = *this;
for(int i = 0; i < _n; ++i) {
--cpy;
}
return cpy;
}
BoundaryFaceIter& operator+=(int _n) {
for(int i = 0; i < _n; ++i) {
++(*this);
}
return *this;
}
BoundaryFaceIter& operator-=(int _n) {
for(int i = 0; i < _n; ++i) {
--(*this);
}
return *this;
}
BoundaryFaceIter& operator++();
BoundaryFaceIter& operator--();
private:
std::vector<FaceHandle>::const_iterator bf_it_;
};
//===========================================================================
class VertexIter : public BaseIterator<
VertexHandle,
VertexHandle> {
......@@ -971,6 +915,62 @@ private:
//===========================================================================
class BoundaryFaceIter : public BaseIterator<FaceHandle,FaceHandle> {
public:
typedef BaseIterator<
FaceHandle,
FaceHandle> BaseIter;
BoundaryFaceIter(const TopologyKernel* _mesh);
// Post increment/decrement operator
BoundaryFaceIter operator++(int) {
BoundaryFaceIter cpy = *this;
++(*this);
return cpy;
}
BoundaryFaceIter operator--(int) {
BoundaryFaceIter cpy = *this;
--(*this);
return cpy;
}
BoundaryFaceIter operator+(int _n) {
BoundaryFaceIter cpy = *this;
for(int i = 0; i < _n; ++i) {
++cpy;
}
return cpy;
}
BoundaryFaceIter operator-(int _n) {
BoundaryFaceIter cpy = *this;
for(int i = 0; i < _n; ++i) {
--cpy;
}
return cpy;
}
BoundaryFaceIter& operator+=(int _n) {
for(int i = 0; i < _n; ++i) {
++(*this);
}
return *this;
}
BoundaryFaceIter& operator-=(int _n) {
for(int i = 0; i < _n; ++i) {
--(*this);
}
return *this;
}
BoundaryFaceIter& operator++();
BoundaryFaceIter& operator--();
private:
FaceIter bf_it_;
};
//===========================================================================
} // Namespace OpenVolumeMesh
#endif /* ITERATORS_HH_ */
......@@ -44,6 +44,9 @@
#define OPENVOLUMEMESHHANDLE_HH_
#include <iostream>
#include <vector>
#include <tr1/functional>
#include <algorithm>
namespace OpenVolumeMesh {
......@@ -90,6 +93,52 @@ class CellHandle : public OpenVolumeMeshHandle { public: CellHandle(int _idx
class HalfEdgeHandle : public OpenVolumeMeshHandle { public: HalfEdgeHandle(int _idx = -1) : OpenVolumeMeshHandle(_idx) {} };
class HalfFaceHandle : public OpenVolumeMeshHandle { public: HalfFaceHandle(int _idx = -1) : OpenVolumeMeshHandle(_idx) {} };
// Helper class that is used to decrease all handles
// exceeding a certain threshold
class VHandleCorrection {
public:
VHandleCorrection(VertexHandle _thld) : thld_(_thld) {}
void correctValue(VertexHandle& _h) {
if(_h > thld_) _h.idx(_h.idx() - 1);
}
private:
VertexHandle thld_;
};
class HEHandleCorrection {
public:
HEHandleCorrection(HalfEdgeHandle _thld) : thld_(_thld) {}
void correctVecValue(std::vector<HalfEdgeHandle>& _vec) {
std::for_each(_vec.begin(), _vec.end(), std::tr1::bind(&HEHandleCorrection::correctValue, this, std::tr1::placeholders::_1));
}
void correctValue(HalfEdgeHandle& _h) {
if(_h > thld_) _h.idx(_h.idx() - 2);
}
private:
HalfEdgeHandle thld_;
};
class HFHandleCorrection {
public:
HFHandleCorrection(HalfFaceHandle _thld) : thld_(_thld) {}
void correctVecValue(std::vector<HalfFaceHandle>& _vec) {
std::for_each(_vec.begin(), _vec.end(), std::tr1::bind(&HFHandleCorrection::correctValue, this, std::tr1::placeholders::_1));
}
void correctValue(HalfFaceHandle& _h) {
if(_h > thld_) _h.idx(_h.idx() - 2);
}
private:
HalfFaceHandle thld_;
};
class CHandleCorrection {
public:
CHandleCorrection(CellHandle _thld) : thld_(_thld) {}
void correctValue(CellHandle& _h) {
if(_h > thld_) _h.idx(_h.idx() - 1);
}
private:
CellHandle thld_;
};
std::ostream& operator<<(std::ostream& _ostr, const OpenVolumeMeshHandle& _handle);
std::istream& operator>>(std::istream& _istr, OpenVolumeMeshHandle& _handle);
......
This diff is collapsed.
......@@ -217,12 +217,7 @@ public:
virtual unsigned int n_cells() const { return cells_.size(); }
/// Add abstract vertex
virtual VertexHandle add_vertex() {
++n_vertices_;
// Return 0-indexed handle
return VertexHandle((int)(n_vertices_ - 1));
}
virtual VertexHandle add_vertex();
//=======================================================================
......@@ -283,7 +278,7 @@ public:
/// Get valence of vertex (number of incident edges)
inline unsigned int valence(const VertexHandle& _vh) const {
if(!has_vertex_adjacencies_) {
if(!v_bottom_up_) {
std::cerr << "Could not get vertex valence: No bottom-up adjacencies for vertices available!" << std::endl;
return 0u;
}
......@@ -293,7 +288,7 @@ public:
/// Get valence of edge (number of incident faces)
inline unsigned int valence(const EdgeHandle& _eh) const {
if(!has_edge_adjacencies_) {
if(!e_bottom_up_) {
std::cerr << "Could not get edge valence: No bottom-up adjacencies for edges available!" << std::endl;
return 0u;
}
......@@ -315,155 +310,21 @@ public:
return cell(_ch).halffaces().size();
}
/**
* \brief Delete vertex from mesh
*
* After performing this operation, all vertices
* following vertex _h in the array will be accessible
* through their old handle decreased by one.
* This function directly fixes the vertex links
* in all edges. This invalidates all bottom-up
* adjacencies. See class StatusAttrib that
* provides a proper garbage collection.
*
* @param _h A vertex handle
*/
virtual VertexIter delete_vertex(const VertexHandle& _h) {
assert(_h.idx() < (int)n_vertices());
--n_vertices_;
for(EdgeIter e_it = edges_begin(); e_it != edges_end();) {
if(edge(*e_it).to_vertex() == _h || edge(*e_it).from_vertex() == _h) {
e_it = delete_edge(*e_it);
} else {
if(edge(*e_it).to_vertex().idx() > _h.idx()) {
edge(*e_it).set_to_vertex(VertexHandle(edge(*e_it).to_vertex() - 1));
}
if(edge(*e_it).from_vertex().idx() > _h.idx()) {
edge(*e_it).set_from_vertex(VertexHandle(edge(*e_it).from_vertex() - 1));
}
++e_it;
}
}
// Remove property element
vertex_deleted(_h);
return (vertices_begin() + _h.idx());
}
/**
* \brief Delete edge from mesh
*
* After performing this operation, all edges
* following edge _h in the array will be accessible
* through their old handle decreased by one.
* This function directly fixes the edge links
* in all faces. This invalidates all bottom-up
* adjacencies. See class StatusAttrib that
* provides a proper garbage collection.
*
* @param _h An edge handle
*/
virtual EdgeIter delete_edge(const EdgeHandle& _h) {
assert(_h.idx() < (int)edges_.size());
edges_.erase(edges_.begin() + _h.idx());
for(FaceIter f_it = faces_begin(); f_it != faces_end();) {
std::vector<HalfEdgeHandle> hes = face(*f_it).halfedges();
bool deleted = false;
for(std::vector<HalfEdgeHandle>::iterator he_it = hes.begin();
he_it != hes.end(); ++he_it) {
if(edge_handle(*he_it) == _h) {
f_it = delete_face(*f_it);
deleted = true;
break;
} else if(edge_handle(*he_it).idx() > _h.idx()) {
*he_it = HalfEdgeHandle(he_it->idx() - 2);
}
}
if(!deleted) {
face(*f_it).set_halfedges(hes);
++f_it;
}
}
// Remove property element
edge_deleted(_h);
return (edges_begin() + _h.idx());
}
/**
* \brief Delete face from mesh
*
* After performing this operation, all faces
* following face _h in the array will be accessible
* through their old handle decreased by one.
* This function directly fixes the face links
* in all cells. This invalidates all bottom-up
* adjacencies. See class StatusAttrib that
* provides a proper garbage collection.
*
* @param _h A face handle
*/
virtual FaceIter delete_face(const FaceHandle& _h) {
assert(_h.idx() < (int)faces_.size());
faces_.erase(faces_.begin() + _h.idx());
for(CellIter c_it = cells_begin(); c_it != cells_end();) {
std::vector<HalfFaceHandle> hfs = cell(*c_it).halffaces();
bool deleted = false;
for(std::vector<HalfFaceHandle>::iterator hf_it = hfs.begin();
hf_it != hfs.end(); ++hf_it) {
if(face_handle(*hf_it) == _h) {
c_it = delete_cell(*c_it);
deleted = true;
break;
} else if(face_handle(*hf_it).idx() > _h.idx()) {
*hf_it = HalfFaceHandle(hf_it->idx() - 2);
}
}
if(!deleted) {
cell(*c_it).set_halffaces(hfs);
++c_it;
}
}
//=====================================================================
// Delete entities
//=====================================================================
// Remove property element
face_deleted(_h);
public:
return (faces_begin() + _h.idx());
}
virtual VertexIter delete_vertex(const VertexHandle& _h);
/**
* \brief Delete cell from mesh
*
* After performing this operation, all cells
* following cell _h in the array will be accessible
* through their old handle decreased by one.
* This invalidates all bottom-up
* adjacencies. See class StatusAttrib that
* provides a proper garbage collection.
*
* @param _h A cell handle
*/
virtual CellIter delete_cell(const CellHandle& _h) {
assert(_h.idx() < (int)cells_.size());
virtual EdgeIter delete_edge(const EdgeHandle& _h);
cells_.erase(cells_.begin() + _h.idx());
virtual FaceIter delete_face(const FaceHandle& _h);
// Remove property element
cell_deleted(_h);
virtual CellIter delete_cell(const CellHandle& _h);
return (cells_begin() + _h.idx());
}
public:
/// Clear whole mesh
virtual void clear(bool _clearProps = true) {
......@@ -474,7 +335,6 @@ public:
outgoing_hes_per_vertex_.clear();
incident_hfs_per_he_.clear();
incident_cell_per_hf_.clear();
boundary_faces_.clear();
if(_clearProps) {
......@@ -500,32 +360,107 @@ public:
// Bottom-up Adjacencies
//=====================================================================
void update_adjacencies();
public:
void enable_bottom_up_adjacencies(bool _enable) {