diff --git a/src/OpenMesh/Core/Mesh/ArrayKernel.cc b/src/OpenMesh/Core/Mesh/ArrayKernel.cc index 21ca61f34e0fd760d42b22d35f70c7aeb86c5521..d2f95871fb3e2030ba3607bbbcfdea3d1ebb5215 100644 --- a/src/OpenMesh/Core/Mesh/ArrayKernel.cc +++ b/src/OpenMesh/Core/Mesh/ArrayKernel.cc @@ -94,10 +94,10 @@ void ArrayKernel::assign_connectivity(const ArrayKernel& _other) #undef COPY_STATUS_PROPERTY } -uint ArrayKernel::delete_isolated_vertices() +unsigned int ArrayKernel::delete_isolated_vertices() { assert(has_vertex_status());//this function requires vertex status property - uint n_isolated = 0; + unsigned int n_isolated = 0; for (KernelVertexIter v_it = vertices_begin(); v_it != vertices_end(); ++v_it) { if (is_isolated(handle(*v_it))) @@ -111,148 +111,10 @@ uint ArrayKernel::delete_isolated_vertices() void ArrayKernel::garbage_collection(bool _v, bool _e, bool _f) { - int i, i0, i1, nV(n_vertices()), nE(n_edges()), nH(2*n_edges()), nF(n_faces()); - - std::vector vh_map; - std::vector hh_map; - std::vector fh_map; - - // setup handle mapping: - vh_map.reserve(nV); - for (i=0; i 0) - { - i0=0; i1=nV-1; - - while (1) - { - // find 1st deleted and last un-deleted - while (!status(VertexHandle(i0)).deleted() && i0 < i1) ++i0; - while ( status(VertexHandle(i1)).deleted() && i0 < i1) --i1; - if (i0 >= i1) break; - - // swap - std::swap(vertices_[i0], vertices_[i1]); - std::swap(vh_map[i0], vh_map[i1]); - vprops_swap(i0, i1); - }; - - vertices_.resize(status(VertexHandle(i0)).deleted() ? i0 : i0+1); - vprops_resize(n_vertices()); - } - - - // remove deleted edges - if (_e && n_edges() > 0) - { - i0=0; i1=nE-1; - - while (1) - { - // find 1st deleted and last un-deleted - while (!status(EdgeHandle(i0)).deleted() && i0 < i1) ++i0; - while ( status(EdgeHandle(i1)).deleted() && i0 < i1) --i1; - if (i0 >= i1) break; - - // swap - std::swap(edges_[i0], edges_[i1]); - std::swap(hh_map[2*i0], hh_map[2*i1]); - std::swap(hh_map[2*i0+1], hh_map[2*i1+1]); - eprops_swap(i0, i1); - hprops_swap(2*i0, 2*i1); - hprops_swap(2*i0+1, 2*i1+1); - }; - - edges_.resize(status(EdgeHandle(i0)).deleted() ? i0 : i0+1); - eprops_resize(n_edges()); - hprops_resize(n_halfedges()); - } - - - // remove deleted faces - if (_f && n_faces() > 0) - { - i0=0; i1=nF-1; - - while (1) - { - // find 1st deleted and last un-deleted - while (!status(FaceHandle(i0)).deleted() && i0 < i1) ++i0; - while ( status(FaceHandle(i1)).deleted() && i0 < i1) --i1; - if (i0 >= i1) break; - - // swap - std::swap(faces_[i0], faces_[i1]); - std::swap(fh_map[i0], fh_map[i1]); - fprops_swap(i0, i1); - }; - - faces_.resize(status(FaceHandle(i0)).deleted() ? i0 : i0+1); - fprops_resize(n_faces()); - } - - - // update handles of vertices - if (_e) - { - KernelVertexIter v_it(vertices_begin()), v_end(vertices_end()); - VertexHandle vh; - - for (; v_it!=v_end; ++v_it) - { - vh = handle(*v_it); - if (!is_isolated(vh)) - { - set_halfedge_handle(vh, hh_map[halfedge_handle(vh).idx()]); - } - } - } - - HalfedgeHandle hh; - // update handles of halfedges - for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) - {//in the first pass update the (half)edges vertices - hh = halfedge_handle(handle(*e_it), 0); - set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); - hh = halfedge_handle(handle(*e_it), 1); - set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); - } - for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) - {//in the second pass update the connectivity of the (half)edges - hh = halfedge_handle(handle(*e_it), 0); - set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); - if (!is_boundary(hh)) - { - set_face_handle(hh, fh_map[face_handle(hh).idx()]); - } - hh = halfedge_handle(handle(*e_it), 1); - set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); - if (!is_boundary(hh)) - { - set_face_handle(hh, fh_map[face_handle(hh).idx()]); - } - } - - // update handles of faces - if (_e) - { - KernelFaceIter f_it(faces_begin()), f_end(faces_end()); - FaceHandle fh; - - for (; f_it!=f_end; ++f_it) - { - fh = handle(*f_it); - set_halfedge_handle(fh, hh_map[halfedge_handle(fh).idx()]); - } - } + std::vector empty_vh; + std::vector empty_hh; + std::vector empty_fh; + garbage_collection( _v, _e, _f, &empty_vh,&empty_hh,&empty_fh); } void ArrayKernel::clear() @@ -273,7 +135,7 @@ void ArrayKernel::clear() } -void ArrayKernel::resize( uint _n_vertices, uint _n_edges, uint _n_faces ) +void ArrayKernel::resize( unsigned int _n_vertices, unsigned int _n_edges, unsigned int _n_faces ) { vertices_.resize(_n_vertices); edges_.resize(_n_edges); @@ -285,7 +147,7 @@ void ArrayKernel::resize( uint _n_vertices, uint _n_edges, uint _n_faces ) fprops_resize(n_faces()); } -void ArrayKernel::reserve(uint _n_vertices, uint _n_edges, uint _n_faces ) +void ArrayKernel::reserve(unsigned int _n_vertices, unsigned int _n_edges, unsigned int _n_faces ) { vertices_.reserve(_n_vertices); edges_.reserve(_n_edges); @@ -300,7 +162,7 @@ void ArrayKernel::reserve(uint _n_vertices, uint _n_edges, uint _n_faces ) // Status Sets API void ArrayKernel::init_bit_masks(BitMaskContainer& _bmc) { - for (uint i = Attributes::UNUSED; i != 0; i <<= 1) + for (unsigned int i = Attributes::UNUSED; i != 0; i <<= 1) { _bmc.push_back(i); } diff --git a/src/OpenMesh/Core/Mesh/ArrayKernel.hh b/src/OpenMesh/Core/Mesh/ArrayKernel.hh index ad118d9eb72c52c7376fe978a129dfb323e46efd..608280caa49ea853eac85dba44f458a85c790bf5 100644 --- a/src/OpenMesh/Core/Mesh/ArrayKernel.hh +++ b/src/OpenMesh/Core/Mesh/ArrayKernel.hh @@ -121,7 +121,7 @@ public: // There are two halfedges stored per edge // Get memory position inside edge vector and devide by size of an edge // to get the corresponding edge for the requested halfedge - uint eh = ( (char*)&_he - (char*)&edges_.front() ) / sizeof(Edge) ; + unsigned int eh = ( (char*)&_he - (char*)&edges_.front() ) / sizeof(Edge) ; assert((&_he == &edges_[eh].halfedges_[0]) || (&_he == &edges_[eh].halfedges_[1])); return ((&_he == &edges_[eh].halfedges_[0]) ? @@ -201,19 +201,19 @@ public: // --- get i'th items --- - VertexHandle vertex_handle(uint _i) const + VertexHandle vertex_handle(unsigned int _i) const { return (_i < n_vertices()) ? handle( vertices_[_i] ) : VertexHandle(); } - HalfedgeHandle halfedge_handle(uint _i) const + HalfedgeHandle halfedge_handle(unsigned int _i) const { return (_i < n_halfedges()) ? halfedge_handle(edge_handle(_i/2), _i%2) : HalfedgeHandle(); } - EdgeHandle edge_handle(uint _i) const + EdgeHandle edge_handle(unsigned int _i) const { return (_i < n_edges()) ? handle(edges_[_i]) : EdgeHandle(); } - FaceHandle face_handle(uint _i) const + FaceHandle face_handle(unsigned int _i) const { return (_i < n_faces()) ? handle(faces_[_i]) : FaceHandle(); } public: @@ -257,18 +257,52 @@ public: public: // --- resize/reserve --- - void resize( uint _n_vertices, uint _n_edges, uint _n_faces ); - void reserve(uint _n_vertices, uint _n_edges, uint _n_faces ); + void resize( unsigned int _n_vertices, unsigned int _n_edges, unsigned int _n_faces ); + void reserve(unsigned int _n_vertices, unsigned int _n_edges, unsigned int _n_faces ); // --- deletion --- + /** \brief garbage collection + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + */ void garbage_collection(bool _v=true, bool _e=true, bool _f=true); + + /** \brief garbage collection + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * \note Garbage collection invalidates all handles. If you need to keep track of + * a set of handles, you can pass vectors of pointers to the handles to this function + * + * @param vh_to_update Vertex handles that should get updated + * @param hh_to_update Halfedge handles that should get updated + * @param fh_to_update Face handles that should get updated + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + */ + template + void garbage_collection(bool _v=true, bool _e=true, bool _f=true, + std_API_Container_VHandlePointer* vh_to_update = 0, + std_API_Container_HHandlePointer* hh_to_update = 0, + std_API_Container_FHandlePointer* fh_to_update = 0); + void clear(); // --- number of items --- - uint n_vertices() const { return vertices_.size(); } - uint n_halfedges() const { return 2*edges_.size(); } - uint n_edges() const { return edges_.size(); } - uint n_faces() const { return faces_.size(); } + unsigned int n_vertices() const { return vertices_.size(); } + unsigned int n_halfedges() const { return 2*edges_.size(); } + unsigned int n_edges() const { return edges_.size(); } + unsigned int n_faces() const { return faces_.size(); } bool vertices_empty() const { return vertices_.empty(); } bool halfedges_empty() const { return edges_.empty(); } @@ -292,7 +326,7 @@ public: void set_isolated(VertexHandle _vh) { vertex(_vh).halfedge_handle_.invalidate(); } - uint delete_isolated_vertices(); + unsigned int delete_isolated_vertices(); // --- halfedge connectivity --- VertexHandle to_vertex_handle(HalfedgeHandle _heh) const @@ -394,7 +428,7 @@ public: { return next_halfedge_handle(opposite_halfedge_handle(_heh)); } // --- edge connectivity --- - HalfedgeHandle halfedge_handle(EdgeHandle _eh, uint _i) const + HalfedgeHandle halfedge_handle(EdgeHandle _eh, unsigned int _i) const { assert(_i<=1); return HalfedgeHandle((_eh.idx() << 1) + _i); @@ -538,10 +572,10 @@ public: ArrayKernel& kernel_; public: - const uint bit_mask_; + const unsigned int bit_mask_; public: - StatusSetT(ArrayKernel& _kernel, uint _bit_mask) + StatusSetT(ArrayKernel& _kernel, unsigned int _bit_mask) : kernel_(_kernel), bit_mask_(_bit_mask) {} @@ -558,14 +592,14 @@ public: { kernel_.status(_hnd).unset_bit(bit_mask_); } /// Note: 0(n) complexity - uint size() const + unsigned int size() const { - uint n_elements = kernel_.status_pph(Handle()).is_valid() ? - kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; - uint sz = 0; - for (uint i = 0; i < n_elements; ++i) + unsigned int n_elements = kernel_.status_pph(Handle()).is_valid() ? + kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + unsigned int sz = 0; + for (unsigned int i = 0; i < n_elements; ++i) { - sz += (uint)is_in(Handle(i)); + sz += (unsigned int)is_in(Handle(i)); } return sz; } @@ -573,9 +607,9 @@ public: /// Note: O(n) complexity void clear() { - uint n_elements = kernel_.status_pph(Handle()).is_valid() ? - kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; - for (uint i = 0; i < n_elements; ++i) + unsigned int n_elements = kernel_.status_pph(Handle()).is_valid() ? + kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + for (unsigned int i = 0; i < n_elements; ++i) { erase(Handle(i)); } @@ -634,7 +668,7 @@ public: typedef typename HandleContainer::const_iterator const_iterator; public: - ExtStatusSetT(ArrayKernel& _kernel, uint _capacity_hint = 0) + ExtStatusSetT(ArrayKernel& _kernel, unsigned int _capacity_hint = 0) : Base(_kernel) { handles_.reserve(_capacity_hint); } @@ -682,7 +716,7 @@ public: } /// Complexity: 0(1) - inline uint size() const + inline unsigned int size() const { return handles_.size(); } inline bool empty() const { return handles_.empty(); } @@ -725,7 +759,7 @@ private: typedef EdgeContainer::const_iterator KernelConstEdgeIter; typedef FaceContainer::iterator KernelFaceIter; typedef FaceContainer::const_iterator KernelConstFaceIter; - typedef std::vector BitMaskContainer; + typedef std::vector BitMaskContainer; KernelVertexIter vertices_begin() { return vertices_.begin(); } @@ -754,16 +788,16 @@ private: { return halfedge_bit_masks_; } template - uint pop_bit_mask(Handle _hnd) + unsigned int pop_bit_mask(Handle _hnd) { assert(!bit_masks(_hnd).empty());//check if the client request too many status sets - uint bit_mask = bit_masks(_hnd).back(); + unsigned int bit_mask = bit_masks(_hnd).back(); bit_masks(_hnd).pop_back(); return bit_mask; } template - void push_bit_mask(Handle _hnd, uint _bit_mask) + void push_bit_mask(Handle _hnd, unsigned int _bit_mask) { assert(std::find(bit_masks(_hnd).begin(), bit_masks(_hnd).end(), _bit_mask) == bit_masks(_hnd).end());//this mask should be not already used @@ -783,10 +817,10 @@ private: EdgeStatusPropertyHandle edge_status_; FaceStatusPropertyHandle face_status_; - uint refcount_vstatus_; - uint refcount_hstatus_; - uint refcount_estatus_; - uint refcount_fstatus_; + unsigned int refcount_vstatus_; + unsigned int refcount_hstatus_; + unsigned int refcount_estatus_; + unsigned int refcount_fstatus_; BitMaskContainer halfedge_bit_masks_; BitMaskContainer edge_bit_masks_; @@ -794,8 +828,14 @@ private: BitMaskContainer face_bit_masks_; }; + //============================================================================= } // namespace OpenMesh //============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_ARRAY_KERNEL_C) +# define OPENMESH_ARRAY_KERNEL_TEMPLATES +# include "ArrayKernelT.cc" +#endif +//============================================================================= #endif // OPENMESH_ARRAY_KERNEL_HH defined //============================================================================= diff --git a/src/OpenMesh/Core/Mesh/ArrayKernelT.cc b/src/OpenMesh/Core/Mesh/ArrayKernelT.cc new file mode 100644 index 0000000000000000000000000000000000000000..c8e7e88a6afcdd68e4c2462b68a17a76ed8e65d2 --- /dev/null +++ b/src/OpenMesh/Core/Mesh/ArrayKernelT.cc @@ -0,0 +1,253 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + * * + * OpenMesh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of * + * the License, or (at your option) any later version with the * + * following exceptions: * + * * + * If other files instantiate templates or use macros * + * or inline functions from this file, or you compile this file and * + * link it with other files to produce an executable, this file does * + * not by itself cause the resulting executable to be covered by the * + * GNU Lesser General Public License. This exception does not however * + * invalidate any other reasons why the executable file might be * + * covered by the GNU Lesser General Public License. * + * * + * OpenMesh is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU LesserGeneral Public * + * License along with OpenMesh. If not, * + * see . * + * * +\*===========================================================================*/ + +/*===========================================================================*\ + * * + * $Revision: 362 $ * + * $Date: 2011-01-26 10:21:12 +0100 (Mi, 26 Jan 2011) $ * + * * +\*===========================================================================*/ + +#define OPENMESH_ARRAY_KERNEL_C + +//== INCLUDES ================================================================= + +#include +//#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh +{ + +//== IMPLEMENTATION ========================================================== + +template +void ArrayKernel::garbage_collection(bool _v, bool _e, bool _f, + std_API_Container_VHandlePointer* vh_to_update, + std_API_Container_HHandlePointer* hh_to_update, + std_API_Container_FHandlePointer* fh_to_update + ) +{ + int i, i0, i1, nV(n_vertices()), nE(n_edges()), nH(2*n_edges()), nF(n_faces()); + + std::vector vh_map; + std::vector hh_map; + std::vector fh_map; + + // setup handle mapping: + vh_map.reserve(nV); + for (i=0; i 0) + { + i0=0; i1=nV-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(VertexHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(VertexHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + std::swap(vertices_[i0], vertices_[i1]); + std::swap(vh_map[i0], vh_map[i1]); + vprops_swap(i0, i1); + }; + + vertices_.resize(status(VertexHandle(i0)).deleted() ? i0 : i0+1); + vprops_resize(n_vertices()); + } + + + // remove deleted edges + if (_e && n_edges() > 0) + { + i0=0; i1=nE-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(EdgeHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(EdgeHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + std::swap(edges_[i0], edges_[i1]); + std::swap(hh_map[2*i0], hh_map[2*i1]); + std::swap(hh_map[2*i0+1], hh_map[2*i1+1]); + eprops_swap(i0, i1); + hprops_swap(2*i0, 2*i1); + hprops_swap(2*i0+1, 2*i1+1); + }; + + edges_.resize(status(EdgeHandle(i0)).deleted() ? i0 : i0+1); + eprops_resize(n_edges()); + hprops_resize(n_halfedges()); + } + + + // remove deleted faces + if (_f && n_faces() > 0) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(FaceHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(FaceHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + std::swap(faces_[i0], faces_[i1]); + std::swap(fh_map[i0], fh_map[i1]); + fprops_swap(i0, i1); + }; + + faces_.resize(status(FaceHandle(i0)).deleted() ? i0 : i0+1); + fprops_resize(n_faces()); + } + + + // update handles of vertices + if (_e) + { + KernelVertexIter v_it(vertices_begin()), v_end(vertices_end()); + VertexHandle vh; + + for (; v_it!=v_end; ++v_it) + { + vh = handle(*v_it); + if (!is_isolated(vh)) + { + set_halfedge_handle(vh, hh_map[halfedge_handle(vh).idx()]); + } + } + } + + HalfedgeHandle hh; + // update handles of halfedges + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the first pass update the (half)edges vertices + hh = halfedge_handle(handle(*e_it), 0); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + hh = halfedge_handle(handle(*e_it), 1); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + } + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the second pass update the connectivity of the (half)edges + hh = halfedge_handle(handle(*e_it), 0); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + hh = halfedge_handle(handle(*e_it), 1); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + } + + // update handles of faces + if (_e) + { + KernelFaceIter f_it(faces_begin()), f_end(faces_end()); + FaceHandle fh; + + for (; f_it!=f_end; ++f_it) + { + fh = handle(*f_it); + set_halfedge_handle(fh, hh_map[halfedge_handle(fh).idx()]); + } + } + + // Update the vertex handles in the vertex handle vector + if ( vh_to_update ) { + + const int vertexCount = vertices_.size(); + typename std_API_Container_VHandlePointer::iterator v_it(vh_to_update->begin()), v_it_end(vh_to_update->end()); + for(; v_it != v_it_end; ++v_it) + { + if ( (*v_it)->idx() >= vertexCount ) + (*v_it)->invalidate(); + else + *(*v_it) = vh_map[(*v_it)->idx()]; + } + + } + + // Update the halfedge handles in the halfedge handle vector + if ( hh_to_update ) { + const int halfedgeCount = edges_.size() * 2; + + typename std_API_Container_HHandlePointer::iterator hh_it(hh_to_update->begin()), hh_it_end(hh_to_update->end()); + for(; hh_it != hh_it_end; ++hh_it) + { + if ( (*hh_it)->idx() >= halfedgeCount ) + (*hh_it)->invalidate(); + else + *(*hh_it) = hh_map[(*hh_it)->idx()]; + } + } + + // Update the face handles in the face handle vector + if(fh_to_update) { + const int faceCount = faces_.size(); + + typename std_API_Container_FHandlePointer::iterator fh_it(fh_to_update->begin()), fh_it_end(fh_to_update->end()); + for(; fh_it != fh_it_end; ++fh_it) + { + if ( (*fh_it)->idx() >= faceCount ) + (*fh_it)->invalidate(); + else + *(*fh_it) = fh_map[(*fh_it)->idx()]; + } + } +} + +} + diff --git a/src/Unittests/unittests.cc b/src/Unittests/unittests.cc index 5721bbb3396f32756ec18df6a661e484847d815d..7b92b84286444b086c78878b371e427ba49147b3 100644 --- a/src/Unittests/unittests.cc +++ b/src/Unittests/unittests.cc @@ -11,6 +11,7 @@ #include "unittests_trimesh_normal_calculations.hh" #include "unittests_trimesh_others.hh" #include "unittests_add_face.hh" +#include "unittests_trimesh_garbage_collection.hh" int main(int _argc, char** _argv) {