/*************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCGLIB_TRIALLOCATOR #define __VCGLIB_TRIALLOCATOR #include #include #include namespace vcg { class PointerToAttribute { public: SimpleTempDataBase * _handle; // pointer to the SimpleTempData that stores the attribute std::string _name; // name of the attribute int _sizeof; // size of the attribute type (used only with VMI loading) int _padding; // padding (used only with VMI loading) int n_attr; // unique ID of the attribute void Resize(const int & sz){((SimpleTempDataBase *)_handle)->Resize(sz);} void Reorder(std::vector & newVertIndex){((SimpleTempDataBase *)_handle)->Reorder(newVertIndex);} bool operator<(const PointerToAttribute b) const { return(_name.empty()&&b._name.empty())?(_handle < b._handle):( _name < b._name);} }; namespace tri { /** \addtogroup trimesh @{ */ template size_t Index(MeshType &m, const typename MeshType::VertexType &v) {return &v-&*m.vert.begin();} template size_t Index(MeshType &m, const typename MeshType::FaceType &f) {return &f-&*m.face.begin();} template size_t Index(MeshType &m, const typename MeshType::EdgeType &e) {return &e-&*m.edge.begin();} template size_t Index(MeshType &m, const typename MeshType::HEdgeType &h) {return &h-&*m.hedge.begin();} template size_t Index(MeshType &m, const typename MeshType::VertexType *vp) {return vp-&*m.vert.begin();} template size_t Index(MeshType &m, const typename MeshType::FaceType * fp) {return fp-&*m.face.begin();} template size_t Index(MeshType &m, const typename MeshType::EdgeType* e) {return e-&*m.edge.begin();} template size_t Index(MeshType &m, const typename MeshType::HEdgeType* h) {return h-&*m.hedge.begin();} template void ReorderAttribute(ATTR_CONT &c,std::vector & newVertIndex, MeshType & /* m */){ typename std::set::iterator ai; for(ai = c.begin(); ai != c.end(); ++ai) ((typename MeshType::PointerToAttribute)(*ai)).Reorder(newVertIndex); } template void ResizeAttribute(ATTR_CONT &c,const int & sz , MeshType &/*m*/){ typename std::set::iterator ai; for(ai =c.begin(); ai != c.end(); ++ai) ((typename MeshType::PointerToAttribute)(*ai)).Resize(sz); } /*! \brief Class to safely add and delete elements in a mesh. Adding elements to a mesh, like faces and vertices can involve the reallocation of the vectors of the involved elements. This class provide the only safe methods to add elements. It also provide an accessory class vcg::tri::PointerUpdater for updating pointers to mesh elements that are kept by the user. */ template class Allocator { public: typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::VertexIterator VertexIterator; typedef typename MeshType::VertContainer VertContainer; typedef typename MeshType::EdgeType EdgeType; typedef typename MeshType::EdgePointer EdgePointer; typedef typename MeshType::EdgeIterator EdgeIterator; typedef typename MeshType::EdgeContainer EdgeContainer; typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceContainer FaceContainer; typedef typename MeshType::HEdgeType HEdgeType; typedef typename MeshType::HEdgePointer HEdgePointer; typedef typename MeshType::HEdgeIterator HEdgeIterator; typedef typename MeshType::HEdgeContainer HEdgeContainer; typedef typename MeshType::PointerToAttribute PointerToAttribute; typedef typename std::set::iterator AttrIterator; typedef typename std::set::const_iterator AttrConstIterator; typedef typename std::set::iterator PAIte; /*! \brief Accessory class to update pointers after eventual reallocation caused by adding elements. This class is used when allocating new vertexes and faces to update the pointers that can be changed when resizing the involved vectors of vertex or faces. It can also be used to prevent any update of the various mesh fields (e.g. in case you are building all the connections by hand as in a importer); \sa \ref allocation */ template class PointerUpdater { public: PointerUpdater(void) : newBase(0), oldBase(0), newEnd(0), oldEnd(0), preventUpdateFlag(false) { ; } void Clear(){newBase=oldBase=newEnd=oldEnd=0;} /*! \brief Update a pointer to an element of a mesh after a reallocation The updating is correctly done only if this PointerUpdater have been passed to the corresponing allocation call. \sa \ref allocation */ void Update(SimplexPointerType &vp) { //if(vp>=newBase && vpoldEnd) return; assert(vp>=oldBase); assert(vp remap; bool preventUpdateFlag; /// when true no update is considered necessary. }; /** \brief Add n vertices to the mesh. Function to add n vertices to the mesh. The elements are added always to the end of the vector. No attempt of reusing previously deleted element is done. \sa PointerUpdater \param m the mesh to be modified \param n the number of elements to be added \param pu a PointerUpdater initialized so that it can be used to update pointers to vertices that could have become invalid after this adding. \retval the iterator to the first element added. */ static VertexIterator AddVertices(MeshType &m,int n, PointerUpdater &pu) { VertexIterator last; if(n == 0) return m.vert.end(); pu.Clear(); if(m.vert.empty()) pu.oldBase=0; // if the vector is empty we cannot find the last valid element else { pu.oldBase=&*m.vert.begin(); pu.oldEnd=&m.vert.back()+1; } m.vert.resize(m.vert.size()+n); m.vn+=n; typename std::set::iterator ai; for(ai = m.vert_attr.begin(); ai != m.vert_attr.end(); ++ai) ((PointerToAttribute)(*ai)).Resize(m.vert.size()); pu.newBase = &*m.vert.begin(); pu.newEnd = &m.vert.back()+1; if(pu.NeedUpdate()) { FaceIterator fi; for (fi=m.face.begin(); fi!=m.face.end(); ++fi) if(!(*fi).IsD()) for(int i=0; i < (*fi).VN(); ++i) if ((*fi).cV(i)!=0) pu.Update((*fi).V(i)); EdgeIterator ei; for (ei=m.edge.begin(); ei!=m.edge.end(); ++ei) if(!(*ei).IsD()) { if(HasEVAdjacency (m)) { pu.Update((*ei).V(0));pu.Update((*ei).V(1));} // if(HasEVAdjacency(m)) pu.Update((*ei).EVp()); } HEdgeIterator hi; for (hi=m.hedge.begin(); hi!=m.hedge.end(); ++hi) if(!(*hi).IsD()) { if(HasHVAdjacency (m)) { pu.Update((*hi).HVp()); } } // e poiche' lo spazio e' cambiato si ricalcola anche last da zero } unsigned int siz=(unsigned int)m.vert.size()-n; last = m.vert.begin(); advance(last,siz); return last;// deve restituire l'iteratore alla prima faccia aggiunta; } /** \brief Wrapper to AddVertices(); no PointerUpdater */ static VertexIterator AddVertices(MeshType &m, int n) { PointerUpdater pu; return AddVertices(m, n,pu); } /** \brief Wrapper to AddVertices() no PointerUpdater but a vector of VertexPointer pointers to be updated */ static VertexIterator AddVertices(MeshType &m, int n, std::vector &local_vec) { PointerUpdater pu; VertexIterator v_ret = AddVertices(m, n,pu); typename std::vector::iterator vi; for(vi=local_vec.begin();vi!=local_vec.end();++vi) pu.Update(**vi); return v_ret; } /* ++++++++++ edges +++++++++++++ */ /** \brief Add n edges to the mesh. Function to add n edges to the mesh. The elements are added always to the end of the vector. No attempt of reusing previously deleted element is done. \sa PointerUpdater \param m the mesh to be modified \param n the number of elements to be added \param pu a PointerUpdater initialized so that it can be used to update pointers to edges that could have become invalid after this adding. \retval the iterator to the first element added. */ static EdgeIterator AddEdges(MeshType &m,int n, PointerUpdater &pu) { EdgeIterator last; if(n == 0) return m.edge.end(); pu.Clear(); if(m.edge.empty()) pu.oldBase=0; // if the vector is empty we cannot find the last valid element else { pu.oldBase=&*m.edge.begin(); pu.oldEnd=&m.edge.back()+1; } m.edge.resize(m.edge.size()+n); m.en+=n; typename std::set::iterator ai; for(ai = m.edge_attr.begin(); ai != m.edge_attr.end(); ++ai) ((typename MeshType::PointerToAttribute)(*ai)).Resize(m.edge.size()); pu.newBase = &*m.edge.begin(); pu.newEnd = &m.edge.back()+1; if(pu.NeedUpdate()) { FaceIterator fi; for (fi=m.face.begin(); fi!=m.face.end(); ++fi){ //if(HasFHEAdjacency(m)) // pu.Update((*fi).FHEp()); if(!(*fi).IsD()) for(int i=0; i < (*fi).VN(); ++i) if ((*fi).cFEp(i)!=0) pu.Update((*fi).FEp(i)); } VertexIterator vi; if(HasVEAdjacency(m)) for (vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if(!(*vi).IsD()) if ((*vi).cVEp()!=0) pu.Update((*vi).VEp()); HEdgeIterator hi; if(HasHEAdjacency(m)) for (hi=m.hedge.begin(); hi!=m.hedge.end(); ++hi) if(!(*hi).IsD()) if ((*hi).cHEp()!=0) pu.Update((*hi).HEp()); } unsigned int siz=(unsigned int)m.edge.size()-n; last = m.edge.begin(); advance(last,siz); return last;// deve restituire l'iteratore alla prima faccia aggiunta; } /** Function to add n edges to the mesh. First wrapper, with no parameters */ static EdgeIterator AddEdges(MeshType &m, int n) { PointerUpdater pu; return AddEdges(m, n,pu); } /** Function to add n edges to the mesh. Second Wrapper, with a vector of vertex pointers to be updated. */ static EdgeIterator AddEdges(MeshType &m, int n, std::vector &local_vec) { PointerUpdater pu; EdgeIterator v_ret = AddEdges(m, n,pu); typename std::vector::iterator ei; for(ei=local_vec.begin();ei!=local_vec.end();++ei) pu.Update(**ei); return v_ret; } /* ++++++++++ hedges +++++++++++++ */ /** Function to add n halfedges to the mesh. The second parameter hold a vector of pointers to pointer to elements of the mesh that should be updated after a possible vector realloc. \sa PointerUpdater \param m the mesh to be modified \param n the number of elements to be added \param pu a PointerUpdater initialized so that it can be used to update pointers to edges that could have become invalid after this adding. \retval the iterator to the first element added. */ static HEdgeIterator AddHEdges(MeshType &m,int n, PointerUpdater &pu) { HEdgeIterator last; if(n == 0) return m.hedge.end(); pu.Clear(); if(m.hedge.empty()) pu.oldBase=0; // if the vector is empty we cannot find the last valid element else { pu.oldBase=&*m.hedge.begin(); pu.oldEnd=&m.hedge.back()+1; } m.hedge.resize(m.hedge.size()+n); m.hn+=n; pu.newBase = &*m.hedge.begin(); pu.newEnd = &m.hedge.back()+1; if(pu.NeedUpdate()) { int ii = 0; FaceIterator fi; for (fi=m.face.begin(); fi!=m.face.end(); ++fi) { if(HasFHAdjacency(m)) if(!(*fi).IsD() && (*fi).FHp()) pu.Update((*fi).FHp()); } { VertexIterator vi; for (vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if(HasVHAdjacency(m)) if(!(*vi).IsD()) if ((*vi).cVHp()!=0) pu.Update((*vi).VHp()); } { EdgeIterator ei; for (ei=m.edge.begin(); ei!=m.edge.end(); ++ei) if(HasEHAdjacency(m)) if(!(*ei).IsD()) if ((*ei).cEHp()!=0) pu.Update((*ei).EHp()); } { HEdgeIterator hi = m.hedge.begin(); while(ii < m.hn - n)// cycle on all the faces except the new ones { if(!(*hi).IsD()) { if(HasHNextAdjacency(m)) pu.Update((*hi).HNp()); if(HasHPrevAdjacency(m)) pu.Update((*hi).HPp()); if(HasHOppAdjacency(m)) pu.Update((*hi).HOp()); ++ii; } ++hi; } } } unsigned int siz = (unsigned int)m.hedge.size()-n; last = m.hedge.begin(); advance(last,siz); return last;// deve restituire l'iteratore alla prima faccia aggiunta; } /** Function to add n vertices to the mesh. First wrapper, with no parameters */ static HEdgeIterator AddHEdges(MeshType &m, int n) { PointerUpdater pu; return AddHEdges(m, n,pu); } /** Function to add n vertices to the mesh. Second Wrapper, with a vector of vertex pointers to be updated. */ static HEdgeIterator AddHEdges(MeshType &m, int n, std::vector &local_vec) { PointerUpdater pu; HEdgeIterator v_ret = AddHEdges(m, n,pu); typename std::vector::iterator ei; for(ei=local_vec.begin();ei!=local_vec.end();++ei) pu.Update(**ei); return v_ret; } /** Function to add n faces to the mesh. First wrapper, with no parameters */ static FaceIterator AddFaces(MeshType &m, int n) { PointerUpdater pu; return AddFaces(m,n,pu); } /** Function to add n faces to the mesh. Second Wrapper, with a vector of face pointer to be updated. */ static FaceIterator AddFaces(MeshType &m, int n,std::vector &local_vec) { PointerUpdater pu; FaceIterator f_ret= AddFaces(m,n,pu); typename std::vector::iterator fi; for(fi=local_vec.begin();fi!=local_vec.end();++fi) pu.Update(**fi); return f_ret; } /** Function to add n faces to the mesh. This is the only full featured function that is able to manage correctly all the internal pointers of the mesh (ff and vf relations). NOTE: THIS FUNCTION ALSO UPDATE FN */ static FaceIterator AddFaces(MeshType &m, int n, PointerUpdater &pu) { FaceIterator last, fi; if(n == 0) return m.face.end(); pu.Clear(); if(m.face.empty()) { pu.oldBase=0; // if the vector is empty we cannot find the last valid element } else { pu.oldBase=&*m.face.begin(); pu.oldEnd=&m.face.back()+1; last=m.face.end(); } m.face.resize(m.face.size()+n); m.fn+=n; typename std::set::iterator ai; for(ai = m.face_attr.begin(); ai != m.face_attr.end(); ++ai) ((PointerToAttribute)(*ai)).Resize(m.face.size()); pu.newBase = &*m.face.begin(); pu.newEnd = &m.face.back()+1; if(pu.NeedUpdate()) { int ii = 0; FaceIterator fi = m.face.begin(); while(ii= &m.face.front() && &f <= &m.face.back()); assert(!f.IsD()); f.SetD(); --m.fn; } /** Function to delete a vertex from the mesh. NOTE: THIS FUNCTION ALSO UPDATE vn */ static void DeleteVertex(MeshType &m, VertexType &v) { assert(&v >= &m.vert.front() && &v <= &m.vert.back()); assert(!v.IsD()); v.SetD(); --m.vn; } /** Function to delete an edge from the mesh. NOTE: THIS FUNCTION ALSO UPDATE en */ static void DeleteEdge(MeshType &m, EdgeType &e) { assert(&e >= &m.edge.front() && &e <= &m.edge.back()); assert(!e.IsD()); e.SetD(); --m.en; } /** Function to delete a hedge from the mesh. NOTE: THIS FUNCTION ALSO UPDATE en */ static void DeleteHEdge(MeshType &m, HEdgeType &h) { assert(!h.IsD()); h.SetD(); --m.hn; } /* Function to rearrange the vertex vector according to a given index permutation the permutation is vector such that after calling this function m.vert[ newVertIndex[i] ] = m.vert[i]; e.g. newVertIndex[i] is the new index of the vertex i */ static void PermutateVertexVector(MeshType &m, PointerUpdater &pu) { for(unsigned int i=0;i &pu ) { // If already compacted fast return please! if(m.vn==(int)m.vert.size()) return; // newVertIndex [ ] gives you the new position of the vertex in the vector; pu.remap.resize( m.vert.size(),std::numeric_limits::max() ); size_t pos=0; size_t i=0; for(i=0;i pu; CompactVertexVector(m,pu); } /*! \brief Compact vector of edges removing deleted elements. Deleted elements are put to the end of the vector and the vector is resized. Order between elements is preserved but not their position (hence the PointerUpdater) After calling this function the \c IsD() test in the scanning a vector, is no more necessary. \warning It should not be called when TemporaryData is active (but works correctly if attributes are present) */ static void CompactEdgeVector( MeshType &m, PointerUpdater &pu ) { // If already compacted fast return please! if(m.en==(int)m.edge.size()) return; // remap [ ] gives you the new position of the edge in the vector; pu.remap.resize( m.edge.size(),std::numeric_limits::max() ); size_t pos=0; size_t i=0; for(i=0;i pu; CompactEdgeVector(m,pu); } /*! \brief Compact vector of faces removing deleted elements. Deleted elements are put to the end of the vector and the vector is resized. Order between elements is preserved but not their position (hence the PointerUpdater) After calling this function the \c IsD() test in the scanning a vector, is no more necessary. \warning It should not be called when TemporaryData is active (but works correctly if attributes are present) */ static void CompactFaceVector( MeshType &m, PointerUpdater &pu ) { // If already compacted fast return please! if(m.fn==(int)m.face.size()) return; // newFaceIndex [ ] gives you the new position of the face in the vector; pu.remap.resize( m.face.size(),std::numeric_limits::max() ); size_t pos=0; size_t i=0; for(i=0;i pu; CompactFaceVector(m,pu); } public: /*! \brief Check if an handle to a Per-Vertex Attribute is valid */ template static bool IsValidHandle( MeshType & m, const typename MeshType::template PerVertexAttributeHandle & a){ if(a._handle == NULL) return false; for(AttrIterator i = m.vert_attr.begin(); i!=m.vert_attr.end();++i) if ( (*i).n_attr == a.n_attr ) return true; return false; } /*! \brief Add a Per-Vertex Attribute of the given ATTR_TYPE with the given name. No attribute with that name must exists (even of different type) */ template static typename MeshType::template PerVertexAttributeHandle AddPerVertexAttribute( MeshType & m, std::string name){ PAIte i; PointerToAttribute h; h._name = name; if(!name.empty()){ i = m.vert_attr.find(h); assert(i ==m.vert_attr.end() );// an attribute with this name exists } h._sizeof = sizeof(ATTR_TYPE); h._padding = 0; h._handle = new SimpleTempData(m.vert); m.attrn++; h.n_attr = m.attrn; std::pair < AttrIterator , bool> res = m.vert_attr.insert(h); return typename MeshType::template PerVertexAttributeHandle(res.first->_handle,res.first->n_attr ); } template static typename MeshType::template PerVertexAttributeHandle AddPerVertexAttribute( MeshType & m){ return AddPerVertexAttribute(m,std::string("")); } /*! \brief Try to retrieve an handle to an attribute with a given name and ATTR_TYPE \returns a invalid handle if no attribute with that name and type exists. */ template static typename MeshType::template PerVertexAttributeHandle GetPerVertexAttribute( MeshType & m, const std::string & name) { assert(!name.empty()); PointerToAttribute h1; h1._name = name; typename std::set :: iterator i; i =m.vert_attr.find(h1); if(i!=m.vert_attr.end()) if((*i)._sizeof == sizeof(ATTR_TYPE) ){ if( (*i)._padding != 0 ){ PointerToAttribute attr = (*i); // copy the PointerToAttribute m.vert_attr.erase(i); // remove it from the set FixPaddedPerVertexAttribute(m,attr); std::pair new_i = m.vert_attr.insert(attr); // insert the modified PointerToAttribute assert(new_i.second); i = new_i.first; } return typename MeshType::template PerVertexAttributeHandle((*i)._handle,(*i).n_attr); } return typename MeshType:: template PerVertexAttributeHandle(NULL,0); } template static void GetAllPerVertexAttribute(MeshType & m, std::vector &all){ all.clear(); typename std::set ::const_iterator i; for(i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i ) if(!(*i)._name.empty()) { typename MeshType:: template PerVertexAttributeHandle hh; hh = Allocator:: template GetPerVertexAttribute (m,(*i)._name); if(IsValidHandle(m,hh)) all.push_back((*i)._name); } } template static void DeletePerVertexAttribute( MeshType & m,typename MeshType::template PerVertexAttributeHandle & h){ typename std::set ::iterator i; for( i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i) if( (*i)._handle == h._handle ){ delete ((SimpleTempData*)(*i)._handle); m.vert_attr.erase(i); return;} assert(0); } // Generic DeleteAttribute. // It must not crash if you try to delete a non existing attribute, // because you do not have a way of asking for a handle of an attribute for which you do not know the type. static bool DeletePerVertexAttribute( MeshType & m, std::string name){ AttrIterator i; PointerToAttribute h1; h1._name = name; i = m.vert_attr.find(h1); if(i==m.vert_attr.end()) return false; delete ((SimpleTempDataBase*)(*i)._handle); m.vert_attr.erase(i); return true; } /// Per Edge Attributes template static bool IsValidHandle( MeshType & m, const typename MeshType::template PerEdgeAttributeHandle & a){ if(a._handle == NULL) return false; for(AttrIterator i = m.edge_attr.begin(); i!=m.edge_attr.end();++i) if ( (*i).n_attr == a.n_attr ) return true; return false; } template static typename MeshType::template PerEdgeAttributeHandle AddPerEdgeAttribute( MeshType & m, std::string name){ PAIte i; PointerToAttribute h; h._name = name; if(!name.empty()){ i = m.edge_attr.find(h); assert(i ==m.edge_attr.end() );// an attribute with this name exists } h._sizeof = sizeof(ATTR_TYPE); h._padding = 0; // h._typename = typeid(ATTR_TYPE).name(); h._handle = new SimpleTempData(m.edge); m.attrn++; h.n_attr = m.attrn; std::pair < AttrIterator , bool> res = m.edge_attr.insert(h); return typename MeshType::template PerEdgeAttributeHandle(res.first->_handle,res.first->n_attr); } template static typename MeshType::template PerEdgeAttributeHandle AddPerEdgeAttribute( MeshType & m){ return AddPerEdgeAttribute(m,std::string("")); } template static typename MeshType::template PerEdgeAttributeHandle GetPerEdgeAttribute( MeshType & m, const std::string & name){ assert(!name.empty()); PointerToAttribute h1; h1._name = name; typename std::set ::const_iterator i; i =m.edge_attr.find(h1); if(i!=m.edge_attr.end()) if((*i)._sizeof == sizeof(ATTR_TYPE) ){ if( (*i)._padding != 0 ){ PointerToAttribute attr = (*i); // copy the PointerToAttribute m.edge_attr.erase(i); // remove it from the set FixPaddedPerEdgeAttribute(m,attr); std::pair new_i = m.edge_attr.insert(attr); // insert the modified PointerToAttribute assert(new_i.second); i = new_i.first; } return typename MeshType::template PerEdgeAttributeHandle((*i)._handle,(*i).n_attr); } // if((*i)._typename == typeid(ATTR_TYPE).name() ) // return typename MeshType:: template PerVertexAttributeHandle(NULL,0); return typename MeshType:: template PerEdgeAttributeHandle(NULL,0); } template static void GetAllPerEdgeAttribute(const MeshType & m, std::vector &all){ typename std::set :: iterator i; for(i = m.edge_attr.begin(); i != m.edge_attr.end(); ++i ) if((*i)._typename == typeid(ATTR_TYPE).name()) all.push_back((*i)._name); } template static void DeletePerEdgeAttribute( MeshType & m,typename MeshType::template PerEdgeAttributeHandle & h){ typename std::set ::iterator i; for( i = m.edge_attr.begin(); i != m.edge_attr.end(); ++i) if( (*i)._handle == h._handle ){ delete ((SimpleTempData*)(*i)._handle); m.edge_attr.erase(i); return;} assert(0); } // Generic DeleteAttribute. // It must not crash if you try to delete a non existing attribute, // because you do not have a way of asking for a handle of an attribute for which you do not know the type. static bool DeletePerEdgeAttribute( MeshType & m, std::string name){ AttrIterator i; PointerToAttribute h1; h1._name = name; i = m.edge_attr.find(h1); if(i==m.edge_attr.end()) return false; delete ((SimpleTempDataBase*)(*i)._handle); m.edge_attr.erase(i); return true; } /// Per Face Attributes template static bool IsValidHandle( MeshType & m, const typename MeshType::template PerFaceAttributeHandle & a){ if(a._handle == NULL) return false; for(AttrIterator i = m.face_attr.begin(); i!=m.face_attr.end();++i) if ( (*i).n_attr == a.n_attr ) return true; return false; } template static typename MeshType::template PerFaceAttributeHandle AddPerFaceAttribute( MeshType & m, std::string name){ PAIte i; PointerToAttribute h; h._name = name; if(!name.empty()){ i = m.face_attr.find(h); assert(i ==m.face_attr.end() );// an attribute with this name exists } h._sizeof = sizeof(ATTR_TYPE); h._padding = 0; h._handle = new SimpleTempData(m.face); m.attrn++; h.n_attr = m.attrn; std::pair < AttrIterator , bool> res = m.face_attr.insert(h); return typename MeshType::template PerFaceAttributeHandle(res.first->_handle,res.first->n_attr); } template static typename MeshType::template PerFaceAttributeHandle AddPerFaceAttribute( MeshType & m){ return AddPerFaceAttribute(m,std::string("")); } template static typename MeshType::template PerFaceAttributeHandle GetPerFaceAttribute( MeshType & m, const std::string & name){ assert(!name.empty()); PointerToAttribute h1; h1._name = name; typename std::set ::iterator i; i =m.face_attr.find(h1); if(i!=m.face_attr.end()) if((*i)._sizeof == sizeof(ATTR_TYPE) ){ if( (*i)._padding != 0 ){ PointerToAttribute attr = (*i); // copy the PointerToAttribute m.face_attr.erase(i); // remove it from the set FixPaddedPerFaceAttribute(m,attr); std::pair new_i = m.face_attr.insert(attr); // insert the modified PointerToAttribute assert(new_i.second); i = new_i.first; } return typename MeshType::template PerFaceAttributeHandle((*i)._handle,(*i).n_attr); } return typename MeshType:: template PerFaceAttributeHandle(NULL,0); } template static void GetAllPerFaceAttribute(MeshType & m, std::vector &all){ all.clear(); typename std::set :: const_iterator i; for(i = m.face_attr.begin(); i != m.face_attr.end(); ++i ) if(!(*i)._name.empty()) { typename MeshType:: template PerFaceAttributeHandle hh; hh = Allocator:: template GetPerFaceAttribute (m,(*i)._name); if(IsValidHandle(m,hh)) all.push_back((*i)._name); } } template static void DeletePerFaceAttribute( MeshType & m,typename MeshType::template PerFaceAttributeHandle & h){ typename std::set ::iterator i; for( i = m.face_attr.begin(); i != m.face_attr.end(); ++i) if( (*i)._handle == h._handle ){ delete ((SimpleTempData*)(*i)._handle); m.face_attr.erase(i); return;} assert(0); } // Generic DeleteAttribute. // It must not crash if you try to delete a non existing attribute, // because you do not have a way of asking for a handle of an attribute for which you do not know the type. static bool DeletePerFaceAttribute( MeshType & m, std::string name){ AttrIterator i; PointerToAttribute h1; h1._name = name; i = m.face_attr.find(h1); if(i==m.face_attr.end()) return false; delete ((SimpleTempDataBase*)(*i)._handle); m.face_attr.erase(i); return true; } /// Per Mesh Attributes template static bool IsValidHandle( MeshType & m, const typename MeshType::template PerMeshAttributeHandle & a){ if(a._handle == NULL) return false; for(AttrIterator i = m.mesh_attr.begin(); i!=m.mesh_attr.end();++i) if ( (*i).n_attr == a.n_attr ) return true; return false; } template static typename MeshType::template PerMeshAttributeHandle AddPerMeshAttribute( MeshType & m, std::string name){ PAIte i; PointerToAttribute h; h._name = name; if(!name.empty()){ i = m.mesh_attr.find(h); assert(i ==m.mesh_attr.end() );// an attribute with this name exists } h._sizeof = sizeof(ATTR_TYPE); h._padding = 0; h._handle = new Attribute(); m.attrn++; h.n_attr = m.attrn; std::pair < AttrIterator , bool> res = m.mesh_attr.insert(h); return typename MeshType::template PerMeshAttributeHandle(res.first->_handle,res.first->n_attr); } template static typename MeshType::template PerMeshAttributeHandle GetPerMeshAttribute( MeshType & m, const std::string & name){ assert(!name.empty()); PointerToAttribute h1; h1._name = name; typename std::set ::iterator i; i =m.mesh_attr.find(h1); if(i!=m.mesh_attr.end()) if((*i)._sizeof == sizeof(ATTR_TYPE) ){ if( (*i)._padding != 0 ){ PointerToAttribute attr = (*i); // copy the PointerToAttribute m.mesh_attr.erase(i); // remove it from the set FixPaddedPerMeshAttribute(m,attr); std::pair new_i = m.mesh_attr.insert(attr); // insert the modified PointerToAttribute assert(new_i.second); i = new_i.first; } return typename MeshType::template PerMeshAttributeHandle((*i)._handle,(*i).n_attr); } return typename MeshType:: template PerMeshAttributeHandle(NULL,0); } template static void GetAllPerMeshAttribute(const MeshType & m, std::vector &all){ typename std::set :: iterator i; for(i = m.mesh_attr.begin(); i != m.mesh_attr.end(); ++i ) if((*i)._sizeof == sizeof(ATTR_TYPE)) all.push_back((*i)._name); } template static void DeletePerMeshAttribute( MeshType & m,typename MeshType::template PerMeshAttributeHandle & h){ typename std::set ::iterator i; for( i = m.mesh_attr.begin(); i != m.mesh_attr.end(); ++i) if( (*i)._handle == h._handle ){ delete (( Attribute *)(*i)._handle); m.mesh_attr.erase(i); return;} assert(0); } static void DeletePerMeshAttribute( MeshType & m, std::string name){ AttrIterator i; PointerToAttribute h1; h1._name = name; i = m.mesh_attr.find(h1); assert(i!=m.mesh_attr.end()); delete ((SimpleTempDataBase *)(*i)._handle); m.mesh_attr.erase(i); } template static void FixPaddedPerVertexAttribute (MeshType & m, PointerToAttribute & pa){ // create the container of the right type SimpleTempData* _handle = new SimpleTempData(m.vert); // copy the padded container in the new one _handle->Resize(m.vert.size()); for(unsigned int i = 0; i < m.vert.size(); ++i){ ATTR_TYPE * dest = &(*_handle)[i]; char * ptr = (char*)( ((SimpleTempDataBase *)pa._handle)->DataBegin()); memcpy((void*)dest , (void*) &(ptr[i * pa._sizeof ]) ,sizeof(ATTR_TYPE)); } // remove the padded container delete ((SimpleTempDataBase*) pa._handle); // update the pointer to data pa._sizeof = sizeof(ATTR_TYPE); // update the pointer to data pa._handle = _handle; // zero the padding pa._padding = 0; } template static void FixPaddedPerEdgeAttribute (MeshType & m, PointerToAttribute & pa){ // create the container of the right type SimpleTempData* _handle = new SimpleTempData(m.edge); // copy the padded container in the new one _handle->Resize(m.edge.size()); for(unsigned int i = 0; i < m.edge.size(); ++i){ ATTR_TYPE * dest = &(*_handle)[i]; char * ptr = (char*)( ((SimpleTempDataBase *)pa._handle)->DataBegin()); memcpy((void*)dest , (void*) &(ptr[i * pa._sizeof ]) ,sizeof(ATTR_TYPE)); } // remove the padded container delete ((SimpleTempDataBase*) pa._handle); // update the pointer to data pa._sizeof = sizeof(ATTR_TYPE); // update the pointer to data pa._handle = _handle; // zero the padding pa._padding = 0; } template static void FixPaddedPerFaceAttribute ( MeshType & m,PointerToAttribute & pa){ // create the container of the right type SimpleTempData* _handle = new SimpleTempData(m.face); // copy the padded container in the new one _handle->Resize(m.face.size()); for(unsigned int i = 0; i < m.face.size(); ++i){ ATTR_TYPE * dest = &(*_handle)[i]; char * ptr = (char*)( ((SimpleTempDataBase *)pa._handle)->DataBegin()); memcpy((void*)dest , (void*) &(ptr[i * pa._sizeof ]) ,sizeof(ATTR_TYPE)); } // remove the padded container delete ((SimpleTempDataBase*) pa._handle); // update the pointer to data pa._sizeof = sizeof(ATTR_TYPE); // update the pointer to data pa._handle = _handle; // zero the padding pa._padding = 0; } template static void FixPaddedPerMeshAttribute ( MeshType & /* m */,PointerToAttribute & pa){ // create the container of the right type Attribute * _handle = new Attribute(); // copy the padded container in the new one char * ptr = (char*)( ((Attribute *)pa._handle)->DataBegin()); memcpy((void*)_handle->attribute ,(void*) &(ptr[0]) ,sizeof(ATTR_TYPE)); // remove the padded container delete ( (Attribute *) pa._handle); // update the pointer to data pa._sizeof = sizeof(ATTR_TYPE); // update the pointer to data pa._handle = _handle; // zero the padding pa._padding = 0; } }; // end class /*@}*/ } // End Namespace TriMesh } // End Namespace vcg #endif