/**************************************************************************** * 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 #include #include #include namespace vcg { namespace tri { /** \addtogroup trimesh */ template size_t Index(MeshType &m, typename MeshType::VertexType &v) {return &v-&*m.vert.begin();} template size_t Index(MeshType &m, typename MeshType::FaceType &f) {return &f-&*m.face.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();} // Placeholder. // this one is called by the Compact and overridden by more specialized functions for OCF classes. // that manage also the additional types template void ReorderFace( std::vector & /*newVertIndex*/, std::vector & /*vert*/) {} template void ReorderVert( std::vector &/*newVertIndex*/, std::vector &/*vert*/) {} 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(m.vn); } /*@{*/ /// Class to safely add vertexes and faces to a mesh updating all the involved pointers. /// It provides static memeber to add either vertex or faces to a trimesh. template class Allocator { public: typedef AllocateMeshType MeshType; 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::PointerToAttribute PtrToAttr; typedef typename std::set::iterator AttrIterator; typedef typename std::set::const_iterator AttrConstIterator; typedef typename std::set::iterator PAIte; /** 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); */ template class PointerUpdater { public: PointerUpdater(void) : newBase(0), oldBase(0), newEnd(0), oldEnd(0), preventUpdateFlag(false) { ; } void Clear(){newBase=oldBase=newEnd=oldEnd=0;}; void Update(SimplexPointerType &vp) { if(vp>=newBase && vp=oldBase); assert(vp &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) ((PtrToAttr)(*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(HasHEVAdjacency(m)) pu.Update((*ei).HEVp()); } // 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; } /** Function to add n vertices to the mesh. First wrapper, with no parameters */ static VertexIterator AddVertices(MeshType &m, int n) { PointerUpdater pu; return AddVertices(m, n,pu); } /** Function to add n vertices to the mesh. Second Wrapper, with a vector of vertex 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; } /** Function to add n edges 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. @param n number of edges to be added @param local_var vector of pointers to pointers to edges to be updated. return an 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::PtrToAttr)(*ai)).Resize(m.edge.size()); pu.newBase = &*m.edge.begin(); pu.newEnd = &m.edge.back()+1; if(pu.NeedUpdate()) { int ii = 0; 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; for (vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if(!(*vi).IsD()) if ((*vi).cVEp()!=0) pu.Update((*vi).VEp()); EdgeIterator ei = m.edge.begin(); while(ii < m.en - n){// cycle on all the faces except the new ones if(!(*ei).IsD()) { if(HasHENextAdjacency(m)) pu.Update((*ei).HENp()); if(HasHEPrevAdjacency(m)) pu.Update((*ei).HEPp()); if(HasHEOppAdjacency(m)) pu.Update((*ei).HEOp()); ++ii; } ++ei; } // e poiche' lo spazio e' cambiato si ricalcola anche last da zero } 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 vertices 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 vertices 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; } /** 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) ((PtrToAttr)(*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 &newVertIndex ) { for(unsigned int i=0;i(newVertIndex,m.vert); // reorder the optional atttributes in m.vert_attr to reflect the changes ReorderAttribute(m.vert_attr,newVertIndex,m); m.vert.resize(m.vn); // resize the optional atttributes in m.vert_attr to reflect the changes ResizeAttribute(m.vert_attr,m.vn,m); FaceIterator fi; VertexPointer vbase=&m.vert[0]; for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) for(unsigned int i=0;i<3;++i) { size_t oldIndex = (*fi).V(i) - vbase; assert(vbase <= (*fi).V(i) && oldIndex < newVertIndex.size()); (*fi).V(i) = vbase+newVertIndex[oldIndex]; } } /* Function to compact all the vertices that have been deleted and put them to the end of the vector. after this pass the isD test in the scanning of vertex vector, is no more strongly necessary. It should not be called when TemporaryData is active; */ static void CompactVertexVector( MeshType &m ) { // 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; std::vector newVertIndex(m.vert.size(),std::numeric_limits::max() ); size_t pos=0; size_t i=0; for(i=0;i ] gives you the new position of the face in the vector; std::vector newFaceIndex(m.face.size(),std::numeric_limits::max() ); size_t pos=0; size_t i=0; for(i=0;i(newFaceIndex,m.face); // reorder the optional atttributes in m.face_attr to reflect the changes ReorderAttribute(m.face_attr,newFaceIndex,m); // Loop on the vertices to correct VF relation VertexIterator vi; FacePointer fbase=&m.face[0]; for (vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if(!(*vi).IsD()) { if(HasVFAdjacency(m)) if ((*vi).cVFp()!=0) { size_t oldIndex = (*vi).cVFp() - fbase; assert(fbase <= (*vi).cVFp() && oldIndex < newFaceIndex.size()); (*vi).VFp() = fbase+newFaceIndex[oldIndex]; } } // Loop on the faces to correct VF and FF relations m.face.resize(m.fn); // resize the optional atttributes in m.face_attr to reflect the changes ResizeAttribute(m.face_attr,m.vn,m); FaceIterator fi; for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) { if(HasVFAdjacency(m)) for(i=0;i<3;++i) if ((*fi).cVFp(i)!=0) { size_t oldIndex = (*fi).VFp(i) - fbase; assert(fbase <= (*fi).VFp(i) && oldIndex < newFaceIndex.size()); (*fi).VFp(i) = fbase+newFaceIndex[oldIndex]; } if(HasFFAdjacency(m)) for(i=0;i<3;++i) if ((*fi).cFFp(i)!=0) { size_t oldIndex = (*fi).FFp(i) - fbase; assert(fbase <= (*fi).FFp(i) && oldIndex < newFaceIndex.size()); (*fi).FFp(i) = fbase+newFaceIndex[oldIndex]; } } } public: /// Per Vertex Attributes 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; } template static typename MeshType::template PerVertexAttributeHandle AddPerVertexAttribute( MeshType & m, std::string name){ PAIte i; PtrToAttr 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 = (void*) 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("")); } template static typename MeshType::template PerVertexAttributeHandle GetPerVertexAttribute( MeshType & m, const std::string & name){ assert(!name.empty()); PtrToAttr h1; h1._name = name; typename std::set :: iterator i; i =m.vert_attr.find(h1); if(i!=m.vert_attr.end()){ if( (*i)._padding != 0 ){ PtrToAttr 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); } else return typename MeshType:: template PerVertexAttributeHandle(NULL,0); } 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); } static void DeletePerVertexAttribute( MeshType & m, std::string name){ AttrIterator i; PtrToAttr h1; h1._name = name; i = m.vert_attr.find(h1); assert(i!=m.vert_attr.end()); delete ((SimpleTempDataBase*)(*i)._handle); m.vert_attr.erase(i); } /// 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; PtrToAttr 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._handle = (void*) 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 PerVertexAttributeHandle AddPerEdgeAttribute( MeshType & m){ return AddPerEdgeAttribute(m,std::string("")); } template static typename MeshType::template PerEdgeAttributeHandle GetPerEdgeAttribute( const MeshType & m, const std::string & name){ assert(!name.empty()); PtrToAttr h1; h1._name = name; typename std::set ::const_iterator i; i =m.edge_attr.find(h1); if(i!=m.edge_attr.end()) return typename MeshType::template PerFaceAttributeHandle((*i)._handle,(*i).n_attr); else return typename MeshType:: template PerFaceAttributeHandle(NULL,0); } 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); } static void DeletePerEdgeAttribute( MeshType & m, std::string name){ AttrIterator i; PtrToAttr h1; h1._name = name; i = m.edge_attr.find(h1); assert(i!=m.edge_attr.end()); delete ((SimpleTempDataBase*)(*i)._handle); m.edge_attr.erase(i); } /// 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; PtrToAttr 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._handle = (void*) 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()); PtrToAttr h1; h1._name = name; typename std::set ::iterator i; i =m.face_attr.find(h1); if(i!=m.face_attr.end()){ if( (*i)._padding != 0 ){ PtrToAttr 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); } else return typename MeshType:: template PerFaceAttributeHandle(NULL,0); } 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); } static void DeletePerFaceAttribute( MeshType & m, std::string name){ AttrIterator i; PtrToAttr h1; h1._name = name; i = m.face_attr.find(h1); assert(i!=m.face_attr.end()); delete ((SimpleTempDataBase*)(*i)._handle); m.face_attr.erase(i); } /// 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; PtrToAttr 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._handle = (void*) 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()); PtrToAttr h1; h1._name = name; typename std::set ::iterator i; i =m.mesh_attr.find(h1); if(i!=m.mesh_attr.end()){ if( (*i)._padding != 0 ){ PtrToAttr 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); } else return typename MeshType:: template PerMeshAttributeHandle(NULL,0); } 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; PtrToAttr h1; h1._name = name; i = m.mesh_attr.find(h1); assert(i!=m.mesh_attr.end()); delete ((AttributeBase *)(*i)._handle); m.mesh_attr.erase(i); } template static void FixPaddedPerVertexAttribute ( MeshType & m,PtrToAttr & 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 FixPaddedPerFaceAttribute ( MeshType & m,PtrToAttr & 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,PtrToAttr & pa){ // create the container of the right type Attribute * _handle = new Attribute(); // copy the padded container in the new one ATTR_TYPE * dest = _handle->attribute; 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