From 90077c02dce530156652bd79f130e2059344bfeb Mon Sep 17 00:00:00 2001 From: "T.Alderighi" Date: Wed, 11 Jul 2018 14:53:20 +0200 Subject: [PATCH] added edgemeshconnectedcomponent and relative iterator --- vcg/complex/algorithms/clean.h | 3569 ++++++++++++++++---------------- vcg/complex/base.h | 896 ++++---- vcg/simplex/edge/component.h | 378 ++-- 3 files changed, 2488 insertions(+), 2355 deletions(-) diff --git a/vcg/complex/algorithms/clean.h b/vcg/complex/algorithms/clean.h index 9534cb48..53f99093 100644 --- a/vcg/complex/algorithms/clean.h +++ b/vcg/complex/algorithms/clean.h @@ -37,59 +37,121 @@ namespace vcg { namespace tri{ +template +class EdgeConnectedComponentIterator +{ +public: + typedef ConnectedEdgeMeshType MeshType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::EdgeType EdgeType; + typedef typename MeshType::EdgePointer EdgePointer; + typedef typename MeshType::EdgeIterator EdgeIterator; + typedef typename MeshType::ConstEdgeIterator ConstEdgeIterator; + typedef typename MeshType::EdgeContainer EdgeContainer; + +public: + void operator ++() + { + EdgePointer ep = se.top(); + se.pop(); + for(int i = 0; i < 2; ++i) + { + edge::VEIterator vei(ep->V(i)); + while (!vei.End()) + { + if (!tri::IsMarked(*mp, vei.E())) + { + tri::Mark(*mp, vei.E()); + se.push(vei.E()); + } + ++vei; + } + } + } + + void start(MeshType &m, EdgePointer e) + { + tri::RequirePerEdgeMark(m); + mp=&m; + + while(!se.empty()) + se.pop(); + + UnMarkAll(m); + + tri::Mark(m, e); + se.push(e); + } + + bool completed() { + return se.empty(); + } + + EdgePointer operator *() + { + return se.top(); + } +private: + std::stack se; + MeshType *mp; +}; + template class ConnectedComponentIterator { public: - typedef ConnectedMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ConstFaceIterator ConstFaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; + typedef ConnectedMeshType MeshType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::FacePointer FacePointer; + typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::ConstFaceIterator ConstFaceIterator; + typedef typename MeshType::FaceContainer FaceContainer; public: - void operator ++() - { - FacePointer fpt=sf.top(); - sf.pop(); - for(int j=0; jVN(); ++j) - if( !face::IsBorder(*fpt,j) ) - { - FacePointer l=fpt->FFp(j); - if( !tri::IsMarked(*mp,l) ) - { - tri::Mark(*mp,l); - sf.push(l); - } - } - } + void operator ++() + { + FacePointer fpt=sf.top(); + sf.pop(); + for(int j=0; jVN(); ++j) + if( !face::IsBorder(*fpt,j) ) + { + FacePointer l=fpt->FFp(j); + if( !tri::IsMarked(*mp,l) ) + { + tri::Mark(*mp,l); + sf.push(l); + } + } + } - void start(MeshType &m, FacePointer p) - { - tri::RequirePerFaceMark(m); - mp=&m; - while(!sf.empty()) sf.pop(); - UnMarkAll(m); - tri::Mark(m,p); - sf.push(p); - } + void start(MeshType &m, FacePointer p) + { + tri::RequirePerFaceMark(m); + mp=&m; + while(!sf.empty()) sf.pop(); + UnMarkAll(m); + tri::Mark(m,p); + sf.push(p); + } - bool completed() { - return sf.empty(); - } + bool completed() { + return sf.empty(); + } - FacePointer operator *() - { - return sf.top(); - } + FacePointer operator *() + { + return sf.top(); + } private: - std::stack sf; - MeshType *mp; + std::stack sf; + MeshType *mp; }; @@ -102,693 +164,693 @@ class Clean { public: - typedef CleanMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ConstVertexIterator ConstVertexIterator; - typedef typename MeshType::EdgeIterator EdgeIterator; - typedef typename MeshType::EdgePointer EdgePointer; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ConstFaceIterator ConstFaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - typedef typename MeshType::TetraType TetraType; - typedef typename MeshType::TetraPointer TetraPointer; - typedef typename MeshType::TetraIterator TetraIterator; - typedef typename MeshType::ConstTetraIterator ConstTetraIterator; - - typedef typename vcg::Box3 Box3Type; - - typedef GridStaticPtr TriMeshGrid; - - /* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/ - class RemoveDuplicateVert_Compare{ - public: - inline bool operator()(VertexPointer const &a, VertexPointer const &b) - { - return ((*a).cP() == (*b).cP()) ? (a mp; - size_t i,j; - VertexIterator vi; - int deleted=0; - int k=0; - size_t num_vert = m.vert.size(); - std::vector perm(num_vert); - for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi, ++k) - perm[k] = &(*vi); - - RemoveDuplicateVert_Compare c_obj; - - std::sort(perm.begin(),perm.end(),c_obj); - - j = 0; - i = j; - mp[perm[i]] = perm[j]; - ++i; - for(;i!=num_vert;) - { - if( (! (*perm[i]).IsD()) && - (! (*perm[j]).IsD()) && - (*perm[i]).P() == (*perm[j]).cP() ) - { - VertexPointer t = perm[i]; - mp[perm[i]] = perm[j]; - ++i; - Allocator::DeleteVertex(m,*t); - deleted++; - } - else - { - j = i; - ++i; - } - } - - for(FaceIterator fi = m.face.begin(); fi!=m.face.end(); ++fi) - if( !(*fi).IsD() ) - for(k = 0; k < (*fi).VN(); ++k) - if( mp.find( (typename MeshType::VertexPointer)(*fi).V(k) ) != mp.end() ) - { - (*fi).V(k) = &*mp[ (*fi).V(k) ]; - } - - - for(EdgeIterator ei = m.edge.begin(); ei!=m.edge.end(); ++ei) - if( !(*ei).IsD() ) - for(k = 0; k < 2; ++k) - if( mp.find( (typename MeshType::VertexPointer)(*ei).V(k) ) != mp.end() ) - { - (*ei).V(k) = &*mp[ (*ei).V(k) ]; - } - - for (TetraIterator ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) - if (!(*ti).IsD()) - for (k = 0; k < 4; ++k) - if (mp.find((typename MeshType::VertexPointer)(*ti).V(k)) != mp.end()) - (*ti).V(k) = &*mp[ (*ti).V(k) ]; - - if(RemoveDegenerateFlag) RemoveDegenerateFace(m); - if(RemoveDegenerateFlag && m.en>0) { - RemoveDegenerateEdge(m); - RemoveDuplicateEdge(m); - } - return deleted; - } - - class SortedPair - { - public: - SortedPair() {} - SortedPair(unsigned int v0, unsigned int v1, EdgePointer _fp) - { - v[0]=v0;v[1]=v1; - fp=_fp; - if(v[0]>v[1]) std::swap(v[0],v[1]); - } - bool operator < (const SortedPair &p) const - { - return (v[1]!=p.v[1])?(v[1] fvec; - for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - { - fvec.push_back(SortedTriple( tri::Index(m,(*fi).V(0)), - tri::Index(m,(*fi).V(1)), - tri::Index(m,(*fi).V(2)), - &*fi)); - } - std::sort(fvec.begin(),fvec.end()); - int total=0; - for(int i=0;i::DeleteFace(m, *(fvec[i].fp) ); - } - } - return total; - } - - /** This function removes all duplicate faces of the mesh by looking only at their vertex reference. - So it should be called after unification of vertices. - Note that it does not update any topology relation that could be affected by this like the VT or TT relation. - the reason this function is usually performed BEFORE building any topology information. - */ - static int RemoveDuplicateEdge( MeshType & m) // V1.0 - { - if (m.en==0) return 0; - std::vector eVec; - for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei) - if(!(*ei).IsD()) - { - eVec.push_back(SortedPair( tri::Index(m,(*ei).V(0)), tri::Index(m,(*ei).V(1)), &*ei)); - } - std::sort(eVec.begin(),eVec.end()); - int total=0; - for(int i=0;i::DeleteEdge(m, *(eVec[i].fp) ); - } - } - return total; - } - - static int CountUnreferencedVertex( MeshType& m) - { - return RemoveUnreferencedVertex(m,false); - } - - - /** This function removes vertices that are not referenced by any face or by any edge. - @param m The mesh - @param DeleteVertexFlag if false prevent the vertex deletion and just count it. - @return The number of removed vertices - */ - static int RemoveUnreferencedVertex( MeshType& m, bool DeleteVertexFlag=true) // V1.0 - { - tri::RequirePerVertexFlags(m); - - std::vector referredVec(m.vert.size(),false); - int deleted = 0; - - for(auto fi = m.face.begin(); fi != m.face.end(); ++fi) - if( !(*fi).IsD() ) - for(auto j=0; j < (*fi).VN(); ++j) - referredVec[tri::Index(m, (*fi).V(j))]=true; - - for(auto ei=m.edge.begin();ei!=m.edge.end();++ei) - if( !(*ei).IsD() ){ - referredVec[tri::Index(m, (*ei).V(0))]=true; - referredVec[tri::Index(m, (*ei).V(1))]=true; - } - - for(auto ti=m.tetra.begin(); ti!=m.tetra.end();++ti) - if( !(*ti).IsD() ){ - referredVec[tri::Index(m, (*ti).V(0))]=true; - referredVec[tri::Index(m, (*ti).V(1))]=true; - referredVec[tri::Index(m, (*ti).V(2))]=true; - referredVec[tri::Index(m, (*ti).V(3))]=true; - } - - - if(!DeleteVertexFlag) - return std::count(referredVec.begin(),referredVec.end(),true); - - for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) - if( (!(*vi).IsD()) && (!referredVec[tri::Index(m,*vi)]) ) - { - Allocator::DeleteVertex(m,*vi); - ++deleted; - } - return deleted; - } - - /** - Degenerate vertices are vertices that have coords with invalid floating point values, - All the faces incident on deleted vertices are also deleted - */ - static int RemoveDegenerateVertex(MeshType& m) - { - VertexIterator vi; - int count_vd = 0; - - for(vi=m.vert.begin(); vi!=m.vert.end();++vi) - if(math::IsNAN( (*vi).P()[0]) || - math::IsNAN( (*vi).P()[1]) || - math::IsNAN( (*vi).P()[2]) ) - { - count_vd++; - Allocator::DeleteVertex(m,*vi); - } - - FaceIterator fi; - int count_fd = 0; - - for(fi=m.face.begin(); fi!=m.face.end();++fi) - if(!(*fi).IsD()) - if( (*fi).V(0)->IsD() || - (*fi).V(1)->IsD() || - (*fi).V(2)->IsD() ) - { - count_fd++; - Allocator::DeleteFace(m,*fi); - } - return count_vd; - } - - /** - Degenerate faces are faces that are Topologically degenerate, - i.e. have two or more vertex reference that link the same vertex - (and not only two vertexes with the same coordinates). - All Degenerate faces are zero area faces BUT not all zero area faces are degenerate. - We do not take care of topology because when we have degenerate faces the - topology calculation functions crash. - */ - static int RemoveDegenerateFace(MeshType& m) - { - int count_fd = 0; - - for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) - if(!(*fi).IsD()) - { - if((*fi).V(0) == (*fi).V(1) || - (*fi).V(0) == (*fi).V(2) || - (*fi).V(1) == (*fi).V(2) ) - { - count_fd++; - Allocator::DeleteFace(m,*fi); - } - } - return count_fd; - } - - static int RemoveDegenerateEdge(MeshType& m) - { - int count_ed = 0; - - for(EdgeIterator ei=m.edge.begin(); ei!=m.edge.end();++ei) - if(!(*ei).IsD()) - { - if((*ei).V(0) == (*ei).V(1) ) - { - count_ed++; - Allocator::DeleteEdge(m,*ei); - } - } - return count_ed; - } - - static int RemoveNonManifoldVertex(MeshType& m) - { - CountNonManifoldVertexFF(m,true); - tri::UpdateSelection::FaceFromVertexLoose(m); - int count_removed = 0; - for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) - if(!(*fi).IsD() && (*fi).IsS()) - Allocator::DeleteFace(m,*fi); - for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi) - if(!(*vi).IsD() && (*vi).IsS()) { - ++count_removed; - Allocator::DeleteVertex(m,*vi); - } - return count_removed; - } - - - static int SplitSelectedVertexOnEdgeMesh(MeshType& m) - { - tri::RequireCompactness(m); - - // count selected vertices references - std::unordered_map refCount; // selected vertex index -> reference count - size_t countSplit = 0; - for (size_t i=0; iIsS()) - { - const size_t refs = ++refCount[Index(m, m.edge[i].V(j))]; - if (refs > 1) { - countSplit++; - } - } - } - } - // actual split - if (countSplit > 0) - { - auto newVertIt = tri::Allocator::AddVertices(m, countSplit); - for (size_t i=0; iIsS()) - { - if (--refCount[vIdx] > 0) - { - newVertIt->ImportData(*vp); - m.edge[i].V(j) = &*(newVertIt++); - } - } - } - } - } - return int(countSplit); - } - - - static void SelectNonManifoldVertexOnEdgeMesh(MeshType &m) - { - tri::RequireCompactness(m); - tri::UpdateSelection::VertexClear(m); - std::vector cnt(m.vn,0); - - for(size_t i=0;i2) m.vert[i].SetS(); - } - - static void SelectCreaseVertexOnEdgeMesh(MeshType &m, ScalarType AngleRadThr) - { - tri::RequireCompactness(m); - tri::RequireVEAdjacency(m); - tri::UpdateTopology::VertexEdge(m); - tri::UpdateSelection::VertexClear(m); - for(size_t i=0;i VVStarVec; - edge::VVStarVE(&(m.vert[i]),VVStarVec); - if(VVStarVec.size()==2) - { - CoordType v0 = m.vert[i].P() - VVStarVec[0]->P(); - CoordType v1 = m.vert[i].P() - VVStarVec[1]->P(); - float angle = M_PI-vcg::Angle(v0,v1); - if(angle > AngleRadThr) m.vert[i].SetS(); - } - } - } - - - /// Removal of faces that were incident on a non manifold edge. - - // Given a mesh with FF adjacency - // it search for non manifold vertices and duplicate them. - // Duplicated vertices are moved apart according to the move threshold param. - // that is a percentage of the average vector from the non manifold vertex to the barycenter of the incident faces. - - static int SplitNonManifoldVertex(MeshType& m, ScalarType moveThreshold) - { - RequireFFAdjacency(m); - typedef std::pair FaceInt; // a face and the index of the vertex that we have to change - // - std::vector > >ToSplitVec; - - SelectionStack ss(m); - ss.push(); - CountNonManifoldVertexFF(m,true); - UpdateFlags::VertexClearV(m); - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - for (int i=0; iVN(); i++) - if ((*fi).V(i)->IsS() && !(*fi).V(i)->IsV()) - { - (*fi).V(i)->SetV(); - face::Pos startPos(&*fi,i); - face::Pos curPos = startPos; - std::set faceSet; - do - { - faceSet.insert(std::make_pair(curPos.F(),curPos.VInd())); - curPos.NextE(); - } while (curPos != startPos); - - ToSplitVec.push_back(make_pair((*fi).V(i),std::vector())); - - typename std::set::const_iterator iii; - - for(iii=faceSet.begin();iii!=faceSet.end();++iii) - ToSplitVec.back().second.push_back(*iii); - } - } - ss.pop(); - // Second step actually add new vertices and split them. - typename tri::Allocator::template PointerUpdater pu; - VertexIterator firstVp = tri::Allocator::AddVertices(m,ToSplitVec.size(),pu); - for(size_t i =0;iImportData(*np); - // loop on the face to be changed, and also compute the movement vector; - CoordType delta(0,0,0); - for(size_t j=0;jV(ff.second)=&*firstVp; - delta+=Barycenter(*(ff.first))-np->cP(); - } - delta /= ToSplitVec[i].second.size(); - firstVp->P() = firstVp->P() + delta * moveThreshold; - firstVp++; - } - - return int(ToSplitVec.size()); - } - - - // Auxiliary function for sorting the non manifold faces according to their area. Used in RemoveNonManifoldFace - struct CompareAreaFP { - bool operator ()(FacePointer const& f1, FacePointer const& f2) const { - return DoubleArea(*f1) < DoubleArea(*f2); - } - }; - - /// Removal of faces that were incident on a non manifold edge. - static int RemoveNonManifoldFace(MeshType& m) - { - FaceIterator fi; - int count_fd = 0; - std::vector ToDelVec; - - for(fi=m.face.begin(); fi!=m.face.end();++fi) - if (!fi->IsD()) - { - if ((!IsManifold(*fi,0))|| - (!IsManifold(*fi,1))|| - (!IsManifold(*fi,2))) - ToDelVec.push_back(&*fi); - } - - std::sort(ToDelVec.begin(),ToDelVec.end(),CompareAreaFP()); - - for(size_t i=0;iIsD()) - { - FaceType &ff= *ToDelVec[i]; - if ((!IsManifold(ff,0))|| - (!IsManifold(ff,1))|| - (!IsManifold(ff,2))) - { - for(int j=0;j<3;++j) - if(!face::IsBorder(ff,j)) - vcg::face::FFDetach(ff,j); - - Allocator::DeleteFace(m,ff); - count_fd++; - } - } - } - return count_fd; - } - - /* Remove the faces that are out of a given range of area */ - static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)(), bool OnlyOnSelected=false) - { - int count_fd = 0; - MinAreaThr*=2; - MaxAreaThr*=2; - for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi){ - if(!(*fi).IsD()) - if(!OnlyOnSelected || (*fi).IsS()) - { - const ScalarType doubleArea=DoubleArea(*fi); - if((doubleArea<=MinAreaThr) || (doubleArea>=MaxAreaThr) ) - { - Allocator::DeleteFace(m,*fi); - count_fd++; - } - } - } - return count_fd; - } - - static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m,0);} - - - - /** - * Is the mesh only composed by quadrilaterals? - */ - static bool IsBitQuadOnly(const MeshType &m) - { - typedef typename MeshType::FaceType F; - tri::RequirePerFaceFlags(m); - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->Flags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp != F::FAUX0 && tmp != F::FAUX1 && tmp != F::FAUX2) return false; - } - return true; - } - - - static bool IsFaceFauxConsistent(MeshType &m) - { - RequirePerFaceFlags(m); - RequireFFAdjacency(m); - for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - for(int z=0;z<(*fi).VN();++z) - { - FacePointer fp = fi->FFp(z); - int zp = fi->FFi(z); - if(fi->IsF(z) != fp->IsF(zp)) return false; - } - } - return true; - } - - /** + typedef CleanMeshType MeshType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::ConstVertexIterator ConstVertexIterator; + typedef typename MeshType::EdgeIterator EdgeIterator; + typedef typename MeshType::EdgePointer EdgePointer; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::FacePointer FacePointer; + typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::ConstFaceIterator ConstFaceIterator; + typedef typename MeshType::FaceContainer FaceContainer; + typedef typename MeshType::TetraType TetraType; + typedef typename MeshType::TetraPointer TetraPointer; + typedef typename MeshType::TetraIterator TetraIterator; + typedef typename MeshType::ConstTetraIterator ConstTetraIterator; + + typedef typename vcg::Box3 Box3Type; + + typedef GridStaticPtr TriMeshGrid; + + /* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/ + class RemoveDuplicateVert_Compare{ + public: + inline bool operator()(VertexPointer const &a, VertexPointer const &b) + { + return ((*a).cP() == (*b).cP()) ? (a mp; + size_t i,j; + VertexIterator vi; + int deleted=0; + int k=0; + size_t num_vert = m.vert.size(); + std::vector perm(num_vert); + for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi, ++k) + perm[k] = &(*vi); + + RemoveDuplicateVert_Compare c_obj; + + std::sort(perm.begin(),perm.end(),c_obj); + + j = 0; + i = j; + mp[perm[i]] = perm[j]; + ++i; + for(;i!=num_vert;) + { + if( (! (*perm[i]).IsD()) && + (! (*perm[j]).IsD()) && + (*perm[i]).P() == (*perm[j]).cP() ) + { + VertexPointer t = perm[i]; + mp[perm[i]] = perm[j]; + ++i; + Allocator::DeleteVertex(m,*t); + deleted++; + } + else + { + j = i; + ++i; + } + } + + for(FaceIterator fi = m.face.begin(); fi!=m.face.end(); ++fi) + if( !(*fi).IsD() ) + for(k = 0; k < (*fi).VN(); ++k) + if( mp.find( (typename MeshType::VertexPointer)(*fi).V(k) ) != mp.end() ) + { + (*fi).V(k) = &*mp[ (*fi).V(k) ]; + } + + + for(EdgeIterator ei = m.edge.begin(); ei!=m.edge.end(); ++ei) + if( !(*ei).IsD() ) + for(k = 0; k < 2; ++k) + if( mp.find( (typename MeshType::VertexPointer)(*ei).V(k) ) != mp.end() ) + { + (*ei).V(k) = &*mp[ (*ei).V(k) ]; + } + + for (TetraIterator ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) + if (!(*ti).IsD()) + for (k = 0; k < 4; ++k) + if (mp.find((typename MeshType::VertexPointer)(*ti).V(k)) != mp.end()) + (*ti).V(k) = &*mp[ (*ti).V(k) ]; + + if(RemoveDegenerateFlag) RemoveDegenerateFace(m); + if(RemoveDegenerateFlag && m.en>0) { + RemoveDegenerateEdge(m); + RemoveDuplicateEdge(m); + } + return deleted; + } + + class SortedPair + { + public: + SortedPair() {} + SortedPair(unsigned int v0, unsigned int v1, EdgePointer _fp) + { + v[0]=v0;v[1]=v1; + fp=_fp; + if(v[0]>v[1]) std::swap(v[0],v[1]); + } + bool operator < (const SortedPair &p) const + { + return (v[1]!=p.v[1])?(v[1] fvec; + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + { + fvec.push_back(SortedTriple( tri::Index(m,(*fi).V(0)), + tri::Index(m,(*fi).V(1)), + tri::Index(m,(*fi).V(2)), + &*fi)); + } + std::sort(fvec.begin(),fvec.end()); + int total=0; + for(int i=0;i::DeleteFace(m, *(fvec[i].fp) ); + } + } + return total; + } + + /** This function removes all duplicate faces of the mesh by looking only at their vertex reference. + So it should be called after unification of vertices. + Note that it does not update any topology relation that could be affected by this like the VT or TT relation. + the reason this function is usually performed BEFORE building any topology information. + */ + static int RemoveDuplicateEdge( MeshType & m) // V1.0 + { + if (m.en==0) return 0; + std::vector eVec; + for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei) + if(!(*ei).IsD()) + { + eVec.push_back(SortedPair( tri::Index(m,(*ei).V(0)), tri::Index(m,(*ei).V(1)), &*ei)); + } + std::sort(eVec.begin(),eVec.end()); + int total=0; + for(int i=0;i::DeleteEdge(m, *(eVec[i].fp) ); + } + } + return total; + } + + static int CountUnreferencedVertex( MeshType& m) + { + return RemoveUnreferencedVertex(m,false); + } + + + /** This function removes vertices that are not referenced by any face or by any edge. + @param m The mesh + @param DeleteVertexFlag if false prevent the vertex deletion and just count it. + @return The number of removed vertices + */ + static int RemoveUnreferencedVertex( MeshType& m, bool DeleteVertexFlag=true) // V1.0 + { + tri::RequirePerVertexFlags(m); + + std::vector referredVec(m.vert.size(),false); + int deleted = 0; + + for(auto fi = m.face.begin(); fi != m.face.end(); ++fi) + if( !(*fi).IsD() ) + for(auto j=0; j < (*fi).VN(); ++j) + referredVec[tri::Index(m, (*fi).V(j))]=true; + + for(auto ei=m.edge.begin();ei!=m.edge.end();++ei) + if( !(*ei).IsD() ){ + referredVec[tri::Index(m, (*ei).V(0))]=true; + referredVec[tri::Index(m, (*ei).V(1))]=true; + } + + for(auto ti=m.tetra.begin(); ti!=m.tetra.end();++ti) + if( !(*ti).IsD() ){ + referredVec[tri::Index(m, (*ti).V(0))]=true; + referredVec[tri::Index(m, (*ti).V(1))]=true; + referredVec[tri::Index(m, (*ti).V(2))]=true; + referredVec[tri::Index(m, (*ti).V(3))]=true; + } + + + if(!DeleteVertexFlag) + return std::count(referredVec.begin(),referredVec.end(),true); + + for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) + if( (!(*vi).IsD()) && (!referredVec[tri::Index(m,*vi)]) ) + { + Allocator::DeleteVertex(m,*vi); + ++deleted; + } + return deleted; + } + + /** + Degenerate vertices are vertices that have coords with invalid floating point values, + All the faces incident on deleted vertices are also deleted + */ + static int RemoveDegenerateVertex(MeshType& m) + { + VertexIterator vi; + int count_vd = 0; + + for(vi=m.vert.begin(); vi!=m.vert.end();++vi) + if(math::IsNAN( (*vi).P()[0]) || + math::IsNAN( (*vi).P()[1]) || + math::IsNAN( (*vi).P()[2]) ) + { + count_vd++; + Allocator::DeleteVertex(m,*vi); + } + + FaceIterator fi; + int count_fd = 0; + + for(fi=m.face.begin(); fi!=m.face.end();++fi) + if(!(*fi).IsD()) + if( (*fi).V(0)->IsD() || + (*fi).V(1)->IsD() || + (*fi).V(2)->IsD() ) + { + count_fd++; + Allocator::DeleteFace(m,*fi); + } + return count_vd; + } + + /** + Degenerate faces are faces that are Topologically degenerate, + i.e. have two or more vertex reference that link the same vertex + (and not only two vertexes with the same coordinates). + All Degenerate faces are zero area faces BUT not all zero area faces are degenerate. + We do not take care of topology because when we have degenerate faces the + topology calculation functions crash. + */ + static int RemoveDegenerateFace(MeshType& m) + { + int count_fd = 0; + + for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) + if(!(*fi).IsD()) + { + if((*fi).V(0) == (*fi).V(1) || + (*fi).V(0) == (*fi).V(2) || + (*fi).V(1) == (*fi).V(2) ) + { + count_fd++; + Allocator::DeleteFace(m,*fi); + } + } + return count_fd; + } + + static int RemoveDegenerateEdge(MeshType& m) + { + int count_ed = 0; + + for(EdgeIterator ei=m.edge.begin(); ei!=m.edge.end();++ei) + if(!(*ei).IsD()) + { + if((*ei).V(0) == (*ei).V(1) ) + { + count_ed++; + Allocator::DeleteEdge(m,*ei); + } + } + return count_ed; + } + + static int RemoveNonManifoldVertex(MeshType& m) + { + CountNonManifoldVertexFF(m,true); + tri::UpdateSelection::FaceFromVertexLoose(m); + int count_removed = 0; + for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) + if(!(*fi).IsD() && (*fi).IsS()) + Allocator::DeleteFace(m,*fi); + for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi) + if(!(*vi).IsD() && (*vi).IsS()) { + ++count_removed; + Allocator::DeleteVertex(m,*vi); + } + return count_removed; + } + + + static int SplitSelectedVertexOnEdgeMesh(MeshType& m) + { + tri::RequireCompactness(m); + + // count selected vertices references + std::unordered_map refCount; // selected vertex index -> reference count + size_t countSplit = 0; + for (size_t i=0; iIsS()) + { + const size_t refs = ++refCount[Index(m, m.edge[i].V(j))]; + if (refs > 1) { + countSplit++; + } + } + } + } + // actual split + if (countSplit > 0) + { + auto newVertIt = tri::Allocator::AddVertices(m, countSplit); + for (size_t i=0; iIsS()) + { + if (--refCount[vIdx] > 0) + { + newVertIt->ImportData(*vp); + m.edge[i].V(j) = &*(newVertIt++); + } + } + } + } + } + return int(countSplit); + } + + + static void SelectNonManifoldVertexOnEdgeMesh(MeshType &m) + { + tri::RequireCompactness(m); + tri::UpdateSelection::VertexClear(m); + std::vector cnt(m.vn,0); + + for(size_t i=0;i2) m.vert[i].SetS(); + } + + static void SelectCreaseVertexOnEdgeMesh(MeshType &m, ScalarType AngleRadThr) + { + tri::RequireCompactness(m); + tri::RequireVEAdjacency(m); + tri::UpdateTopology::VertexEdge(m); + tri::UpdateSelection::VertexClear(m); + for(size_t i=0;i VVStarVec; + edge::VVStarVE(&(m.vert[i]),VVStarVec); + if(VVStarVec.size()==2) + { + CoordType v0 = m.vert[i].P() - VVStarVec[0]->P(); + CoordType v1 = m.vert[i].P() - VVStarVec[1]->P(); + float angle = M_PI-vcg::Angle(v0,v1); + if(angle > AngleRadThr) m.vert[i].SetS(); + } + } + } + + + /// Removal of faces that were incident on a non manifold edge. + + // Given a mesh with FF adjacency + // it search for non manifold vertices and duplicate them. + // Duplicated vertices are moved apart according to the move threshold param. + // that is a percentage of the average vector from the non manifold vertex to the barycenter of the incident faces. + + static int SplitNonManifoldVertex(MeshType& m, ScalarType moveThreshold) + { + RequireFFAdjacency(m); + typedef std::pair FaceInt; // a face and the index of the vertex that we have to change + // + std::vector > >ToSplitVec; + + SelectionStack ss(m); + ss.push(); + CountNonManifoldVertexFF(m,true); + UpdateFlags::VertexClearV(m); + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) + { + for (int i=0; iVN(); i++) + if ((*fi).V(i)->IsS() && !(*fi).V(i)->IsV()) + { + (*fi).V(i)->SetV(); + face::Pos startPos(&*fi,i); + face::Pos curPos = startPos; + std::set faceSet; + do + { + faceSet.insert(std::make_pair(curPos.F(),curPos.VInd())); + curPos.NextE(); + } while (curPos != startPos); + + ToSplitVec.push_back(make_pair((*fi).V(i),std::vector())); + + typename std::set::const_iterator iii; + + for(iii=faceSet.begin();iii!=faceSet.end();++iii) + ToSplitVec.back().second.push_back(*iii); + } + } + ss.pop(); + // Second step actually add new vertices and split them. + typename tri::Allocator::template PointerUpdater pu; + VertexIterator firstVp = tri::Allocator::AddVertices(m,ToSplitVec.size(),pu); + for(size_t i =0;iImportData(*np); + // loop on the face to be changed, and also compute the movement vector; + CoordType delta(0,0,0); + for(size_t j=0;jV(ff.second)=&*firstVp; + delta+=Barycenter(*(ff.first))-np->cP(); + } + delta /= ToSplitVec[i].second.size(); + firstVp->P() = firstVp->P() + delta * moveThreshold; + firstVp++; + } + + return int(ToSplitVec.size()); + } + + + // Auxiliary function for sorting the non manifold faces according to their area. Used in RemoveNonManifoldFace + struct CompareAreaFP { + bool operator ()(FacePointer const& f1, FacePointer const& f2) const { + return DoubleArea(*f1) < DoubleArea(*f2); + } + }; + + /// Removal of faces that were incident on a non manifold edge. + static int RemoveNonManifoldFace(MeshType& m) + { + FaceIterator fi; + int count_fd = 0; + std::vector ToDelVec; + + for(fi=m.face.begin(); fi!=m.face.end();++fi) + if (!fi->IsD()) + { + if ((!IsManifold(*fi,0))|| + (!IsManifold(*fi,1))|| + (!IsManifold(*fi,2))) + ToDelVec.push_back(&*fi); + } + + std::sort(ToDelVec.begin(),ToDelVec.end(),CompareAreaFP()); + + for(size_t i=0;iIsD()) + { + FaceType &ff= *ToDelVec[i]; + if ((!IsManifold(ff,0))|| + (!IsManifold(ff,1))|| + (!IsManifold(ff,2))) + { + for(int j=0;j<3;++j) + if(!face::IsBorder(ff,j)) + vcg::face::FFDetach(ff,j); + + Allocator::DeleteFace(m,ff); + count_fd++; + } + } + } + return count_fd; + } + + /* Remove the faces that are out of a given range of area */ + static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)(), bool OnlyOnSelected=false) + { + int count_fd = 0; + MinAreaThr*=2; + MaxAreaThr*=2; + for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi){ + if(!(*fi).IsD()) + if(!OnlyOnSelected || (*fi).IsS()) + { + const ScalarType doubleArea=DoubleArea(*fi); + if((doubleArea<=MinAreaThr) || (doubleArea>=MaxAreaThr) ) + { + Allocator::DeleteFace(m,*fi); + count_fd++; + } + } + } + return count_fd; + } + + static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m,0);} + + + + /** + * Is the mesh only composed by quadrilaterals? + */ + static bool IsBitQuadOnly(const MeshType &m) + { + typedef typename MeshType::FaceType F; + tri::RequirePerFaceFlags(m); + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + unsigned int tmp = fi->Flags()&(F::FAUX0|F::FAUX1|F::FAUX2); + if ( tmp != F::FAUX0 && tmp != F::FAUX1 && tmp != F::FAUX2) return false; + } + return true; + } + + + static bool IsFaceFauxConsistent(MeshType &m) + { + RequirePerFaceFlags(m); + RequireFFAdjacency(m); + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) + { + for(int z=0;z<(*fi).VN();++z) + { + FacePointer fp = fi->FFp(z); + int zp = fi->FFi(z); + if(fi->IsF(z) != fp->IsF(zp)) return false; + } + } + return true; + } + + /** * Is the mesh only composed by triangles? (non polygonal faces) */ - static bool IsBitTriOnly(const MeshType &m) - { - tri::RequirePerFaceFlags(m); - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) { - if ( !fi->IsD() && fi->IsAnyF() ) return false; - } - return true; - } + static bool IsBitTriOnly(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) { + if ( !fi->IsD() && fi->IsAnyF() ) return false; + } + return true; + } - static bool IsBitPolygonal(const MeshType &m){ - return !IsBitTriOnly(m); - } + static bool IsBitPolygonal(const MeshType &m){ + return !IsBitTriOnly(m); + } - /** + /** * Is the mesh only composed by quadrilaterals and triangles? (no pentas, etc) * It assumes that the bits are consistent. In that case there can be only a single faux edge. */ - static bool IsBitTriQuadOnly(const MeshType &m) - { - tri::RequirePerFaceFlags(m); - typedef typename MeshType::FaceType F; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp!=F::FAUX0 && tmp!=F::FAUX1 && tmp!=F::FAUX2 && tmp!=0 ) return false; - } - return true; - } + static bool IsBitTriQuadOnly(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + typedef typename MeshType::FaceType F; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); + if ( tmp!=F::FAUX0 && tmp!=F::FAUX1 && tmp!=F::FAUX2 && tmp!=0 ) return false; + } + return true; + } - /** + /** * How many quadrilaterals? * It assumes that the bits are consistent. In that case we count the tris with a single faux edge and divide by two. */ - static int CountBitQuads(const MeshType &m) - { - tri::RequirePerFaceFlags(m); - typedef typename MeshType::FaceType F; - int count=0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp==F::FAUX0 || tmp==F::FAUX1 || tmp==F::FAUX2) count++; - } - return count / 2; - } + static int CountBitQuads(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + typedef typename MeshType::FaceType F; + int count=0; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); + if ( tmp==F::FAUX0 || tmp==F::FAUX1 || tmp==F::FAUX2) count++; + } + return count / 2; + } - /** + /** * How many triangles? (non polygonal faces) */ - static int CountBitTris(const MeshType &m) - { - tri::RequirePerFaceFlags(m); - int count=0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - if (!(fi->IsAnyF())) count++; - } - return count; - } + static int CountBitTris(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + int count=0; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + if (!(fi->IsAnyF())) count++; + } + return count; + } - /** + /** * How many polygons of any kind? (including triangles) * it assumes that there are no faux vertexes (e.g vertices completely surrounded by faux edges) */ - static int CountBitPolygons(const MeshType &m) - { - tri::RequirePerFaceFlags(m); - int count = 0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - if (fi->IsF(0)) count++; - if (fi->IsF(1)) count++; - if (fi->IsF(2)) count++; - } - return m.fn - count/2; - } + static int CountBitPolygons(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + int count = 0; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + if (fi->IsF(0)) count++; + if (fi->IsF(1)) count++; + if (fi->IsF(2)) count++; + } + return m.fn - count/2; + } - /** + /** * The number of polygonal faces is * FN - EN_f (each faux edge hides exactly one triangular face or in other words a polygon of n edges has n-3 faux edges.) * In the general case where a The number of polygonal faces is @@ -799,1104 +861,1145 @@ public: * as a intuitive proof think to a internal vertex that is collapsed onto a border of a polygon: * it deletes 2 faces, 1 faux edges and 1 vertex so to keep the balance you have to add back the removed vertex. */ - static int CountBitLargePolygons(MeshType &m) - { - tri::RequirePerFaceFlags(m); - UpdateFlags::VertexSetV(m); - // First loop Clear all referenced vertices - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!fi->IsD()) - for(int i=0;i<3;++i) fi->V(i)->ClearV(); + static int CountBitLargePolygons(MeshType &m) + { + tri::RequirePerFaceFlags(m); + UpdateFlags::VertexSetV(m); + // First loop Clear all referenced vertices + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if (!fi->IsD()) + for(int i=0;i<3;++i) fi->V(i)->ClearV(); - // Second Loop, count (twice) faux edges and mark all vertices touched by non faux edges - // (e.g vertexes on the boundary of a polygon) - int countE = 0; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!fi->IsD()) { - for(int i=0;i<3;++i) - { - if (fi->IsF(i)) - countE++; - else - { - fi->V0(i)->SetV(); - fi->V1(i)->SetV(); - } - } - } - // Third Loop, count the number of referenced vertexes that are completely surrounded by faux edges. + // Second Loop, count (twice) faux edges and mark all vertices touched by non faux edges + // (e.g vertexes on the boundary of a polygon) + int countE = 0; + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if (!fi->IsD()) { + for(int i=0;i<3;++i) + { + if (fi->IsF(i)) + countE++; + else + { + fi->V0(i)->SetV(); + fi->V1(i)->SetV(); + } + } + } + // Third Loop, count the number of referenced vertexes that are completely surrounded by faux edges. - int countV = 0; - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!vi->IsD() && !vi->IsV()) countV++; + int countV = 0; + for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) + if (!vi->IsD() && !vi->IsV()) countV++; - return m.fn - countE/2 + countV ; - } + return m.fn - countE/2 + countV ; + } - /** + /** * Checks that the mesh has consistent per-face faux edges * (the ones that merges triangles into larger polygons). * A border edge should never be faux, and faux edges should always be * reciprocated by another faux edges. * It requires FF adjacency. */ - static bool HasConsistentPerFaceFauxFlag(const MeshType &m) - { - RequireFFAdjacency(m); - RequirePerFaceFlags(m); + static bool HasConsistentPerFaceFauxFlag(const MeshType &m) + { + RequireFFAdjacency(m); + RequirePerFaceFlags(m); - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - for (int k=0; k<3; k++) - if( ( fi->IsF(k) != fi->cFFp(k)->IsF(fi->cFFi(k)) ) || - ( fi->IsF(k) && face::IsBorder(*fi,k)) ) - { - return false; - } - return true; - } + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if(!(*fi).IsD()) + for (int k=0; k<3; k++) + if( ( fi->IsF(k) != fi->cFFp(k)->IsF(fi->cFFi(k)) ) || + ( fi->IsF(k) && face::IsBorder(*fi,k)) ) + { + return false; + } + return true; + } - /** + /** * Count the number of non manifold edges in a polylinemesh, e.g. the edges where there are more than 2 incident faces. * */ - static int CountNonManifoldEdgeEE( MeshType & m, bool SelectFlag=false) - { - MeshAssert::OnlyEdgeMesh(m); - RequireEEAdjacency(m); - tri::UpdateTopology::EdgeEdge(m); + static int CountNonManifoldEdgeEE( MeshType & m, bool SelectFlag=false) + { + MeshAssert::OnlyEdgeMesh(m); + RequireEEAdjacency(m); + tri::UpdateTopology::EdgeEdge(m); - if(SelectFlag) UpdateSelection::VertexClear(m); + if(SelectFlag) UpdateSelection::VertexClear(m); - int nonManifoldCnt=0; - SimpleTempData TD(m.vert,0); + int nonManifoldCnt=0; + SimpleTempData TD(m.vert,0); - // First Loop, just count how many faces are incident on a vertex and store it in the TemporaryData Counter. - EdgeIterator ei; - for (ei = m.edge.begin(); ei != m.edge.end(); ++ei) if (!ei->IsD()) - { - TD[(*ei).V(0)]++; - TD[(*ei).V(1)]++; - } + // First Loop, just count how many faces are incident on a vertex and store it in the TemporaryData Counter. + EdgeIterator ei; + for (ei = m.edge.begin(); ei != m.edge.end(); ++ei) if (!ei->IsD()) + { + TD[(*ei).V(0)]++; + TD[(*ei).V(1)]++; + } - tri::UpdateFlags::VertexClearV(m); - // Second Loop, Check that each vertex have been seen 1 or 2 times. - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if (!vi->IsD()) - { - if( TD[vi] >2 ) - { - if(SelectFlag) (*vi).SetS(); - nonManifoldCnt++; - } - } - return nonManifoldCnt; - } + tri::UpdateFlags::VertexClearV(m); + // Second Loop, Check that each vertex have been seen 1 or 2 times. + for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if (!vi->IsD()) + { + if( TD[vi] >2 ) + { + if(SelectFlag) (*vi).SetS(); + nonManifoldCnt++; + } + } + return nonManifoldCnt; + } - /** - * Count the number of non manifold edges in a mesh, e.g. the edges where there are more than 2 incident faces. - * - * Note that this test is not enough to say that a mesh is two manifold, - * you have to count also the non manifold vertexes. - */ - static int CountNonManifoldEdgeFF( MeshType & m, bool SelectFlag=false) - { - RequireFFAdjacency(m); - int nmfBit[3]; - nmfBit[0]= FaceType::NewBitFlag(); - nmfBit[1]= FaceType::NewBitFlag(); - nmfBit[2]= FaceType::NewBitFlag(); + /** + * Count the number of non manifold edges in a mesh, e.g. the edges where there are more than 2 incident faces. + * + * Note that this test is not enough to say that a mesh is two manifold, + * you have to count also the non manifold vertexes. + */ + static int CountNonManifoldEdgeFF( MeshType & m, bool SelectFlag=false) + { + RequireFFAdjacency(m); + int nmfBit[3]; + nmfBit[0]= FaceType::NewBitFlag(); + nmfBit[1]= FaceType::NewBitFlag(); + nmfBit[2]= FaceType::NewBitFlag(); - UpdateFlags::FaceClear(m,nmfBit[0]+nmfBit[1]+nmfBit[2]); + UpdateFlags::FaceClear(m,nmfBit[0]+nmfBit[1]+nmfBit[2]); - if(SelectFlag){ - UpdateSelection::VertexClear(m); - UpdateSelection::FaceClear(m); - } + if(SelectFlag){ + UpdateSelection::VertexClear(m); + UpdateSelection::FaceClear(m); + } - int edgeCnt = 0; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if (!fi->IsD()) - { - for(int i=0;i<3;++i) - if(!IsManifold(*fi,i)) - { - if(!(*fi).IsUserBit(nmfBit[i])) - { - ++edgeCnt; - if(SelectFlag) - { - (*fi).V0(i)->SetS(); - (*fi).V1(i)->SetS(); - } - // follow the ring of faces incident on edge i; - face::Pos nmf(&*fi,i); - do - { - if(SelectFlag) nmf.F()->SetS(); - nmf.F()->SetUserBit(nmfBit[nmf.E()]); - nmf.NextF(); - } - while(nmf.f != &*fi); - } - } - } - } - return edgeCnt; - } + int edgeCnt = 0; + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + { + if (!fi->IsD()) + { + for(int i=0;i<3;++i) + if(!IsManifold(*fi,i)) + { + if(!(*fi).IsUserBit(nmfBit[i])) + { + ++edgeCnt; + if(SelectFlag) + { + (*fi).V0(i)->SetS(); + (*fi).V1(i)->SetS(); + } + // follow the ring of faces incident on edge i; + face::Pos nmf(&*fi,i); + do + { + if(SelectFlag) nmf.F()->SetS(); + nmf.F()->SetUserBit(nmfBit[nmf.E()]); + nmf.NextF(); + } + while(nmf.f != &*fi); + } + } + } + } + return edgeCnt; + } - /** Count (and eventually select) non 2-Manifold vertexes of a mesh - * e.g. the vertices with a non 2-manif. neighbourhood but that do not belong to not 2-manif edges. - * typical situation two cones connected by one vertex. - */ - static int CountNonManifoldVertexFF( MeshType & m, bool selectVert = true ) - { - RequireFFAdjacency(m); - if(selectVert) UpdateSelection::VertexClear(m); + /** Count (and eventually select) non 2-Manifold vertexes of a mesh + * e.g. the vertices with a non 2-manif. neighbourhood but that do not belong to not 2-manif edges. + * typical situation two cones connected by one vertex. + */ + static int CountNonManifoldVertexFF( MeshType & m, bool selectVert = true ) + { + RequireFFAdjacency(m); + if(selectVert) UpdateSelection::VertexClear(m); - int nonManifoldCnt=0; - SimpleTempData TD(m.vert,0); + int nonManifoldCnt=0; + SimpleTempData TD(m.vert,0); - // First Loop, just count how many faces are incident on a vertex and store it in the TemporaryData Counter. - FaceIterator fi; - for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - for (int k=0; kVN(); k++) - { - TD[(*fi).V(k)]++; - } - } + // First Loop, just count how many faces are incident on a vertex and store it in the TemporaryData Counter. + FaceIterator fi; + for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) + { + for (int k=0; kVN(); k++) + { + TD[(*fi).V(k)]++; + } + } - tri::UpdateFlags::VertexClearV(m); - // Second Loop. - // mark out of the game the vertexes that are incident on non manifold edges. - for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - for(int i=0; iVN(); ++i) - if (!IsManifold(*fi,i)) - { - (*fi).V0(i)->SetV(); - (*fi).V1(i)->SetV(); - } - } - // Third Loop, for safe vertexes, check that the number of faces that you can reach starting - // from it and using FF is the same of the previously counted. - for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - for(int i=0; iVN(); i++) if (!(*fi).V(i)->IsV()) - { - (*fi).V(i)->SetV(); - face::Pos pos(&(*fi),i); + tri::UpdateFlags::VertexClearV(m); + // Second Loop. + // mark out of the game the vertexes that are incident on non manifold edges. + for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) + { + for(int i=0; iVN(); ++i) + if (!IsManifold(*fi,i)) + { + (*fi).V0(i)->SetV(); + (*fi).V1(i)->SetV(); + } + } + // Third Loop, for safe vertexes, check that the number of faces that you can reach starting + // from it and using FF is the same of the previously counted. + for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) + { + for(int i=0; iVN(); i++) if (!(*fi).V(i)->IsV()) + { + (*fi).V(i)->SetV(); + face::Pos pos(&(*fi),i); - int starSizeFF = pos.NumberOfIncidentFaces(); + int starSizeFF = pos.NumberOfIncidentFaces(); - if (starSizeFF != TD[(*fi).V(i)]) - { - if (selectVert) - (*fi).V(i)->SetS(); - nonManifoldCnt++; - } - } - } - return nonManifoldCnt; - } - /// Very simple test of water tightness. No boundary and no non manifold edges. - /// Assume that it is orientable. - /// It could be debated if a closed non orientable surface is watertight or not. - /// - /// The rationale of not testing orientability here is that - /// it requires FFAdj while this test do not require any adjacency. - /// - static bool IsWaterTight(MeshType & m) - { - int edgeNum=0,edgeBorderNum=0,edgeNonManifNum=0; - CountEdgeNum(m, edgeNum, edgeBorderNum,edgeNonManifNum); - return (edgeBorderNum==0) && (edgeNonManifNum==0); - } + if (starSizeFF != TD[(*fi).V(i)]) + { + if (selectVert) + (*fi).V(i)->SetS(); + nonManifoldCnt++; + } + } + } + return nonManifoldCnt; + } + /// Very simple test of water tightness. No boundary and no non manifold edges. + /// Assume that it is orientable. + /// It could be debated if a closed non orientable surface is watertight or not. + /// + /// The rationale of not testing orientability here is that + /// it requires FFAdj while this test do not require any adjacency. + /// + static bool IsWaterTight(MeshType & m) + { + int edgeNum=0,edgeBorderNum=0,edgeNonManifNum=0; + CountEdgeNum(m, edgeNum, edgeBorderNum,edgeNonManifNum); + return (edgeBorderNum==0) && (edgeNonManifNum==0); + } - static void CountEdgeNum( MeshType & m, int &total_e, int &boundary_e, int &non_manif_e ) - { - std::vector< typename tri::UpdateTopology::PEdge > edgeVec; - tri::UpdateTopology::FillEdgeVector(m,edgeVec,true); - sort(edgeVec.begin(), edgeVec.end()); // Lo ordino per vertici - total_e=0; - boundary_e=0; - non_manif_e=0; + static void CountEdgeNum( MeshType & m, int &total_e, int &boundary_e, int &non_manif_e ) + { + std::vector< typename tri::UpdateTopology::PEdge > edgeVec; + tri::UpdateTopology::FillEdgeVector(m,edgeVec,true); + sort(edgeVec.begin(), edgeVec.end()); // Lo ordino per vertici + total_e=0; + boundary_e=0; + non_manif_e=0; - size_t f_on_cur_edge =1; - for(size_t i=0;i2) - ++non_manif_e; - f_on_cur_edge=1; - } - else - { - ++f_on_cur_edge; - } - } // end for - } + size_t f_on_cur_edge =1; + for(size_t i=0;i2) + ++non_manif_e; + f_on_cur_edge=1; + } + else + { + ++f_on_cur_edge; + } + } // end for + } - static int CountHoles( MeshType & m) - { - UpdateFlags::FaceClearV(m); - int loopNum=0; - for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) if(!fi->IsD()) - { - for(int j=0;j<3;++j) - { - if(!fi->IsV() && face::IsBorder(*fi,j)) - { - face::Pos startPos(&*fi,j); - face::Pos curPos=startPos; - do - { - curPos.NextB(); - curPos.F()->SetV(); - } - while(curPos!=startPos); - ++loopNum; - } - } - } - return loopNum; - } + static int CountHoles( MeshType & m) + { + UpdateFlags::FaceClearV(m); + int loopNum=0; + for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) if(!fi->IsD()) + { + for(int j=0;j<3;++j) + { + if(!fi->IsV() && face::IsBorder(*fi,j)) + { + face::Pos startPos(&*fi,j); + face::Pos curPos=startPos; + do + { + curPos.NextB(); + curPos.F()->SetV(); + } + while(curPos!=startPos); + ++loopNum; + } + } + } + return loopNum; + } - /* + /* Compute the set of connected components of a given mesh it fills a vector of pair < int , faceptr > with, for each connecteed component its size and a represnant */ - static int CountConnectedComponents(MeshType &m) - { - std::vector< std::pair > CCV; - return ConnectedComponents(m,CCV); - } - - static int ConnectedComponents(MeshType &m, std::vector< std::pair > &CCV) - { - tri::RequireFFAdjacency(m); - CCV.clear(); - tri::UpdateFlags::FaceClearV(m); - std::stack sf; - FacePointer fpt=&*(m.face.begin()); - for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) - { - if(!((*fi).IsD()) && !(*fi).IsV()) - { - (*fi).SetV(); - CCV.push_back(std::make_pair(0,&*fi)); - sf.push(&*fi); - while (!sf.empty()) - { - fpt=sf.top(); - ++CCV.back().first; - sf.pop(); - for(int j=0; jVN(); ++j) - { - if( !face::IsBorder(*fpt,j) ) - { - FacePointer l = fpt->FFp(j); - if( !(*l).IsV() ) - { - (*l).SetV(); - sf.push(l); - } - } - } - } - } - } - return int(CCV.size()); - } - - static void ComputeValence( MeshType &m, typename MeshType::PerVertexIntHandle &h) - { - for(VertexIterator vi=m.vert.begin(); vi!= m.vert.end();++vi) - h[vi]=0; - - for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) - { - if(!((*fi).IsD())) - for(int j=0;jVN();j++) - ++h[tri::Index(m,fi->V(j))]; - } - } - - /** - GENUS. - - A topologically invariant property of a surface defined as - the largest number of non-intersecting simple closed curves that can be - drawn on the surface without separating it. - - Roughly speaking, it is the number of holes in a surface. - The genus g of a closed surface, also called the geometric genus, is related to the - Euler characteristic by the relation $chi$ by $chi==2-2g$. - - The genus of a connected, orientable surface is an integer representing the maximum - number of cuttings along closed simple curves without rendering the resultant - manifold disconnected. It is equal to the number of handles on it. - - For general polyhedra the Euler Formula is: - - V - E + F = 2 - 2G - B - - where V is the number of vertices, F is the number of faces, E is the - number of edges, G is the genus and B is the number of boundary polygons. - - The above formula is valid for a mesh with one single connected component. - By considering multiple connected components the formula becomes: - - V - E + F = 2C - 2Gs - B -> 2Gs = - ( V-E+F +B -2C) - - where C is the number of connected components and Gs is the sum of - the genus of all connected components. - - Note that in the case of a mesh with boundaries the intuitive meaning of Genus is less intuitive that it could seem. - A closed sphere, a sphere with one hole (e.g. a disk) and a sphere with two holes (e.g. a tube) all of them have Genus == 0 - - */ - - static int MeshGenus(int nvert,int nedges,int nfaces, int numholes, int numcomponents) - { - return -((nvert + nfaces - nedges + numholes - 2 * numcomponents) / 2); - } - - static int MeshGenus(MeshType &m) - { - int nvert=m.vn; - int nfaces=m.fn; - int boundary_e,total_e,nonmanif_e; - CountEdgeNum(m,total_e,boundary_e,nonmanif_e); - int numholes=CountHoles(m); - int numcomponents=CountConnectedComponents(m); - int G=MeshGenus(nvert,total_e,nfaces,numholes,numcomponents); - return G; - } - - /** - * Check if the given mesh is regular, semi-regular or irregular. - * - * Each vertex of a \em regular mesh has valence 6 except for border vertices - * which have valence 4. - * - * A \em semi-regular mesh is derived from an irregular one applying - * 1-to-4 subdivision recursively. (not checked for now) - * - * All other meshes are \em irregular. - */ - static void IsRegularMesh(MeshType &m, bool &Regular, bool &Semiregular) - { - RequireVFAdjacency(m); - Regular = true; - - VertexIterator vi; - - // for each vertex the number of edges are count - for (vi = m.vert.begin(); vi != m.vert.end(); ++vi) - { - if (!vi->IsD()) - { - face::Pos he((*vi).VFp(), &*vi); - face::Pos ht = he; - - int n=0; - bool border=false; - do - { - ++n; - ht.NextE(); - if (ht.IsBorder()) - border=true; - } - while (ht != he); - - if (border) - n = n/2; - - if ((n != 6)&&(!border && n != 4)) - { - Regular = false; - break; - } - } - } - - if (!Regular) - Semiregular = false; - else - { - // For now we do not account for semi-regularity - Semiregular = false; - } - } - - - static bool IsCoherentlyOrientedMesh(MeshType &m) - { - RequireFFAdjacency(m); - MeshAssert::FFAdjacencyIsInitialized(m); - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!fi->IsD()) - for(int i=0;i<3;++i) - if(!face::CheckOrientation(*fi,i)) - return false; - - return true; - } - - static void OrientCoherentlyMesh(MeshType &m, bool &_IsOriented, bool &_IsOrientable) - { - RequireFFAdjacency(m); - MeshAssert::FFAdjacencyIsInitialized(m); - bool IsOrientable = true; - bool IsOriented = true; - - UpdateFlags::FaceClearV(m); - std::stack faces; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if (!fi->IsD() && !fi->IsV()) - { - // each face put in the stack is selected (and oriented) - fi->SetV(); - faces.push(&(*fi)); - while (!faces.empty()) - { - FacePointer fp = faces.top(); - faces.pop(); - - // make consistently oriented the adjacent faces - for (int j = 0; j < 3; j++) - { - if (!face::IsBorder(*fp,j) && face::IsManifold(*fp, j)) - { - FacePointer fpaux = fp->FFp(j); - int iaux = fp->FFi(j); - if (!CheckOrientation(*fpaux, iaux)) - { - IsOriented = false; - - if (!fpaux->IsV()) - face::SwapEdge(*fpaux, iaux); - else - { - IsOrientable = false; - break; - } - } - if (!fpaux->IsV()) - { - fpaux->SetV(); - faces.push(fpaux); - } - } - } - } - } - if (!IsOrientable) break; - } - _IsOriented = IsOriented; - _IsOrientable = IsOrientable; - } - - - /// Flip the orientation of the whole mesh flipping all the faces (by swapping the first two vertices) - static void FlipMesh(MeshType &m, bool selected=false) - { - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD()) - if(!selected || (*fi).IsS()) - { - face::SwapEdge((*fi), 0); - if (HasPerWedgeTexCoord(m)) - std::swap((*fi).WT(0),(*fi).WT(1)); - } - } - /// Flip a mesh so that its normals are orented outside. - /// Just for safety it uses a voting scheme. - /// It assumes that - /// mesh has already has coherent normals. - /// mesh is watertight and signle component. - static bool FlipNormalOutside(MeshType &m) - { - if(m.vert.empty()) return false; - - tri::UpdateNormal::PerVertexAngleWeighted(m); - tri::UpdateNormal::NormalizePerVertex(m); - - std::vector< VertexPointer > minVertVec; - std::vector< VertexPointer > maxVertVec; - - // The set of directions to be choosen - std::vector< CoordType > dirVec; - dirVec.push_back(CoordType(1,0,0)); - dirVec.push_back(CoordType(0,1,0)); - dirVec.push_back(CoordType(0,0,1)); - dirVec.push_back(CoordType( 1, 1,1)); - dirVec.push_back(CoordType(-1, 1,1)); - dirVec.push_back(CoordType(-1,-1,1)); - dirVec.push_back(CoordType( 1,-1,1)); - for(size_t i=0;iP().dot(dirVec[i])) minVertVec[i] = &*vi; - if( (*vi).cP().dot(dirVec[i]) > maxVertVec[i]->P().dot(dirVec[i])) maxVertVec[i] = &*vi; - } - } - - int voteCount=0; - ScalarType angleThreshold = cos(math::ToRad(85.0)); - for(size_t i=0;iP()[0],minVertVec[i]->P()[1],minVertVec[i]->P()[2]); - // qDebug("Max vert along (%f %f %f) is %f %f %f",dirVec[i][0],dirVec[i][1],dirVec[i][2],maxVertVec[i]->P()[0],maxVertVec[i]->P()[1],maxVertVec[i]->P()[2]); - if(minVertVec[i]->N().dot(dirVec[i]) > angleThreshold ) voteCount++; - if(maxVertVec[i]->N().dot(dirVec[i]) < -angleThreshold ) voteCount++; - } - // qDebug("votecount = %i",voteCount); - if(voteCount < int(dirVec.size())/2) return false; - FlipMesh(m); - return true; - } - - // Search and remove small single triangle folds - // - a face has normal opposite to all other faces - // - choose the edge that brings to the face f1 containing the vertex opposite to that edge. - static int RemoveFaceFoldByFlip(MeshType &m, float normalThresholdDeg=175, bool repeat=true) - { - RequireFFAdjacency(m); - RequirePerVertexMark(m); - //Counters for logging and convergence - int count, total = 0; - - do { - tri::UpdateTopology::FaceFace(m); - tri::UnMarkAll(m); - count = 0; - - ScalarType NormalThrRad = math::ToRad(normalThresholdDeg); - ScalarType eps = ScalarType(0.0001); // this epsilon value is in absolute value. It is a distance from edge in baricentric coords. - //detection stage - for(FaceIterator fi=m.face.begin();fi!= m.face.end();++fi ) if(!(*fi).IsV()) - { Point3 NN = vcg::TriangleNormal((*fi)).Normalize(); - if( vcg::AngleN(NN,TriangleNormal(*(*fi).FFp(0)).Normalize()) > NormalThrRad && - vcg::AngleN(NN,TriangleNormal(*(*fi).FFp(1)).Normalize()) > NormalThrRad && - vcg::AngleN(NN,TriangleNormal(*(*fi).FFp(2)).Normalize()) > NormalThrRad ) - { - (*fi).SetS(); - //(*fi).C()=Color4b(Color4b::Red); - // now search the best edge to flip - for(int i=0;i<3;i++) - { - Point3 &p=(*fi).P2(i); - Point3 L; - bool ret = vcg::InterpolationParameters((*(*fi).FFp(i)),TriangleNormal(*(*fi).FFp(i)),p,L); - if(ret && L[0]>eps && L[1]>eps && L[2]>eps) - { - (*fi).FFp(i)->SetS(); - (*fi).FFp(i)->SetV(); - //(*fi).FFp(i)->C()=Color4b(Color4b::Green); - if(face::CheckFlipEdge( *fi, i )) { - face::FlipEdge( *fi, i ); - ++count; ++total; - } - } - } - } - } - - // tri::UpdateNormal::PerFace(m); - } - while( repeat && count ); - return total; - } - - - static int RemoveTVertexByFlip(MeshType &m, float threshold=40, bool repeat=true) - { - RequireFFAdjacency(m); - RequirePerVertexMark(m); - //Counters for logging and convergence - int count, total = 0; - - do { - tri::UpdateTopology::FaceFace(m); - tri::UnMarkAll(m); - count = 0; - - //detection stage - for(unsigned int index = 0 ; index < m.face.size(); ++index ) - { - FacePointer f = &(m.face[index]); float sides[3]; CoordType dummy; - sides[0] = Distance(f->P(0), f->P(1)); - sides[1] = Distance(f->P(1), f->P(2)); - sides[2] = Distance(f->P(2), f->P(0)); - // Find largest triangle side - int i = std::find(sides, sides+3, std::max( std::max(sides[0],sides[1]), sides[2])) - (sides); - if( tri::IsMarked(m,f->V2(i) )) continue; - - if( PSDist(f->P2(i),f->P(i),f->P1(i),dummy)*threshold <= sides[i] ) - { - tri::Mark(m,f->V2(i)); - if(face::CheckFlipEdge( *f, i )) { - // Check if EdgeFlipping improves quality - FacePointer g = f->FFp(i); int k = f->FFi(i); - Triangle3 t1(f->P(i), f->P1(i), f->P2(i)), t2(g->P(k), g->P1(k), g->P2(k)), - t3(f->P(i), g->P2(k), f->P2(i)), t4(g->P(k), f->P2(i), g->P2(k)); - - if ( std::min( QualityFace(t1), QualityFace(t2) ) < std::min( QualityFace(t3), QualityFace(t4) )) - { - face::FlipEdge( *f, i ); - ++count; ++total; - } - } - - } - } - - // tri::UpdateNormal::PerFace(m); - } - while( repeat && count ); - return total; - } - - static int RemoveTVertexByCollapse(MeshType &m, float threshold=40, bool repeat=true) - { - RequirePerVertexMark(m); - //Counters for logging and convergence - int count, total = 0; - - do { - tri::UnMarkAll(m); - count = 0; - - //detection stage - for(unsigned int index = 0 ; index < m.face.size(); ++index ) - { - FacePointer f = &(m.face[index]); - float sides[3]; - CoordType dummy; - - sides[0] = Distance(f->P(0), f->P(1)); - sides[1] = Distance(f->P(1), f->P(2)); - sides[2] = Distance(f->P(2), f->P(0)); - int i = std::find(sides, sides+3, std::max( std::max(sides[0],sides[1]), sides[2])) - (sides); - if( tri::IsMarked(m,f->V2(i) )) continue; - - if( PSDist(f->P2(i),f->P(i),f->P1(i),dummy)*threshold <= sides[i] ) - { - tri::Mark(m,f->V2(i)); - - int j = Distance(dummy,f->P(i))P1(i))?i:(i+1)%3; - f->P2(i) = f->P(j); tri::Mark(m,f->V(j)); - ++count; ++total; - } - } - - - tri::Clean::RemoveDuplicateVertex(m); - tri::Allocator::CompactFaceVector(m); - tri::Allocator::CompactVertexVector(m); - } - while( repeat && count ); - - return total; - } - - static bool SelfIntersections(MeshType &m, std::vector &ret) - { - RequirePerFaceMark(m); - ret.clear(); - int referredBit = FaceType::NewBitFlag(); - tri::UpdateFlags::FaceClear(m,referredBit); - - TriMeshGrid gM; - gM.Set(m.face.begin(),m.face.end()); - - for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - (*fi).SetUserBit(referredBit); - Box3< ScalarType> bbox; - (*fi).GetBBox(bbox); - std::vector inBox; - vcg::tri::GetInBoxFace(m, gM, bbox,inBox); - bool Intersected=false; - typename std::vector::iterator fib; - for(fib=inBox.begin();fib!=inBox.end();++fib) - { - if(!(*fib)->IsUserBit(referredBit) && (*fib != &*fi) ) - if(Clean::TestFaceFaceIntersection(&*fi,*fib)){ - ret.push_back(*fib); - if(!Intersected) { - ret.push_back(&*fi); - Intersected=true; - } - } - } - inBox.clear(); - } - - FaceType::DeleteBitFlag(referredBit); - return (ret.size()>0); - } - - /** - This function simply test that the vn and fn counters be consistent with the size of the containers and the number of deleted simplexes. - */ - static bool IsSizeConsistent(MeshType &m) - { - int DeletedVertNum=0; - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if((*vi).IsD()) DeletedVertNum++; - - int DeletedEdgeNum=0; - for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) - if((*ei).IsD()) DeletedEdgeNum++; - - int DeletedFaceNum=0; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if((*fi).IsD()) DeletedFaceNum++; - - if(size_t(m.vn+DeletedVertNum) != m.vert.size()) return false; - if(size_t(m.en+DeletedEdgeNum) != m.edge.size()) return false; - if(size_t(m.fn+DeletedFaceNum) != m.face.size()) return false; - - return true; - } - - /** - This function simply test that all the faces have a consistent face-face topology relation. - useful for checking that a topology modifying algorithm does not mess something. - */ - static bool IsFFAdjacencyConsistent(MeshType &m) - { - RequireFFAdjacency(m); - - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - for(int i=0;i<3;++i) - if(!FFCorrectness(*fi, i)) return false; - } - return true; - } - - /** - This function simply test that a mesh has some reasonable tex coord. - */ - static bool HasConsistentPerWedgeTexCoord(MeshType &m) - { - tri::RequirePerFaceWedgeTexCoord(m); - - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { FaceType &f=(*fi); - if( ! ( (f.WT(0).N() == f.WT(1).N()) && (f.WT(0).N() == (*fi).WT(2).N()) ) ) - return false; // all the vertices must have the same index. - - if((*fi).WT(0).N() <0) return false; // no undefined texture should be allowed - } - return true; - } - - /** + static int CountConnectedComponents(MeshType &m) + { + std::vector< std::pair > CCV; + return ConnectedComponents(m,CCV); + } + + static int ConnectedComponents(MeshType &m, std::vector< std::pair > &CCV) + { + tri::RequireFFAdjacency(m); + CCV.clear(); + tri::UpdateFlags::FaceClearV(m); + std::stack sf; + FacePointer fpt=&*(m.face.begin()); + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + { + if(!((*fi).IsD()) && !(*fi).IsV()) + { + (*fi).SetV(); + CCV.push_back(std::make_pair(0,&*fi)); + sf.push(&*fi); + while (!sf.empty()) + { + fpt=sf.top(); + ++CCV.back().first; + sf.pop(); + for(int j=0; jVN(); ++j) + { + if( !face::IsBorder(*fpt,j) ) + { + FacePointer l = fpt->FFp(j); + if( !(*l).IsV() ) + { + (*l).SetV(); + sf.push(l); + } + } + } + } + } + } + return int(CCV.size()); + } + + static int edgeMeshConnectedComponents(MeshType & poly, std::vector > &eCC) + { + typedef typename MeshType::EdgePointer EdgePointer; + tri::UpdateTopology::VertexEdge(poly); + tri::UpdateFlags::EdgeClear(poly); + eCC.clear(); + std::stack stack; + + for (auto ei = poly.edge.begin(); ei != poly.edge.end(); ++ei) + if (!ei->IsD() && !ei->IsV()) + { + ei->SetV(); + + std::pair cc(1, &*ei); + + stack.push(&*ei); + while (!stack.empty()) + { + EdgePointer ep = stack.top(); + stack.pop(); + + for (int i = 0; i < 2; ++i) + { + edge::VEIterator vei(ep->V(i)); + while (!vei.End()) + { + if (!vei.E()->IsV()) + { + vei.E()->SetV(); + stack.push(vei.E()); + cc.first += 1; + } + ++vei; + } + } + } + eCC.push_back(cc); + } + return int(eCC.size()); + } + + static void ComputeValence( MeshType &m, typename MeshType::PerVertexIntHandle &h) + { + for(VertexIterator vi=m.vert.begin(); vi!= m.vert.end();++vi) + h[vi]=0; + + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + { + if(!((*fi).IsD())) + for(int j=0;jVN();j++) + ++h[tri::Index(m,fi->V(j))]; + } + } + + /** + GENUS. + + A topologically invariant property of a surface defined as + the largest number of non-intersecting simple closed curves that can be + drawn on the surface without separating it. + + Roughly speaking, it is the number of holes in a surface. + The genus g of a closed surface, also called the geometric genus, is related to the + Euler characteristic by the relation $chi$ by $chi==2-2g$. + + The genus of a connected, orientable surface is an integer representing the maximum + number of cuttings along closed simple curves without rendering the resultant + manifold disconnected. It is equal to the number of handles on it. + + For general polyhedra the Euler Formula is: + + V - E + F = 2 - 2G - B + + where V is the number of vertices, F is the number of faces, E is the + number of edges, G is the genus and B is the number of boundary polygons. + + The above formula is valid for a mesh with one single connected component. + By considering multiple connected components the formula becomes: + + V - E + F = 2C - 2Gs - B -> 2Gs = - ( V-E+F +B -2C) + + where C is the number of connected components and Gs is the sum of + the genus of all connected components. + + Note that in the case of a mesh with boundaries the intuitive meaning of Genus is less intuitive that it could seem. + A closed sphere, a sphere with one hole (e.g. a disk) and a sphere with two holes (e.g. a tube) all of them have Genus == 0 + + */ + + static int MeshGenus(int nvert,int nedges,int nfaces, int numholes, int numcomponents) + { + return -((nvert + nfaces - nedges + numholes - 2 * numcomponents) / 2); + } + + static int MeshGenus(MeshType &m) + { + int nvert=m.vn; + int nfaces=m.fn; + int boundary_e,total_e,nonmanif_e; + CountEdgeNum(m,total_e,boundary_e,nonmanif_e); + int numholes=CountHoles(m); + int numcomponents=CountConnectedComponents(m); + int G=MeshGenus(nvert,total_e,nfaces,numholes,numcomponents); + return G; + } + + /** + * Check if the given mesh is regular, semi-regular or irregular. + * + * Each vertex of a \em regular mesh has valence 6 except for border vertices + * which have valence 4. + * + * A \em semi-regular mesh is derived from an irregular one applying + * 1-to-4 subdivision recursively. (not checked for now) + * + * All other meshes are \em irregular. + */ + static void IsRegularMesh(MeshType &m, bool &Regular, bool &Semiregular) + { + RequireVFAdjacency(m); + Regular = true; + + VertexIterator vi; + + // for each vertex the number of edges are count + for (vi = m.vert.begin(); vi != m.vert.end(); ++vi) + { + if (!vi->IsD()) + { + face::Pos he((*vi).VFp(), &*vi); + face::Pos ht = he; + + int n=0; + bool border=false; + do + { + ++n; + ht.NextE(); + if (ht.IsBorder()) + border=true; + } + while (ht != he); + + if (border) + n = n/2; + + if ((n != 6)&&(!border && n != 4)) + { + Regular = false; + break; + } + } + } + + if (!Regular) + Semiregular = false; + else + { + // For now we do not account for semi-regularity + Semiregular = false; + } + } + + + static bool IsCoherentlyOrientedMesh(MeshType &m) + { + RequireFFAdjacency(m); + MeshAssert::FFAdjacencyIsInitialized(m); + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if (!fi->IsD()) + for(int i=0;i<3;++i) + if(!face::CheckOrientation(*fi,i)) + return false; + + return true; + } + + static void OrientCoherentlyMesh(MeshType &m, bool &_IsOriented, bool &_IsOrientable) + { + RequireFFAdjacency(m); + MeshAssert::FFAdjacencyIsInitialized(m); + bool IsOrientable = true; + bool IsOriented = true; + + UpdateFlags::FaceClearV(m); + std::stack faces; + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + { + if (!fi->IsD() && !fi->IsV()) + { + // each face put in the stack is selected (and oriented) + fi->SetV(); + faces.push(&(*fi)); + while (!faces.empty()) + { + FacePointer fp = faces.top(); + faces.pop(); + + // make consistently oriented the adjacent faces + for (int j = 0; j < 3; j++) + { + if (!face::IsBorder(*fp,j) && face::IsManifold(*fp, j)) + { + FacePointer fpaux = fp->FFp(j); + int iaux = fp->FFi(j); + if (!CheckOrientation(*fpaux, iaux)) + { + IsOriented = false; + + if (!fpaux->IsV()) + face::SwapEdge(*fpaux, iaux); + else + { + IsOrientable = false; + break; + } + } + if (!fpaux->IsV()) + { + fpaux->SetV(); + faces.push(fpaux); + } + } + } + } + } + if (!IsOrientable) break; + } + _IsOriented = IsOriented; + _IsOrientable = IsOrientable; + } + + + /// Flip the orientation of the whole mesh flipping all the faces (by swapping the first two vertices) + static void FlipMesh(MeshType &m, bool selected=false) + { + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD()) + if(!selected || (*fi).IsS()) + { + face::SwapEdge((*fi), 0); + if (HasPerWedgeTexCoord(m)) + std::swap((*fi).WT(0),(*fi).WT(1)); + } + } + /// Flip a mesh so that its normals are orented outside. + /// Just for safety it uses a voting scheme. + /// It assumes that + /// mesh has already has coherent normals. + /// mesh is watertight and signle component. + static bool FlipNormalOutside(MeshType &m) + { + if(m.vert.empty()) return false; + + tri::UpdateNormal::PerVertexAngleWeighted(m); + tri::UpdateNormal::NormalizePerVertex(m); + + std::vector< VertexPointer > minVertVec; + std::vector< VertexPointer > maxVertVec; + + // The set of directions to be choosen + std::vector< CoordType > dirVec; + dirVec.push_back(CoordType(1,0,0)); + dirVec.push_back(CoordType(0,1,0)); + dirVec.push_back(CoordType(0,0,1)); + dirVec.push_back(CoordType( 1, 1,1)); + dirVec.push_back(CoordType(-1, 1,1)); + dirVec.push_back(CoordType(-1,-1,1)); + dirVec.push_back(CoordType( 1,-1,1)); + for(size_t i=0;iP().dot(dirVec[i])) minVertVec[i] = &*vi; + if( (*vi).cP().dot(dirVec[i]) > maxVertVec[i]->P().dot(dirVec[i])) maxVertVec[i] = &*vi; + } + } + + int voteCount=0; + ScalarType angleThreshold = cos(math::ToRad(85.0)); + for(size_t i=0;iP()[0],minVertVec[i]->P()[1],minVertVec[i]->P()[2]); + // qDebug("Max vert along (%f %f %f) is %f %f %f",dirVec[i][0],dirVec[i][1],dirVec[i][2],maxVertVec[i]->P()[0],maxVertVec[i]->P()[1],maxVertVec[i]->P()[2]); + if(minVertVec[i]->N().dot(dirVec[i]) > angleThreshold ) voteCount++; + if(maxVertVec[i]->N().dot(dirVec[i]) < -angleThreshold ) voteCount++; + } + // qDebug("votecount = %i",voteCount); + if(voteCount < int(dirVec.size())/2) return false; + FlipMesh(m); + return true; + } + + // Search and remove small single triangle folds + // - a face has normal opposite to all other faces + // - choose the edge that brings to the face f1 containing the vertex opposite to that edge. + static int RemoveFaceFoldByFlip(MeshType &m, float normalThresholdDeg=175, bool repeat=true) + { + RequireFFAdjacency(m); + RequirePerVertexMark(m); + //Counters for logging and convergence + int count, total = 0; + + do { + tri::UpdateTopology::FaceFace(m); + tri::UnMarkAll(m); + count = 0; + + ScalarType NormalThrRad = math::ToRad(normalThresholdDeg); + ScalarType eps = ScalarType(0.0001); // this epsilon value is in absolute value. It is a distance from edge in baricentric coords. + //detection stage + for(FaceIterator fi=m.face.begin();fi!= m.face.end();++fi ) if(!(*fi).IsV()) + { Point3 NN = vcg::TriangleNormal((*fi)).Normalize(); + if( vcg::AngleN(NN,TriangleNormal(*(*fi).FFp(0)).Normalize()) > NormalThrRad && + vcg::AngleN(NN,TriangleNormal(*(*fi).FFp(1)).Normalize()) > NormalThrRad && + vcg::AngleN(NN,TriangleNormal(*(*fi).FFp(2)).Normalize()) > NormalThrRad ) + { + (*fi).SetS(); + //(*fi).C()=Color4b(Color4b::Red); + // now search the best edge to flip + for(int i=0;i<3;i++) + { + Point3 &p=(*fi).P2(i); + Point3 L; + bool ret = vcg::InterpolationParameters((*(*fi).FFp(i)),TriangleNormal(*(*fi).FFp(i)),p,L); + if(ret && L[0]>eps && L[1]>eps && L[2]>eps) + { + (*fi).FFp(i)->SetS(); + (*fi).FFp(i)->SetV(); + //(*fi).FFp(i)->C()=Color4b(Color4b::Green); + if(face::CheckFlipEdge( *fi, i )) { + face::FlipEdge( *fi, i ); + ++count; ++total; + } + } + } + } + } + + // tri::UpdateNormal::PerFace(m); + } + while( repeat && count ); + return total; + } + + + static int RemoveTVertexByFlip(MeshType &m, float threshold=40, bool repeat=true) + { + RequireFFAdjacency(m); + RequirePerVertexMark(m); + //Counters for logging and convergence + int count, total = 0; + + do { + tri::UpdateTopology::FaceFace(m); + tri::UnMarkAll(m); + count = 0; + + //detection stage + for(unsigned int index = 0 ; index < m.face.size(); ++index ) + { + FacePointer f = &(m.face[index]); float sides[3]; CoordType dummy; + sides[0] = Distance(f->P(0), f->P(1)); + sides[1] = Distance(f->P(1), f->P(2)); + sides[2] = Distance(f->P(2), f->P(0)); + // Find largest triangle side + int i = std::find(sides, sides+3, std::max( std::max(sides[0],sides[1]), sides[2])) - (sides); + if( tri::IsMarked(m,f->V2(i) )) continue; + + if( PSDist(f->P2(i),f->P(i),f->P1(i),dummy)*threshold <= sides[i] ) + { + tri::Mark(m,f->V2(i)); + if(face::CheckFlipEdge( *f, i )) { + // Check if EdgeFlipping improves quality + FacePointer g = f->FFp(i); int k = f->FFi(i); + Triangle3 t1(f->P(i), f->P1(i), f->P2(i)), t2(g->P(k), g->P1(k), g->P2(k)), + t3(f->P(i), g->P2(k), f->P2(i)), t4(g->P(k), f->P2(i), g->P2(k)); + + if ( std::min( QualityFace(t1), QualityFace(t2) ) < std::min( QualityFace(t3), QualityFace(t4) )) + { + face::FlipEdge( *f, i ); + ++count; ++total; + } + } + + } + } + + // tri::UpdateNormal::PerFace(m); + } + while( repeat && count ); + return total; + } + + static int RemoveTVertexByCollapse(MeshType &m, float threshold=40, bool repeat=true) + { + RequirePerVertexMark(m); + //Counters for logging and convergence + int count, total = 0; + + do { + tri::UnMarkAll(m); + count = 0; + + //detection stage + for(unsigned int index = 0 ; index < m.face.size(); ++index ) + { + FacePointer f = &(m.face[index]); + float sides[3]; + CoordType dummy; + + sides[0] = Distance(f->P(0), f->P(1)); + sides[1] = Distance(f->P(1), f->P(2)); + sides[2] = Distance(f->P(2), f->P(0)); + int i = std::find(sides, sides+3, std::max( std::max(sides[0],sides[1]), sides[2])) - (sides); + if( tri::IsMarked(m,f->V2(i) )) continue; + + if( PSDist(f->P2(i),f->P(i),f->P1(i),dummy)*threshold <= sides[i] ) + { + tri::Mark(m,f->V2(i)); + + int j = Distance(dummy,f->P(i))P1(i))?i:(i+1)%3; + f->P2(i) = f->P(j); tri::Mark(m,f->V(j)); + ++count; ++total; + } + } + + + tri::Clean::RemoveDuplicateVertex(m); + tri::Allocator::CompactFaceVector(m); + tri::Allocator::CompactVertexVector(m); + } + while( repeat && count ); + + return total; + } + + static bool SelfIntersections(MeshType &m, std::vector &ret) + { + RequirePerFaceMark(m); + ret.clear(); + int referredBit = FaceType::NewBitFlag(); + tri::UpdateFlags::FaceClear(m,referredBit); + + TriMeshGrid gM; + gM.Set(m.face.begin(),m.face.end()); + + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) + { + (*fi).SetUserBit(referredBit); + Box3< ScalarType> bbox; + (*fi).GetBBox(bbox); + std::vector inBox; + vcg::tri::GetInBoxFace(m, gM, bbox,inBox); + bool Intersected=false; + typename std::vector::iterator fib; + for(fib=inBox.begin();fib!=inBox.end();++fib) + { + if(!(*fib)->IsUserBit(referredBit) && (*fib != &*fi) ) + if(Clean::TestFaceFaceIntersection(&*fi,*fib)){ + ret.push_back(*fib); + if(!Intersected) { + ret.push_back(&*fi); + Intersected=true; + } + } + } + inBox.clear(); + } + + FaceType::DeleteBitFlag(referredBit); + return (ret.size()>0); + } + + /** + This function simply test that the vn and fn counters be consistent with the size of the containers and the number of deleted simplexes. + */ + static bool IsSizeConsistent(MeshType &m) + { + int DeletedVertNum=0; + for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) + if((*vi).IsD()) DeletedVertNum++; + + int DeletedEdgeNum=0; + for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) + if((*ei).IsD()) DeletedEdgeNum++; + + int DeletedFaceNum=0; + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if((*fi).IsD()) DeletedFaceNum++; + + if(size_t(m.vn+DeletedVertNum) != m.vert.size()) return false; + if(size_t(m.en+DeletedEdgeNum) != m.edge.size()) return false; + if(size_t(m.fn+DeletedFaceNum) != m.face.size()) return false; + + return true; + } + + /** + This function simply test that all the faces have a consistent face-face topology relation. + useful for checking that a topology modifying algorithm does not mess something. + */ + static bool IsFFAdjacencyConsistent(MeshType &m) + { + RequireFFAdjacency(m); + + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if(!(*fi).IsD()) + { + for(int i=0;i<3;++i) + if(!FFCorrectness(*fi, i)) return false; + } + return true; + } + + /** + This function simply test that a mesh has some reasonable tex coord. + */ + static bool HasConsistentPerWedgeTexCoord(MeshType &m) + { + tri::RequirePerFaceWedgeTexCoord(m); + + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if(!(*fi).IsD()) + { FaceType &f=(*fi); + if( ! ( (f.WT(0).N() == f.WT(1).N()) && (f.WT(0).N() == (*fi).WT(2).N()) ) ) + return false; // all the vertices must have the same index. + + if((*fi).WT(0).N() <0) return false; // no undefined texture should be allowed + } + return true; + } + + /** Simple check that there are no face with all collapsed tex coords. */ - static bool HasZeroTexCoordFace(MeshType &m) - { - tri::RequirePerFaceWedgeTexCoord(m); + static bool HasZeroTexCoordFace(MeshType &m) + { + tri::RequirePerFaceWedgeTexCoord(m); - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - if( (*fi).WT(0).P() == (*fi).WT(1).P() && (*fi).WT(0).P() == (*fi).WT(2).P() ) return false; - } - return true; - } + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if(!(*fi).IsD()) + { + if( (*fi).WT(0).P() == (*fi).WT(1).P() && (*fi).WT(0).P() == (*fi).WT(2).P() ) return false; + } + return true; + } - /** - This function test if two triangular faces of a mesh intersect. - It assumes that the faces (as storage) are different (e.g different address) - If the two faces are different but coincident (same set of vertexes) return true. - if the faces share an edge no test is done. - if the faces share only a vertex, the opposite edge is tested against the face + /** + This function test if two triangular faces of a mesh intersect. + It assumes that the faces (as storage) are different (e.g different address) + If the two faces are different but coincident (same set of vertexes) return true. + if the faces share an edge no test is done. + if the faces share only a vertex, the opposite edge is tested against the face */ - static bool TestFaceFaceIntersection(FaceType *f0,FaceType *f1) - { - int sv = face::CountSharedVertex(f0,f1); - if(sv==3) return true; - if(sv==0) return (vcg::IntersectionTriangleTriangle((*f0),(*f1))); - // if the faces share only a vertex, the opposite edge (as a segment) is tested against the face - // to avoid degenerate cases where the two triangles have the opposite edge on a common plane - // we offset the segment to test toward the shared vertex - if(sv==1) - { - int i0,i1; ScalarType a,b; - face::FindSharedVertex(f0,f1,i0,i1); - CoordType shP = f0->V(i0)->P()*0.5; - if(vcg::IntersectionSegmentTriangle(Segment3((*f0).V1(i0)->P()*0.5+shP,(*f0).V2(i0)->P()*0.5+shP), *f1, a, b) ) - { - // a,b are the param coords of the intersection point of the segment. - if(a+b>=1 || a<=EPSIL || b<=EPSIL ) return false; - return true; - } - if(vcg::IntersectionSegmentTriangle(Segment3((*f1).V1(i1)->P()*0.5+shP,(*f1).V2(i1)->P()*0.5+shP), *f0, a, b) ) - { - // a,b are the param coords of the intersection point of the segment. - if(a+b>=1 || a<=EPSIL || b<=EPSIL ) return false; - return true; - } + static bool TestFaceFaceIntersection(FaceType *f0,FaceType *f1) + { + int sv = face::CountSharedVertex(f0,f1); + if(sv==3) return true; + if(sv==0) return (vcg::IntersectionTriangleTriangle((*f0),(*f1))); + // if the faces share only a vertex, the opposite edge (as a segment) is tested against the face + // to avoid degenerate cases where the two triangles have the opposite edge on a common plane + // we offset the segment to test toward the shared vertex + if(sv==1) + { + int i0,i1; ScalarType a,b; + face::FindSharedVertex(f0,f1,i0,i1); + CoordType shP = f0->V(i0)->P()*0.5; + if(vcg::IntersectionSegmentTriangle(Segment3((*f0).V1(i0)->P()*0.5+shP,(*f0).V2(i0)->P()*0.5+shP), *f1, a, b) ) + { + // a,b are the param coords of the intersection point of the segment. + if(a+b>=1 || a<=EPSIL || b<=EPSIL ) return false; + return true; + } + if(vcg::IntersectionSegmentTriangle(Segment3((*f1).V1(i1)->P()*0.5+shP,(*f1).V2(i1)->P()*0.5+shP), *f0, a, b) ) + { + // a,b are the param coords of the intersection point of the segment. + if(a+b>=1 || a<=EPSIL || b<=EPSIL ) return false; + return true; + } - } - return false; - } + } + return false; + } - /** - This function merge all the vertices that are closer than the given radius + /** + This function merge all the vertices that are closer than the given radius */ - static int MergeCloseVertex(MeshType &m, const ScalarType radius) - { - int mergedCnt=0; - mergedCnt = ClusterVertex(m,radius); - RemoveDuplicateVertex(m,true); - return mergedCnt; - } + static int MergeCloseVertex(MeshType &m, const ScalarType radius) + { + int mergedCnt=0; + mergedCnt = ClusterVertex(m,radius); + RemoveDuplicateVertex(m,true); + return mergedCnt; + } - static int ClusterVertex(MeshType &m, const ScalarType radius) - { - if(m.vn==0) return 0; - // some spatial indexing structure does not work well with deleted vertices... - tri::Allocator::CompactVertexVector(m); - typedef vcg::SpatialHashTable SampleSHT; - SampleSHT sht; - tri::EmptyTMark markerFunctor; - std::vector closests; - int mergedCnt=0; - sht.Set(m.vert.begin(), m.vert.end()); - UpdateFlags::VertexClearV(m); - for(VertexIterator viv = m.vert.begin(); viv!= m.vert.end(); ++viv) - if(!(*viv).IsD() && !(*viv).IsV()) - { - (*viv).SetV(); - Point3 p = viv->cP(); - Box3 bb(p-Point3(radius,radius,radius),p+Point3(radius,radius,radius)); - GridGetInBox(sht, markerFunctor, bb, closests); - // qDebug("Vertex %i has %i closest", &*viv - &*m.vert.begin(),closests.size()); - for(size_t i=0; icP()); - if(dist < radius && !closests[i]->IsV()) - { - // printf("%f %f \n",dist,radius); - mergedCnt++; - closests[i]->SetV(); - closests[i]->P()=p; - } - } - } - return mergedCnt; - } + static int ClusterVertex(MeshType &m, const ScalarType radius) + { + if(m.vn==0) return 0; + // some spatial indexing structure does not work well with deleted vertices... + tri::Allocator::CompactVertexVector(m); + typedef vcg::SpatialHashTable SampleSHT; + SampleSHT sht; + tri::EmptyTMark markerFunctor; + std::vector closests; + int mergedCnt=0; + sht.Set(m.vert.begin(), m.vert.end()); + UpdateFlags::VertexClearV(m); + for(VertexIterator viv = m.vert.begin(); viv!= m.vert.end(); ++viv) + if(!(*viv).IsD() && !(*viv).IsV()) + { + (*viv).SetV(); + Point3 p = viv->cP(); + Box3 bb(p-Point3(radius,radius,radius),p+Point3(radius,radius,radius)); + GridGetInBox(sht, markerFunctor, bb, closests); + // qDebug("Vertex %i has %i closest", &*viv - &*m.vert.begin(),closests.size()); + for(size_t i=0; icP()); + if(dist < radius && !closests[i]->IsV()) + { + // printf("%f %f \n",dist,radius); + mergedCnt++; + closests[i]->SetV(); + closests[i]->P()=p; + } + } + } + return mergedCnt; + } - static std::pair RemoveSmallConnectedComponentsSize(MeshType &m, int maxCCSize) - { - std::vector< std::pair > CCV; - int TotalCC=ConnectedComponents(m, CCV); - int DeletedCC=0; + static std::pair RemoveSmallConnectedComponentsSize(MeshType &m, int maxCCSize) + { + std::vector< std::pair > CCV; + int TotalCC=ConnectedComponents(m, CCV); + int DeletedCC=0; - ConnectedComponentIterator ci; - for(unsigned int i=0;i FPV; - if(CCV[i].first ci; + for(unsigned int i=0;i FPV; + if(CCV[i].first::iterator fpvi; - for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) - Allocator::DeleteFace(m,(**fpvi)); - } - } - return std::make_pair(TotalCC,DeletedCC); - } + typename std::vector::iterator fpvi; + for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) + Allocator::DeleteFace(m,(**fpvi)); + } + } + return std::make_pair(TotalCC,DeletedCC); + } - /// Remove the connected components smaller than a given diameter - // it returns a pair with the number of connected components and the number of deleted ones. - static std::pair RemoveSmallConnectedComponentsDiameter(MeshType &m, ScalarType maxDiameter) - { - std::vector< std::pair > CCV; - int TotalCC=ConnectedComponents(m, CCV); - int DeletedCC=0; - tri::ConnectedComponentIterator ci; - for(unsigned int i=0;i bb; - std::vector FPV; - for(ci.start(m,CCV[i].second);!ci.completed();++ci) - { - FPV.push_back(*ci); - bb.Add((*ci)->P(0)); - bb.Add((*ci)->P(1)); - bb.Add((*ci)->P(2)); - } - if(bb.Diag()::iterator fpvi; - for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) - tri::Allocator::DeleteFace(m,(**fpvi)); - } - } - return std::make_pair(TotalCC,DeletedCC); - } + /// Remove the connected components smaller than a given diameter + // it returns a pair with the number of connected components and the number of deleted ones. + static std::pair RemoveSmallConnectedComponentsDiameter(MeshType &m, ScalarType maxDiameter) + { + std::vector< std::pair > CCV; + int TotalCC=ConnectedComponents(m, CCV); + int DeletedCC=0; + tri::ConnectedComponentIterator ci; + for(unsigned int i=0;i bb; + std::vector FPV; + for(ci.start(m,CCV[i].second);!ci.completed();++ci) + { + FPV.push_back(*ci); + bb.Add((*ci)->P(0)); + bb.Add((*ci)->P(1)); + bb.Add((*ci)->P(2)); + } + if(bb.Diag()::iterator fpvi; + for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) + tri::Allocator::DeleteFace(m,(**fpvi)); + } + } + return std::make_pair(TotalCC,DeletedCC); + } - /// Remove the connected components greater than a given diameter - // it returns a pair with the number of connected components and the number of deleted ones. - static std::pair RemoveHugeConnectedComponentsDiameter(MeshType &m, ScalarType minDiameter) - { - std::vector< std::pair > CCV; - int TotalCC=ConnectedComponents(m, CCV); - int DeletedCC=0; - tri::ConnectedComponentIterator ci; - for(unsigned int i=0;i FPV; - for(ci.start(m,CCV[i].second);!ci.completed();++ci) - { - FPV.push_back(*ci); - bb.Add((*ci)->P(0)); - bb.Add((*ci)->P(1)); - bb.Add((*ci)->P(2)); - } - if(bb.Diag()>minDiameter) - { - DeletedCC++; - typename std::vector::iterator fpvi; - for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) - tri::Allocator::DeleteFace(m,(**fpvi)); - } - } - return std::make_pair(TotalCC,DeletedCC); - } + /// Remove the connected components greater than a given diameter + // it returns a pair with the number of connected components and the number of deleted ones. + static std::pair RemoveHugeConnectedComponentsDiameter(MeshType &m, ScalarType minDiameter) + { + std::vector< std::pair > CCV; + int TotalCC=ConnectedComponents(m, CCV); + int DeletedCC=0; + tri::ConnectedComponentIterator ci; + for(unsigned int i=0;i FPV; + for(ci.start(m,CCV[i].second);!ci.completed();++ci) + { + FPV.push_back(*ci); + bb.Add((*ci)->P(0)); + bb.Add((*ci)->P(1)); + bb.Add((*ci)->P(2)); + } + if(bb.Diag()>minDiameter) + { + DeletedCC++; + typename std::vector::iterator fpvi; + for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) + tri::Allocator::DeleteFace(m,(**fpvi)); + } + } + return std::make_pair(TotalCC,DeletedCC); + } - /** + /** Select the folded faces using an angle threshold on the face normal. The face is selected if the dot product between the face normal and the normal of the plane fitted using the vertices of the one ring faces is below the cosThreshold. The cosThreshold requires a negative cosine value (a positive value is clamp to zero). */ - static void SelectFoldedFaceFromOneRingFaces(MeshType &m, ScalarType cosThreshold) - { - typedef std::unordered_set VertexSet; - tri::RequireVFAdjacency(m); - tri::RequirePerFaceNormal(m); - tri::RequirePerVertexNormal(m); - vcg::tri::UpdateSelection::FaceClear(m); - vcg::tri::UpdateNormal::PerFaceNormalized(m); - vcg::tri::UpdateNormal::PerVertexNormalized(m); - vcg::tri::UpdateTopology::VertexFace(m); - if (cosThreshold > 0) - cosThreshold = 0; + static void SelectFoldedFaceFromOneRingFaces(MeshType &m, ScalarType cosThreshold) + { + typedef std::unordered_set VertexSet; + tri::RequireVFAdjacency(m); + tri::RequirePerFaceNormal(m); + tri::RequirePerVertexNormal(m); + vcg::tri::UpdateSelection::FaceClear(m); + vcg::tri::UpdateNormal::PerFaceNormalized(m); + vcg::tri::UpdateNormal::PerVertexNormalized(m); + vcg::tri::UpdateTopology::VertexFace(m); + if (cosThreshold > 0) + cosThreshold = 0; #pragma omp parallel for schedule(dynamic, 10) - for (int i = 0; i < m.face.size(); i++) - { - VertexSet nearVertex; - std::vector pointVec; - FacePointer f = &m.face[i]; - for (int j = 0; j < 3; j++) - { - std::vector temp; - vcg::face::VVStarVF(f->V(j), temp); - typename std::vector::iterator iter = temp.begin(); - for (; iter != temp.end(); iter++) - { - if ((*iter) != f->V1(j) && (*iter) != f->V2(j)) - { - if (nearVertex.insert((*iter)).second) - pointVec.push_back((*iter)->P()); - } - } - nearVertex.insert(f->V(j)); - pointVec.push_back(f->P(j)); - } + for (int i = 0; i < m.face.size(); i++) + { + VertexSet nearVertex; + std::vector pointVec; + FacePointer f = &m.face[i]; + for (int j = 0; j < 3; j++) + { + std::vector temp; + vcg::face::VVStarVF(f->V(j), temp); + typename std::vector::iterator iter = temp.begin(); + for (; iter != temp.end(); iter++) + { + if ((*iter) != f->V1(j) && (*iter) != f->V2(j)) + { + if (nearVertex.insert((*iter)).second) + pointVec.push_back((*iter)->P()); + } + } + nearVertex.insert(f->V(j)); + pointVec.push_back(f->P(j)); + } - if (pointVec.size() > 3) - { - vcg::Plane3 plane; - vcg::FitPlaneToPointSet(pointVec, plane); - float avgDot = 0; - for (auto nvp : nearVertex) - avgDot += plane.Direction().dot(nvp->N()); - avgDot /= nearVertex.size(); - typename MeshType::VertexType::NormalType normal; - if (avgDot < 0) - normal = -plane.Direction(); - else - normal = plane.Direction(); - if (normal.dot(f->N()) < cosThreshold) - f->SetS(); - } - } - } - /** + if (pointVec.size() > 3) + { + vcg::Plane3 plane; + vcg::FitPlaneToPointSet(pointVec, plane); + float avgDot = 0; + for (auto nvp : nearVertex) + avgDot += plane.Direction().dot(nvp->N()); + avgDot /= nearVertex.size(); + typename MeshType::VertexType::NormalType normal; + if (avgDot < 0) + normal = -plane.Direction(); + else + normal = plane.Direction(); + if (normal.dot(f->N()) < cosThreshold) + f->SetS(); + } + } + } + /** Select the faces on the first mesh that intersect the second mesh. It uses a grid for querying so a face::mark should be added. */ - static int SelectIntersectingFaces(MeshType &m1, MeshType &m2) - { - RequirePerFaceMark(m2); - RequireCompactness(m1); - RequireCompactness(m2); + static int SelectIntersectingFaces(MeshType &m1, MeshType &m2) + { + RequirePerFaceMark(m2); + RequireCompactness(m1); + RequireCompactness(m2); - tri::UpdateSelection::FaceClear(m1); + tri::UpdateSelection::FaceClear(m1); - TriMeshGrid gM; - gM.Set(m2.face.begin(),m2.face.end()); - int selCnt=0; - for(auto fi=m1.face.begin();fi!=m1.face.end();++fi) - { - Box3< ScalarType> bbox; - (*fi).GetBBox(bbox); - std::vector inBox; - vcg::tri::GetInBoxFace(m2, gM, bbox,inBox); - for(auto fib=inBox.begin(); fib!=inBox.end(); ++fib) - { - if(Clean::TestFaceFaceIntersection(&*fi,*fib)){ - fi->SetS(); - ++selCnt; - } - } - inBox.clear(); - } - return selCnt; - } + TriMeshGrid gM; + gM.Set(m2.face.begin(),m2.face.end()); + int selCnt=0; + for(auto fi=m1.face.begin();fi!=m1.face.end();++fi) + { + Box3< ScalarType> bbox; + (*fi).GetBBox(bbox); + std::vector inBox; + vcg::tri::GetInBoxFace(m2, gM, bbox,inBox); + for(auto fib=inBox.begin(); fib!=inBox.end(); ++fib) + { + if(Clean::TestFaceFaceIntersection(&*fi,*fib)){ + fi->SetS(); + ++selCnt; + } + } + inBox.clear(); + } + return selCnt; + } }; // end class /*@}*/ diff --git a/vcg/complex/base.h b/vcg/complex/base.h index e269158a..88d51d27 100644 --- a/vcg/complex/base.h +++ b/vcg/complex/base.h @@ -31,18 +31,18 @@ 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) + 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 - std::type_index _type; - void Resize(size_t 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);} + int n_attr; // unique ID of the attribute + std::type_index _type; + void Resize(size_t 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);} - PointerToAttribute(): _type(typeid(void)) { }; + PointerToAttribute(): _type(typeid(void)) { }; }; @@ -51,113 +51,115 @@ namespace tri { /*@{*/ - /* MeshTypeHolder is a class which is used to define the types in the mesh +/* MeshTypeHolder is a class which is used to define the types in the mesh */ - template - struct BaseMeshTypeHolder{ +template +struct BaseMeshTypeHolder{ - typedef bool ScalarType; - typedef std::vector< typename TYPESPOOL::VertexType > CONTV; - typedef std::vector< typename TYPESPOOL::EdgeType > CONTE; - typedef std::vector< typename TYPESPOOL::FaceType > CONTF; - typedef std::vector< typename TYPESPOOL::HEdgeType > CONTH; - typedef std::vector CONTT; + typedef bool ScalarType; + typedef std::vector< typename TYPESPOOL::VertexType > CONTV; + typedef std::vector< typename TYPESPOOL::EdgeType > CONTE; + typedef std::vector< typename TYPESPOOL::FaceType > CONTF; + typedef std::vector< typename TYPESPOOL::HEdgeType > CONTH; + typedef std::vector CONTT; - typedef CONTV VertContainer; - typedef typename CONTV::value_type VertexType; - typedef typename TYPESPOOL::VertexPointer VertexPointer; - typedef const typename TYPESPOOL::VertexPointer ConstVertexPointer; - typedef bool CoordType; - typedef typename CONTV::iterator VertexIterator; - typedef typename CONTV::const_iterator ConstVertexIterator; + typedef CONTV VertContainer; + typedef typename CONTV::value_type VertexType; + typedef typename TYPESPOOL::VertexPointer VertexPointer; + typedef const typename TYPESPOOL::VertexPointer ConstVertexPointer; + typedef bool CoordType; + typedef typename CONTV::iterator VertexIterator; + typedef typename CONTV::const_iterator ConstVertexIterator; - typedef CONTE EdgeContainer; - typedef typename CONTE::value_type EdgeType; - typedef typename TYPESPOOL::EdgePointer EdgePointer; - typedef typename CONTE::iterator EdgeIterator; - typedef typename CONTE::const_iterator ConstEdgeIterator; + typedef CONTE EdgeContainer; + typedef typename CONTE::value_type EdgeType; + typedef typename TYPESPOOL::EdgePointer EdgePointer; + typedef const typename TYPESPOOL::EdgePointer ConstEdgePointer; + typedef typename CONTE::iterator EdgeIterator; + typedef typename CONTE::const_iterator ConstEdgeIterator; - typedef CONTF FaceContainer; - typedef typename CONTF::value_type FaceType; - typedef typename CONTF::const_iterator ConstFaceIterator; - typedef typename CONTF::iterator FaceIterator; - typedef typename TYPESPOOL::FacePointer FacePointer; - typedef const typename TYPESPOOL::FacePointer ConstFacePointer; + typedef CONTF FaceContainer; + typedef typename CONTF::value_type FaceType; + typedef typename CONTF::const_iterator ConstFaceIterator; + typedef typename CONTF::iterator FaceIterator; + typedef typename TYPESPOOL::FacePointer FacePointer; + typedef const typename TYPESPOOL::FacePointer ConstFacePointer; - typedef CONTH HEdgeContainer; - typedef typename CONTH::value_type HEdgeType; - typedef typename TYPESPOOL::HEdgePointer HEdgePointer; - typedef typename CONTH::iterator HEdgeIterator; - typedef typename CONTH::const_iterator ConstHEdgeIterator; + typedef CONTH HEdgeContainer; + typedef typename CONTH::value_type HEdgeType; + typedef typename TYPESPOOL::HEdgePointer HEdgePointer; + typedef typename CONTH::iterator HEdgeIterator; + typedef typename CONTH::const_iterator ConstHEdgeIterator; - typedef CONTT TetraContainer; - typedef typename CONTT::value_type TetraType; - typedef typename TYPESPOOL::TetraPointer TetraPointer; - typedef const typename TYPESPOOL::TetraPointer ConstTetraPointer; - typedef typename CONTT::iterator TetraIterator; - typedef typename CONTT::const_iterator ConstTetraIterator; + typedef CONTT TetraContainer; + typedef typename CONTT::value_type TetraType; + typedef typename TYPESPOOL::TetraPointer TetraPointer; + typedef const typename TYPESPOOL::TetraPointer ConstTetraPointer; + typedef typename CONTT::iterator TetraIterator; + typedef typename CONTT::const_iterator ConstTetraIterator; - }; - - - - template - struct MeshTypeHolder: public T {}; - - template - struct MeshTypeHolder: public T { - typedef CONT VertContainer; - typedef typename VertContainer::value_type VertexType; - typedef VertexType * VertexPointer; - typedef const VertexType * ConstVertexPointer; - typedef typename VertexType::ScalarType ScalarType; - typedef typename VertexType::CoordType CoordType; - typedef typename VertContainer::iterator VertexIterator; - typedef typename VertContainer::const_iterator ConstVertexIterator; - }; - - - template - struct MeshTypeHolder< T, CONT, AllTypes::AEdgeType>: public T{ - typedef CONT EdgeContainer; - typedef typename EdgeContainer::value_type EdgeType; - typedef typename EdgeContainer::value_type * EdgePointer; - typedef typename EdgeContainer::iterator EdgeIterator; - typedef typename EdgeContainer::const_iterator ConstEdgeIterator; }; - template - struct MeshTypeHolder< T, CONT, AllTypes::AFaceType>:public T { - typedef CONT FaceContainer; - typedef typename FaceContainer::value_type FaceType; - typedef typename FaceContainer::const_iterator ConstFaceIterator; - typedef typename FaceContainer::iterator FaceIterator; - typedef FaceType * FacePointer; - typedef const FaceType * ConstFacePointer; - }; - template - struct MeshTypeHolder< T, CONT, AllTypes::AHEdgeType>: public T{ - typedef CONT HEdgeContainer; - typedef typename HEdgeContainer::value_type HEdgeType; - typedef typename HEdgeContainer::value_type * HEdgePointer; - typedef typename HEdgeContainer::iterator HEdgeIterator; - typedef typename HEdgeContainer::const_iterator ConstHEdgeIterator; - }; - template - struct MeshTypeHolder : public T - { - typedef CONT TetraContainer; - typedef typename TetraContainer::value_type TetraType; - typedef TetraType *TetraPointer; - typedef const TetraType *ConstTetraPointer; - typedef typename TetraContainer::iterator TetraIterator; - typedef typename TetraContainer::const_iterator ConstTetraIterator; - }; +template +struct MeshTypeHolder: public T {}; + +template +struct MeshTypeHolder: public T { + typedef CONT VertContainer; + typedef typename VertContainer::value_type VertexType; + typedef VertexType * VertexPointer; + typedef const VertexType * ConstVertexPointer; + typedef typename VertexType::ScalarType ScalarType; + typedef typename VertexType::CoordType CoordType; + typedef typename VertContainer::iterator VertexIterator; + typedef typename VertContainer::const_iterator ConstVertexIterator; +}; + + +template +struct MeshTypeHolder< T, CONT, AllTypes::AEdgeType>: public T{ + typedef CONT EdgeContainer; + typedef typename EdgeContainer::value_type EdgeType; + typedef EdgeType * EdgePointer; + typedef const EdgeType * ConstEdgePointer; + typedef typename EdgeContainer::iterator EdgeIterator; + typedef typename EdgeContainer::const_iterator ConstEdgeIterator; +}; + +template +struct MeshTypeHolder< T, CONT, AllTypes::AFaceType>:public T { + typedef CONT FaceContainer; + typedef typename FaceContainer::value_type FaceType; + typedef typename FaceContainer::const_iterator ConstFaceIterator; + typedef typename FaceContainer::iterator FaceIterator; + typedef FaceType * FacePointer; + typedef const FaceType * ConstFacePointer; +}; + +template +struct MeshTypeHolder< T, CONT, AllTypes::AHEdgeType>: public T{ + typedef CONT HEdgeContainer; + typedef typename HEdgeContainer::value_type HEdgeType; + typedef typename HEdgeContainer::value_type * HEdgePointer; + typedef typename HEdgeContainer::iterator HEdgeIterator; + typedef typename HEdgeContainer::const_iterator ConstHEdgeIterator; +}; + +template +struct MeshTypeHolder : public T +{ + typedef CONT TetraContainer; + typedef typename TetraContainer::value_type TetraType; + typedef TetraType *TetraPointer; + typedef const TetraType *ConstTetraPointer; + typedef typename TetraContainer::iterator TetraIterator; + typedef typename TetraContainer::const_iterator ConstTetraIterator; +}; template struct Der: public MeshTypeHolder{}; struct DummyContainer{struct value_type{ typedef int IAm;}; }; @@ -168,337 +170,347 @@ As explained in \ref basic_concepts, this class is templated over a list of cont template < class Container0 = DummyContainer, class Container1 = DummyContainer, class Container2 = DummyContainer, class Container3 = DummyContainer, class Container4 = DummyContainer > class TriMesh - : public MArity5< BaseMeshTypeHolder, Container0, Der ,Container1, Der, Container2, Der, Container3, Der, Container4, Der >{ - public: - - typedef typename TriMesh::ScalarType ScalarType; - typedef typename TriMesh::VertContainer VertContainer; - typedef typename TriMesh::EdgeContainer EdgeContainer; - typedef typename TriMesh::FaceContainer FaceContainer; - typedef typename TriMesh::TetraContainer TetraContainer; - - // types for vertex - typedef typename TriMesh::VertexType VertexType; - typedef typename TriMesh::VertexPointer VertexPointer; - typedef typename TriMesh::ConstVertexPointer ConstVertexPointer; - typedef typename TriMesh::CoordType CoordType; - typedef typename TriMesh::VertexIterator VertexIterator; - typedef typename TriMesh::ConstVertexIterator ConstVertexIterator; - - // types for edge - typedef typename TriMesh::EdgeType EdgeType; - typedef typename TriMesh::EdgePointer EdgePointer; - typedef typename TriMesh::EdgeIterator EdgeIterator; - typedef typename TriMesh::ConstEdgeIterator ConstEdgeIterator; - - //types for face - typedef typename TriMesh::FaceType FaceType; - typedef typename TriMesh::ConstFaceIterator ConstFaceIterator; - typedef typename TriMesh::FaceIterator FaceIterator; - typedef typename TriMesh::FacePointer FacePointer; - typedef typename TriMesh::ConstFacePointer ConstFacePointer; - - // types for hedge - typedef typename TriMesh::HEdgeType HEdgeType; - typedef typename TriMesh::HEdgePointer HEdgePointer; - typedef typename TriMesh::HEdgeIterator HEdgeIterator; - typedef typename TriMesh::HEdgeContainer HEdgeContainer; - typedef typename TriMesh::ConstHEdgeIterator ConstHEdgeIterator; - - // types for tetra - typedef typename TriMesh::TetraType TetraType; - typedef typename TriMesh::TetraPointer TetraPointer; - typedef typename TriMesh::TetraIterator TetraIterator; - typedef typename TriMesh::ConstTetraIterator ConstTetraIterator; - - typedef vcg::PointerToAttribute PointerToAttribute; - - typedef TriMesh MeshType; - - typedef Box3 BoxType; - - /// Container of vertices, usually a vector. - VertContainer vert; - /// Current number of vertices; this member is for internal use only. You should always use the VN() member - int vn; - /// Current number of vertices - inline int VN() const { return vn; } - - /// Container of edges, usually a vector. - EdgeContainer edge; - /// Current number of edges; this member is for internal use only. You should always use the EN() member - int en; - /// Current number of edges - inline int EN() const { return en; } - - /// Container of faces, usually a vector. - FaceContainer face; - /// Current number of faces; this member is for internal use only. You should always use the FN() member - int fn; - /// Current number of faces - inline int FN() const { return fn; } - - /// Container of half edges, usually a vector. - HEdgeContainer hedge; - /// Current number of halfedges; this member is for internal use only. You should always use the HN() member - int hn; - /// Current number of halfedges; - inline int HN() const { return hn; } - - /// Container of tetras, usually a vector. - TetraContainer tetra; - /// Current number of tetras; this member is for internal use only. You should always use the TN() member - int tn; - /// Current number of tetras; - inline int TN() const { return tn; } - - /// Bounding box of the mesh - Box3 bbox; - - /// Nomi di textures - // - std::vector textures; - // - std::vector normalmaps; - - int attrn; // total numer of attribute created - - - std::set< PointerToAttribute > vert_attr; - std::set< PointerToAttribute > edge_attr; - std::set< PointerToAttribute > face_attr; - std::set< PointerToAttribute > mesh_attr; - std::set< PointerToAttribute > tetra_attr; - - - template - class AttributeHandle{ - public: - AttributeHandle(){_handle=(SimpleTempData *)NULL;} - AttributeHandle( void *ah,const int & n):_handle ( (SimpleTempData *)ah ),n_attr(n){} - AttributeHandle operator = ( const PointerToAttribute & pva){ - _handle = (SimpleTempData *)pva._handle; - n_attr = pva.n_attr; - return (*this); - } - - //pointer to the SimpleTempData that stores the attribute - SimpleTempData * _handle; - - // its attribute number - int n_attr; - - // access function - template - ATTR_TYPE & operator [](const RefType & i){return (*_handle)[i];} - void resize(size_t /*size*/) { }; - }; - - template - class PerVertexAttributeHandle: public AttributeHandle{ - public: - PerVertexAttributeHandle():AttributeHandle(){} - PerVertexAttributeHandle( void *ah,const int & n):AttributeHandle(ah,n){} - }; - - - template - class PerFaceAttributeHandle: public AttributeHandle{ - public: - PerFaceAttributeHandle():AttributeHandle(){} - PerFaceAttributeHandle( void *ah,const int & n):AttributeHandle(ah,n){} - }; - - template - class PerEdgeAttributeHandle: public AttributeHandle{ - public: - PerEdgeAttributeHandle():AttributeHandle(){} - PerEdgeAttributeHandle( void *ah,const int & n):AttributeHandle(ah,n){} - }; - - template - class PerTetraAttributeHandle : public AttributeHandle - { - public: - PerTetraAttributeHandle() : AttributeHandle() {} - PerTetraAttributeHandle(void *ah, const int &n) : AttributeHandle(ah, n) {} - }; - - template - class PerMeshAttributeHandle{ - public: - PerMeshAttributeHandle(){_handle=NULL;} - PerMeshAttributeHandle(void *ah,const int & n):_handle ( (Attribute *)ah ),n_attr(n){} - PerMeshAttributeHandle operator = ( const PerMeshAttributeHandle & pva){ - _handle = (Attribute *)pva._handle; - n_attr = pva.n_attr; - return (*this); - } - - Attribute * _handle; - int n_attr; - ATTR_TYPE & operator ()(){ return *((Attribute *)_handle)->attribute;} - }; - - // Some common Handle typedefs to simplify use - typedef typename MeshType::template PerVertexAttributeHandle PerVertexScalarHandle; - typedef typename MeshType::template PerVertexAttributeHandle PerVertexIntHandle; - typedef typename MeshType::template PerVertexAttributeHandle PerVertexBoolHandle; - typedef typename MeshType::template PerVertexAttributeHandle PerVertexCoordHandle; - - typedef typename MeshType::template PerFaceAttributeHandle PerFaceScalarHandle; - typedef typename MeshType::template PerFaceAttributeHandle PerFaceIntHandle; - typedef typename MeshType::template PerFaceAttributeHandle PerFaceBoolHandle; - typedef typename MeshType::template PerFaceAttributeHandle PerFaceCoordHandle; - - typedef typename MeshType::template PerTetraAttributeHandle PerTetraScalarHandle; - typedef typename MeshType::template PerTetraAttributeHandle PerTetraIntHandle; - typedef typename MeshType::template PerTetraAttributeHandle PerTetraBoolHandle; - typedef typename MeshType::template PerTetraAttributeHandle PerTetraCoordHandle; - - - // the camera member (that should keep the intrinsics) is no more needed since 2006, when intrisncs moved into the Shot structure - //Camera camera; // intrinsic - Shot shot; // intrinsic && extrinsic - -private: - /// The per-mesh color. Not very useful and meaningful... - Color4b c; + : public MArity5< BaseMeshTypeHolder, Container0, Der ,Container1, Der, Container2, Der, Container3, Der, Container4, Der >{ public: - inline const Color4b &C() const { return c; } - inline Color4b &C() { return c; } - inline Color4b cC() const { return c; } + typedef typename TriMesh::ScalarType ScalarType; + typedef typename TriMesh::VertContainer VertContainer; + typedef typename TriMesh::EdgeContainer EdgeContainer; + typedef typename TriMesh::FaceContainer FaceContainer; + typedef typename TriMesh::TetraContainer TetraContainer; - /// Default constructor - TriMesh() - { - Clear(); - } + // types for vertex + typedef typename TriMesh::VertexType VertexType; + typedef typename TriMesh::VertexPointer VertexPointer; + typedef typename TriMesh::ConstVertexPointer ConstVertexPointer; + typedef typename TriMesh::CoordType CoordType; + typedef typename TriMesh::VertexIterator VertexIterator; + typedef typename TriMesh::ConstVertexIterator ConstVertexIterator; - /// destructor - ~TriMesh() - { - Clear(); - } + // types for edge + typedef typename TriMesh::EdgeType EdgeType; + typedef typename TriMesh::EdgePointer EdgePointer; + typedef typename TriMesh::ConstEdgePointer ConstEdgePointer; + typedef typename TriMesh::EdgeIterator EdgeIterator; + typedef typename TriMesh::ConstEdgeIterator ConstEdgeIterator; - int Mem(const int & nv, const int & nf, const int & nt) const { - typename std::set< PointerToAttribute>::const_iterator i; - int size = 0; - size += sizeof(TriMesh)+sizeof(VertexType)*nv+sizeof(FaceType)*nf; + //types for face + typedef typename TriMesh::FaceType FaceType; + typedef typename TriMesh::ConstFaceIterator ConstFaceIterator; + typedef typename TriMesh::FaceIterator FaceIterator; + typedef typename TriMesh::FacePointer FacePointer; + typedef typename TriMesh::ConstFacePointer ConstFacePointer; - for( i = vert_attr.begin(); i != vert_attr.end(); ++i) - size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf()*nv; - for( i = edge_attr.begin(); i != edge_attr.end(); ++i) - size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf()*en; - for( i = face_attr.begin(); i != face_attr.end(); ++i) - size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf()*nf; - for (i = tetra_attr.begin(); i != tetra_attr.end(); ++i) - size += ((SimpleTempDataBase *)(*i)._handle)->SizeOf() * nt; - for( i = mesh_attr.begin(); i != mesh_attr.end(); ++i) - size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf(); + // types for hedge + typedef typename TriMesh::HEdgeType HEdgeType; + typedef typename TriMesh::HEdgePointer HEdgePointer; + typedef typename TriMesh::HEdgeIterator HEdgeIterator; + typedef typename TriMesh::HEdgeContainer HEdgeContainer; + typedef typename TriMesh::ConstHEdgeIterator ConstHEdgeIterator; - return size; - } - int MemUsed() const {return Mem(vert.size(),face.size(), tetra.size());} - inline int MemNeeded() const {return Mem(vn,fn);} + // types for tetra + typedef typename TriMesh::TetraType TetraType; + typedef typename TriMesh::TetraPointer TetraPointer; + typedef typename TriMesh::TetraIterator TetraIterator; + typedef typename TriMesh::ConstTetraIterator ConstTetraIterator; + + typedef vcg::PointerToAttribute PointerToAttribute; + + typedef TriMesh MeshType; + + typedef Box3 BoxType; + + /// Container of vertices, usually a vector. + VertContainer vert; + /// Current number of vertices; this member is for internal use only. You should always use the VN() member + int vn; + /// Current number of vertices + inline int VN() const { return vn; } + + /// Container of edges, usually a vector. + EdgeContainer edge; + /// Current number of edges; this member is for internal use only. You should always use the EN() member + int en; + /// Current number of edges + inline int EN() const { return en; } + + /// Container of faces, usually a vector. + FaceContainer face; + /// Current number of faces; this member is for internal use only. You should always use the FN() member + int fn; + /// Current number of faces + inline int FN() const { return fn; } + + /// Container of half edges, usually a vector. + HEdgeContainer hedge; + /// Current number of halfedges; this member is for internal use only. You should always use the HN() member + int hn; + /// Current number of halfedges; + inline int HN() const { return hn; } + + /// Container of tetras, usually a vector. + TetraContainer tetra; + /// Current number of tetras; this member is for internal use only. You should always use the TN() member + int tn; + /// Current number of tetras; + inline int TN() const { return tn; } + + /// Bounding box of the mesh + Box3 bbox; + + /// Nomi di textures + // + std::vector textures; + // + std::vector normalmaps; + + int attrn; // total numer of attribute created - - /// Function to destroy the mesh - void Clear() - { - for(FaceIterator fi = face.begin(); fi != face.end(); ++fi) - (*fi).Dealloc(); - vert.clear(); - face.clear(); - edge.clear(); - tetra.clear(); -// textures.clear(); -// normalmaps.clear(); - vn = 0; - en = 0; - fn = 0; - hn = 0; - tn = 0; - imark = 0; - C()=Color4b::Gray; - } + std::set< PointerToAttribute > vert_attr; + std::set< PointerToAttribute > edge_attr; + std::set< PointerToAttribute > face_attr; + std::set< PointerToAttribute > mesh_attr; + std::set< PointerToAttribute > tetra_attr; - void ClearAttributes() - { - // Clear attributes - typename std::set< PointerToAttribute>::iterator i; - for (i = vert_attr.begin(); i != vert_attr.end(); ++i) - delete ((SimpleTempDataBase*)(*i)._handle); - vert_attr.clear(); + template + class AttributeHandle{ + public: + AttributeHandle(){_handle=(SimpleTempData *)NULL;} + AttributeHandle( void *ah,const int & n):_handle ( (SimpleTempData *)ah ),n_attr(n){} + AttributeHandle operator = ( const PointerToAttribute & pva){ + _handle = (SimpleTempData *)pva._handle; + n_attr = pva.n_attr; + return (*this); + } - for (i = edge_attr.begin(); i != edge_attr.end(); ++i) - delete ((SimpleTempDataBase*)(*i)._handle); - edge_attr.clear(); + //pointer to the SimpleTempData that stores the attribute + SimpleTempData * _handle; - for (i = face_attr.begin(); i != face_attr.end(); ++i) - delete ((SimpleTempDataBase*)(*i)._handle); - face_attr.clear(); + // its attribute number + int n_attr; - for (i = tetra_attr.begin(); i != tetra_attr.end(); ++i) - delete ((SimpleTempDataBase *)(*i)._handle); - tetra_attr.clear(); + // access function + template + ATTR_TYPE & operator [](const RefType & i){return (*_handle)[i];} + void resize(size_t /*size*/) { }; + }; - for (i = mesh_attr.begin(); i != mesh_attr.end(); ++i) - delete ((SimpleTempDataBase*)(*i)._handle); - mesh_attr.clear(); - attrn = 0; - } + template + class PerVertexAttributeHandle: public AttributeHandle{ + public: + PerVertexAttributeHandle():AttributeHandle(){} + PerVertexAttributeHandle( void *ah,const int & n):AttributeHandle(ah,n){} + }; - bool IsEmpty() const - { - return vert.empty() && edge.empty() && face.empty() && tetra.empty(); - } - int & SimplexNumber(){ return fn;} - int & VertexNumber(){ return vn;} + template + class PerFaceAttributeHandle: public AttributeHandle{ + public: + PerFaceAttributeHandle():AttributeHandle(){} + PerFaceAttributeHandle( void *ah,const int & n):AttributeHandle(ah,n){} + }; - /// The incremental mark - int imark; + template + class PerEdgeAttributeHandle: public AttributeHandle{ + public: + PerEdgeAttributeHandle():AttributeHandle(){} + PerEdgeAttributeHandle( void *ah,const int & n):AttributeHandle(ah,n){} + }; + + template + class PerTetraAttributeHandle : public AttributeHandle + { + public: + PerTetraAttributeHandle() : AttributeHandle() {} + PerTetraAttributeHandle(void *ah, const int &n) : AttributeHandle(ah, n) {} + }; + + template + class PerMeshAttributeHandle{ + public: + PerMeshAttributeHandle(){_handle=NULL;} + PerMeshAttributeHandle(void *ah,const int & n):_handle ( (Attribute *)ah ),n_attr(n){} + PerMeshAttributeHandle operator = ( const PerMeshAttributeHandle & pva){ + _handle = (Attribute *)pva._handle; + n_attr = pva.n_attr; + return (*this); + } + + Attribute * _handle; + int n_attr; + ATTR_TYPE & operator ()(){ return *((Attribute *)_handle)->attribute;} + }; + + // Some common Handle typedefs to simplify use + typedef typename MeshType::template PerVertexAttributeHandle PerVertexScalarHandle; + typedef typename MeshType::template PerVertexAttributeHandle PerVertexIntHandle; + typedef typename MeshType::template PerVertexAttributeHandle PerVertexBoolHandle; + typedef typename MeshType::template PerVertexAttributeHandle PerVertexCoordHandle; + + typedef typename MeshType::template PerFaceAttributeHandle PerFaceScalarHandle; + typedef typename MeshType::template PerFaceAttributeHandle PerFaceIntHandle; + typedef typename MeshType::template PerFaceAttributeHandle PerFaceBoolHandle; + typedef typename MeshType::template PerFaceAttributeHandle PerFaceCoordHandle; + + typedef typename MeshType::template PerTetraAttributeHandle PerTetraScalarHandle; + typedef typename MeshType::template PerTetraAttributeHandle PerTetraIntHandle; + typedef typename MeshType::template PerTetraAttributeHandle PerTetraBoolHandle; + typedef typename MeshType::template PerTetraAttributeHandle PerTetraCoordHandle; + + + // the camera member (that should keep the intrinsics) is no more needed since 2006, when intrisncs moved into the Shot structure + //Camera camera; // intrinsic + Shot shot; // intrinsic && extrinsic private: - // TriMesh cannot be copied. Use Append (see vcg/complex/append.h) - TriMesh operator =(const TriMesh & /*m*/){assert(0);return TriMesh();} - TriMesh(const TriMesh & ){} + /// The per-mesh color. Not very useful and meaningful... + Color4b c; +public: + + inline const Color4b &C() const { return c; } + inline Color4b &C() { return c; } + inline Color4b cC() const { return c; } + + /// Default constructor + TriMesh() + { + Clear(); + } + + /// destructor + ~TriMesh() + { + Clear(); + } + + int Mem(const int & nv, const int & nf, const int & nt) const { + typename std::set< PointerToAttribute>::const_iterator i; + int size = 0; + size += sizeof(TriMesh)+sizeof(VertexType)*nv+sizeof(FaceType)*nf; + + for( i = vert_attr.begin(); i != vert_attr.end(); ++i) + size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf()*nv; + for( i = edge_attr.begin(); i != edge_attr.end(); ++i) + size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf()*en; + for( i = face_attr.begin(); i != face_attr.end(); ++i) + size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf()*nf; + for (i = tetra_attr.begin(); i != tetra_attr.end(); ++i) + size += ((SimpleTempDataBase *)(*i)._handle)->SizeOf() * nt; + for( i = mesh_attr.begin(); i != mesh_attr.end(); ++i) + size += ((SimpleTempDataBase*)(*i)._handle)->SizeOf(); + + return size; + } + int MemUsed() const {return Mem(vert.size(),face.size(), tetra.size());} + inline int MemNeeded() const {return Mem(vn,fn);} + + + + /// Function to destroy the mesh + void Clear() + { + for(FaceIterator fi = face.begin(); fi != face.end(); ++fi) + (*fi).Dealloc(); + vert.clear(); + face.clear(); + edge.clear(); + tetra.clear(); + // textures.clear(); + // normalmaps.clear(); + vn = 0; + en = 0; + fn = 0; + hn = 0; + tn = 0; + imark = 0; + C()=Color4b::Gray; + } + + + void ClearAttributes() + { + // Clear attributes + typename std::set< PointerToAttribute>::iterator i; + for (i = vert_attr.begin(); i != vert_attr.end(); ++i) + delete ((SimpleTempDataBase*)(*i)._handle); + vert_attr.clear(); + + for (i = edge_attr.begin(); i != edge_attr.end(); ++i) + delete ((SimpleTempDataBase*)(*i)._handle); + edge_attr.clear(); + + for (i = face_attr.begin(); i != face_attr.end(); ++i) + delete ((SimpleTempDataBase*)(*i)._handle); + face_attr.clear(); + + for (i = tetra_attr.begin(); i != tetra_attr.end(); ++i) + delete ((SimpleTempDataBase *)(*i)._handle); + tetra_attr.clear(); + + for (i = mesh_attr.begin(); i != mesh_attr.end(); ++i) + delete ((SimpleTempDataBase*)(*i)._handle); + mesh_attr.clear(); + attrn = 0; + } + + bool IsEmpty() const + { + return vert.empty() && edge.empty() && face.empty() && tetra.empty(); + } + + int & SimplexNumber(){ return fn;} + int & VertexNumber(){ return vn;} + + /// The incremental mark + int imark; + +private: + // TriMesh cannot be copied. Use Append (see vcg/complex/append.h) + TriMesh operator =(const TriMesh & /*m*/){assert(0);return TriMesh();} + TriMesh(const TriMesh & ){} }; // end class Mesh /// Initialize the imark-system of the faces template inline void InitFaceIMark(MeshType & m) { - typename MeshType::FaceIterator f; + typename MeshType::FaceIterator f; - for(f=m.face.begin();f!=m.face.end();++f) - if( !(*f).IsD() && (*f).IsR() && (*f).IsW() ) - (*f).InitIMark(); + for(f=m.face.begin();f!=m.face.end();++f) + if( !(*f).IsD() && (*f).IsR() && (*f).IsW() ) + (*f).InitIMark(); } /// Initialize the imark-system of the vertices template inline void InitVertexIMark(MeshType & m) { - typename MeshType::VertexIterator vi; + typename MeshType::VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if( !(*vi).IsD() && (*vi).IsRW() ) - (*vi).InitIMark(); + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if( !(*vi).IsD() && (*vi).IsRW() ) + (*vi).InitIMark(); +} +/// Initialize the imark-system of the edges +template inline void InitEdgeIMark(MeshType & m) +{ + typename MeshType::EdgeIterator ei; + + for (ei = m.edge.begin(); ei != m.edge.end(); ++ei) + if( !(*ei).IsD() && (*ei).IsRW() ) + (*ei).InitIMark(); } ///initialize the imark-sysyem of the tetras template inline void InitTetraIMark(MeshType &m) { - typename MeshType::TetraIterator ti; + typename MeshType::TetraIterator ti; - for (ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) - if (!(*ti).IsD() && (*ti).IsRW()) - (*ti).InitIMark(); + for (ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) + if (!(*ti).IsD() && (*ti).IsRW()) + (*ti).InitIMark(); } /** \brief Access function to the incremental mark. @@ -507,47 +519,57 @@ inline void InitTetraIMark(MeshType &m) template inline int & IMark(MeshType & m){return m.imark;} /** \brief Check if the vertex incremental mark matches the one of the mesh. - @param m the mesh containing the element - @param v Vertex pointer */ + @param m the mesh containing the element + @param v Vertex pointer */ template inline bool IsMarked(MeshType & m, typename MeshType::ConstVertexPointer v ) { return v->cIMark() == m.imark; } +/** \brief Check if the edge incremental mark matches the one of the mesh. + @param m the mesh containing the element + @param e edge pointer */ +template inline bool IsMarked(MeshType & m, typename MeshType::ConstEdgePointer e ) { return e->cIMark() == m.imark; } + /** \brief Check if the face incremental mark matches the one of the mesh. - @param m the mesh containing the element - @param f Face pointer */ + @param m the mesh containing the element + @param f Face pointer */ template inline bool IsMarked( MeshType & m,typename MeshType::ConstFacePointer f ) { return f->cIMark() == m.imark; } /** \brief Check if the tetra incremental mark matches the one of the mesh. - @param m the mesh containing the element - @param t tetra pointer */ + @param m the mesh containing the element + @param t tetra pointer */ template inline bool IsMarked(MeshType &m, typename MeshType::ConstTetraPointer t) { return t->cIMark() == m.imark; } /** \brief Set the vertex incremental mark of the vertex to the one of the mesh. - @param m the mesh containing the element - @param v Vertex pointer */ + @param m the mesh containing the element + @param v Vertex pointer */ template inline void Mark(MeshType & m, typename MeshType::VertexPointer v ) { v->IMark() = m.imark; } +/** \brief Set the edge incremental mark of the edge to the one of the mesh. + @param m the mesh containing the element + @param e edge pointer */ +template inline void Mark(MeshType & m, typename MeshType::EdgePointer e ) { e->IMark() = m.imark; } + /** \brief Set the face incremental mark of the vertex to the one of the mesh. - @param m the mesh containing the element - @param f Vertex pointer */ + @param m the mesh containing the element + @param f Vertex pointer */ template inline void Mark(MeshType & m, typename MeshType::FacePointer f ) { f->IMark() = m.imark; } /** \brief Set the tetra incremental mark to the one of the mesh. - @param m the mesh containing the element - @param t tetra pointer */ + @param m the mesh containing the element + @param t tetra pointer */ template inline void Mark(MeshType &m, typename MeshType::TetraPointer t) { t->IMark() = m.imark; } /** \brief Unmark, in constant time, all the elements (face and vertices) of a mesh. - @param m the mesh containing the element + @param m the mesh containing the element - In practice this function just increment the internal counter that stores the value for which an element is considered marked; - therefore all the mesh elements become immediately un-mmarked. - */ + In practice this function just increment the internal counter that stores the value for which an element is considered marked; + therefore all the mesh elements become immediately un-mmarked. + */ template inline void UnMarkAll(MeshType & m) { - ++m.imark; + ++m.imark; } @@ -714,60 +736,60 @@ bool HasHOppAdjacency (const TriMesh < CType0, CType1, CType2, CType3> & /*m*/) template bool HasPerVertexAttribute(const MeshType &m, std::string name){ - typename std::set< typename MeshType::PointerToAttribute>::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.vert_attr.find(h); - return (ai!= m.vert_attr.end() ) ; + typename std::set< typename MeshType::PointerToAttribute>::const_iterator ai; + typename MeshType::PointerToAttribute h; + h._name = name; + ai = m.vert_attr.find(h); + return (ai!= m.vert_attr.end() ) ; } template bool HasPerFaceAttribute(const MeshType &m, std::string name){ - typename std::set< typename MeshType::PointerToAttribute>::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.face_attr.find(h); - return (ai!= m.face_attr.end() ) ; + typename std::set< typename MeshType::PointerToAttribute>::const_iterator ai; + typename MeshType::PointerToAttribute h; + h._name = name; + ai = m.face_attr.find(h); + return (ai!= m.face_attr.end() ) ; } template bool HasPerTetraAttribute(const MeshType &m, std::string name) { - typename std::set::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.tetra_attr.find(h); - return (ai != m.tetra_attr.end()); + typename std::set::const_iterator ai; + typename MeshType::PointerToAttribute h; + h._name = name; + ai = m.tetra_attr.find(h); + return (ai != m.tetra_attr.end()); } template bool HasPerMeshAttribute(const MeshType &m, std::string name){ - typename std::set< typename MeshType::PointerToAttribute>::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.mesh_attr.find(h); - return (ai!= m.mesh_attr.end() ) ; + typename std::set< typename MeshType::PointerToAttribute>::const_iterator ai; + typename MeshType::PointerToAttribute h; + h._name = name; + ai = m.mesh_attr.find(h); + return (ai!= m.mesh_attr.end() ) ; } template void RequireVertexCompactness (MeshType &m) { - if(m.vert.size()!=size_t(m.vn)) throw vcg::MissingCompactnessException("Vertex Vector Contains deleted elements"); + if(m.vert.size()!=size_t(m.vn)) throw vcg::MissingCompactnessException("Vertex Vector Contains deleted elements"); } template void RequireFaceCompactness (MeshType &m) { - if(m.face.size()!=size_t(m.fn)) throw vcg::MissingCompactnessException("Face Vector Contains deleted elements"); + if(m.face.size()!=size_t(m.fn)) throw vcg::MissingCompactnessException("Face Vector Contains deleted elements"); } template void RequireEdgeCompactness (MeshType &m) { if(m.edge.size()!=size_t(m.en)) throw vcg::MissingCompactnessException("Edge Vector Contains deleted elements"); } template void RequireTetraCompactness(MeshType &m) { - if (m.tetra.size() != size_t(m.tn)) throw vcg::MissingCompactnessException("Tetra Vector Contains deleted elements"); + if (m.tetra.size() != size_t(m.tn)) throw vcg::MissingCompactnessException("Tetra Vector Contains deleted elements"); } template void RequireCompactness(MeshType &m) { - RequireVertexCompactness(m); - RequireFaceCompactness(m); - RequireEdgeCompactness(m); - RequireTetraCompactness(m); + RequireVertexCompactness(m); + RequireFaceCompactness(m); + RequireEdgeCompactness(m); + RequireTetraCompactness(m); } //todo require tetramesh diff --git a/vcg/simplex/edge/component.h b/vcg/simplex/edge/component.h index f614c6d2..a78ca4c6 100644 --- a/vcg/simplex/edge/component.h +++ b/vcg/simplex/edge/component.h @@ -27,10 +27,10 @@ #define __VCG_EDGE_PLUS_COMPONENT namespace vcg { - namespace edge { +namespace edge { - /** \addtogroup EdgeComponentGroup - @{ +/** \addtogroup EdgeComponentGroup + @{ */ /* @@ -38,120 +38,122 @@ Some naming Rules All the Components that can be added to a vertex should be defined in the namespace edge: */ - /*------------------------- EMPTY CORE COMPONENTS -----------------------------------------*/ +/*------------------------- EMPTY CORE COMPONENTS -----------------------------------------*/ template class EmptyCore: public T - { +{ public: - inline typename T::VertexType * & V( const int j ) { (void)j; assert(0); static typename T::VertexType *vp=0; return vp; } - inline typename T::VertexType * const & V( const int j ) const { (void)j; assert(0); static typename T::VertexType *vp=0; return vp; } - inline typename T::VertexType * cV( const int j ) const { (void)j; assert(0); static typename T::VertexType *vp=0; return vp; } - inline typename T::CoordType & P( const int j ) { (void)j; assert(0); static typename T::CoordType coord(0, 0, 0); return coord; } - inline const typename T::CoordType & P( const int j ) const { (void)j; assert(0); static typename T::CoordType coord(0, 0, 0); return coord; } - inline const typename T::CoordType & cP( const int j ) const { (void)j; assert(0); static typename T::CoordType coord(0, 0, 0); return coord; } - static bool HasEVAdjacency() { return false; } - static bool HasVertexRef() { return false; } + inline typename T::VertexType * & V( const int j ) { (void)j; assert(0); static typename T::VertexType *vp=0; return vp; } + inline typename T::VertexType * const & V( const int j ) const { (void)j; assert(0); static typename T::VertexType *vp=0; return vp; } + inline typename T::VertexType * cV( const int j ) const { (void)j; assert(0); static typename T::VertexType *vp=0; return vp; } + inline typename T::CoordType & P( const int j ) { (void)j; assert(0); static typename T::CoordType coord(0, 0, 0); return coord; } + inline const typename T::CoordType & P( const int j ) const { (void)j; assert(0); static typename T::CoordType coord(0, 0, 0); return coord; } + inline const typename T::CoordType & cP( const int j ) const { (void)j; assert(0); static typename T::CoordType coord(0, 0, 0); return coord; } + static bool HasEVAdjacency() { return false; } + static bool HasVertexRef() { return false; } - typedef vcg::Color4b ColorType; - ColorType &C() { static ColorType dumcolor(vcg::Color4b::White); assert(0); return dumcolor; } - ColorType cC() const { static ColorType dumcolor(vcg::Color4b::White); assert(0); return dumcolor; } - static bool HasColor() { return false; } + typedef vcg::Color4b ColorType; + ColorType &C() { static ColorType dumcolor(vcg::Color4b::White); assert(0); return dumcolor; } + ColorType cC() const { static ColorType dumcolor(vcg::Color4b::White); assert(0); return dumcolor; } + static bool HasColor() { return false; } - typedef float QualityType; - QualityType &Q() { static QualityType dummyQuality(0); assert(0); return dummyQuality; } - QualityType cQ() const { static QualityType dummyQuality(0); assert(0); return dummyQuality; } - static bool HasQuality() { return false; } + typedef float QualityType; + QualityType &Q() { static QualityType dummyQuality(0); assert(0); return dummyQuality; } + QualityType cQ() const { static QualityType dummyQuality(0); assert(0); return dummyQuality; } + static bool HasQuality() { return false; } - typedef int MarkType; - inline void InitIMark() { } - inline int cIMark() const { assert(0); static int tmp=-1; return tmp;} - inline int &IMark() { assert(0); static int tmp=-1; return tmp;} - static bool HasMark() { return false; } + typedef int MarkType; + inline void InitIMark() { } + inline int cIMark() const { assert(0); static int tmp=-1; return tmp;} + inline int &IMark() { assert(0); static int tmp=-1; return tmp;} + static bool HasMark() { return false; } + inline bool IsMarkEnabled( ) const { return T::EdgeType::HasMark(); } - typedef int FlagType; - int &Flags() { static int dummyflags(0); assert(0); return dummyflags; } - int Flags() const { return 0; } - static bool HasFlags() { return false; } - typename T::EdgePointer &VEp(const int & ) { static typename T::EdgePointer ep=0; assert(0); return ep; } - typename T::EdgePointer cVEp(const int & ) const { static typename T::EdgePointer ep=0; assert(0); return ep; } - int &VEi(const int &){static int z=0; assert(0); return z;} - int cVEi(const int &) const {static int z=0; assert(0); return z;} - static bool HasVEAdjacency() { return false; } + typedef int FlagType; + int &Flags() { static int dummyflags(0); assert(0); return dummyflags; } + int Flags() const { return 0; } + static bool HasFlags() { return false; } - typename T::EdgePointer &EEp(const int & ) { static typename T::EdgePointer ep=0; assert(0); return ep; } - typename T::EdgePointer cEEp(const int & ) const { static typename T::EdgePointer ep=0; assert(0); return ep; } - int &EEi(const int &){static int z=0; assert(0); return z;} - int cEEi(const int &) const {static int z=0; assert(0); return z;} - static bool HasEEAdjacency() { return false; } + typename T::EdgePointer &VEp(const int & ) { static typename T::EdgePointer ep=0; assert(0); return ep; } + typename T::EdgePointer cVEp(const int & ) const { static typename T::EdgePointer ep=0; assert(0); return ep; } + int &VEi(const int &){static int z=0; assert(0); return z;} + int cVEi(const int &) const {static int z=0; assert(0); return z;} + static bool HasVEAdjacency() { return false; } - typename T::HEdgePointer &EHp( ) { static typename T::HEdgePointer hp=0; assert(0); return hp; } - typename T::HEdgePointer cEHp( ) const { static typename T::HEdgePointer hp=0; assert(0); return hp; } - static bool HasEHAdjacency() { return false; } + typename T::EdgePointer &EEp(const int & ) { static typename T::EdgePointer ep=0; assert(0); return ep; } + typename T::EdgePointer cEEp(const int & ) const { static typename T::EdgePointer ep=0; assert(0); return ep; } + int &EEi(const int &){static int z=0; assert(0); return z;} + int cEEi(const int &) const {static int z=0; assert(0); return z;} + static bool HasEEAdjacency() { return false; } - typename T::FacePointer &EFp() { static typename T::FacePointer fp=0; assert(0); return fp; } - typename T::FacePointer cEFp() const { static typename T::FacePointer fp=0; assert(0); return fp; } - int &EFi() {static int z=0; return z;} - int &cEFi() const {static int z=0; return z;} - static bool HasEFAdjacency() { return false; } + typename T::HEdgePointer &EHp( ) { static typename T::HEdgePointer hp=0; assert(0); return hp; } + typename T::HEdgePointer cEHp( ) const { static typename T::HEdgePointer hp=0; assert(0); return hp; } + static bool HasEHAdjacency() { return false; } - template - void ImportData(const LeftF & leftF) {T::ImportData(leftF);} - static void Name(std::vector & name){T::Name(name);} - }; + typename T::FacePointer &EFp() { static typename T::FacePointer fp=0; assert(0); return fp; } + typename T::FacePointer cEFp() const { static typename T::FacePointer fp=0; assert(0); return fp; } + int &EFi() {static int z=0; return z;} + int &cEFi() const {static int z=0; return z;} + static bool HasEFAdjacency() { return false; } - /*-------------------------- VertexRef ----------------------------------------*/ - /*! \brief The references to the two vertexes of a edge + template + void ImportData(const LeftF & leftF) {T::ImportData(leftF);} + static void Name(std::vector & name){T::Name(name);} +}; + +/*-------------------------- VertexRef ----------------------------------------*/ +/*! \brief The references to the two vertexes of a edge * * Stored as pointers to the VertexType */ template class VertexRef: public T { public: - VertexRef(){ - v[0]=0; - v[1]=0; - } + VertexRef(){ + v[0]=0; + v[1]=0; + } - typedef typename T::VertexType::CoordType CoordType; - typedef typename T::VertexType::ScalarType ScalarType; + typedef typename T::VertexType::CoordType CoordType; + typedef typename T::VertexType::ScalarType ScalarType; - inline typename T::VertexType * & V( const int j ) { assert(j>=0 && j<2); return v[j]; } - inline typename T::VertexType * const & V( const int j ) const { assert(j>=0 && j<2); return v[j]; } - inline typename T::VertexType * cV( const int j ) const { assert(j>=0 && j<2); return v[j]; } + inline typename T::VertexType * & V( const int j ) { assert(j>=0 && j<2); return v[j]; } + inline typename T::VertexType * const & V( const int j ) const { assert(j>=0 && j<2); return v[j]; } + inline typename T::VertexType * cV( const int j ) const { assert(j>=0 && j<2); return v[j]; } - // Shortcut per accedere ai punti delle facce - inline CoordType & P( const int j ) { assert(j>=0 && j<2); return v[j]->P(); } - inline const CoordType &cP( const int j ) const { assert(j>=0 && j<2); return v[j]->P(); } + // Shortcut per accedere ai punti delle facce + inline CoordType & P( const int j ) { assert(j>=0 && j<2); return v[j]->P(); } + inline const CoordType &cP( const int j ) const { assert(j>=0 && j<2); return v[j]->P(); } - /** Return the pointer to the ((j+1)%3)-th vertex of the face. - @param j Index of the face vertex. - */ - inline typename T::VertexType * & V0( const int j ) { return V(j);} - inline typename T::VertexType * & V1( const int j ) { return V((j+1)%2);} - inline const typename T::VertexType * const & V0( const int j ) const { return V(j);} - inline const typename T::VertexType * const & V1( const int j ) const { return V((j+1)%2);} - inline const typename T::VertexType * const & cV0( const int j ) const { return cV(j);} - inline const typename T::VertexType * const & cV1( const int j ) const { return cV((j+1)%2);} + /** Return the pointer to the ((j+1)%3)-th vertex of the face. + @param j Index of the face vertex. + */ + inline typename T::VertexType * & V0( const int j ) { return V(j);} + inline typename T::VertexType * & V1( const int j ) { return V((j+1)%2);} + inline const typename T::VertexType * const & V0( const int j ) const { return V(j);} + inline const typename T::VertexType * const & V1( const int j ) const { return V((j+1)%2);} + inline const typename T::VertexType * const & cV0( const int j ) const { return cV(j);} + inline const typename T::VertexType * const & cV1( const int j ) const { return cV((j+1)%2);} - /// Shortcut per accedere ai punti delle facce - inline CoordType & P0( const int j ) { return V(j)->P();} - inline CoordType & P1( const int j ) { return V((j+1)%2)->P();} - inline const CoordType & P0( const int j ) const { return V(j)->P();} - inline const CoordType & P1( const int j ) const { return V((j+1)%2)->P();} - inline const CoordType & cP0( const int j ) const { return cV(j)->P();} - inline const CoordType & cP1( const int j ) const { return cV((j+1)%2)->P();} + /// Shortcut per accedere ai punti delle facce + inline CoordType & P0( const int j ) { return V(j)->P();} + inline CoordType & P1( const int j ) { return V((j+1)%2)->P();} + inline const CoordType & P0( const int j ) const { return V(j)->P();} + inline const CoordType & P1( const int j ) const { return V((j+1)%2)->P();} + inline const CoordType & cP0( const int j ) const { return cV(j)->P();} + inline const CoordType & cP1( const int j ) const { return cV((j+1)%2)->P();} - template - void ImportData(const LeftF & leftF){ T::ImportData(leftF);} + template + void ImportData(const LeftF & leftF){ T::ImportData(leftF);} - static bool HasEVAdjacency() { return true; } - static bool HasVertexRef() { return true; } - static void Name(std::vector & name){name.push_back(std::string("VertexRef"));T::Name(name);} + static bool HasEVAdjacency() { return true; } + static bool HasVertexRef() { return true; } + static void Name(std::vector & name){name.push_back(std::string("VertexRef"));T::Name(name);} - private: - typename T::VertexType *v[2]; +private: + typename T::VertexType *v[2]; }; template class EVAdj : public VertexRef{}; @@ -165,68 +167,74 @@ template class EVAdj : public VertexRef{}; */ template class Mark: public T { public: - Mark():_imark(0){} - static bool HasMark() { return true; } - static bool HasMarkOcc() { return true; } - inline void InitIMark() { _imark = 0; } - inline int & IMark() { return _imark;} - inline const int & IMark() const {return _imark;} - template < class LeftV> - void ImportData(const LeftV & left ) { IMark() = left.IMark(); T::ImportData( left); } - static void Name(std::vector & name){name.push_back(std::string("Mark"));T::Name(name);} + Mark():_imark(0){} + static bool HasMark() { return true; } + static bool HasMarkOcc() { return true; } + inline void InitIMark() { _imark = 0; } + inline int & IMark() { return _imark;} + inline int cIMark() const { return _imark;} - private: - int _imark; + template < class RightValueType> + void ImportData(const RightValueType & rightE ) + { + if(rightE.IsMarkEnabled()) + IMark() = rightE.cIMark(); + T::ImportData(rightE); + } + static void Name(std::vector & name){name.push_back(std::string("Mark"));T::Name(name);} + +private: + int _imark; }; /*------------------------- FLAGS -----------------------------------------*/ - /*! \brief \em Component: Per edge \b Flags +/*! \brief \em Component: Per edge \b Flags * * This component stores a 32 bit array of bit flags. These bit flags are used for keeping track of selection, deletion, visiting etc. \sa \ref flags for more details on common uses of flags. */ template class BitFlags: public T { public: - BitFlags(){_flags=0;} - typedef int FlagType; - int &Flags() {return _flags; } - int Flags() const {return _flags; } - template < class LeftV> - void ImportData(const LeftV & left ) { Flags() = left.Flags(); T::ImportData( left); } - static bool HasFlags() { return true; } - static void Name(std::vector & name){name.push_back(std::string("BitFlags"));T::Name(name);} + BitFlags(){_flags=0;} + typedef int FlagType; + int &Flags() {return _flags; } + int Flags() const {return _flags; } + template < class LeftV> + void ImportData(const LeftV & left ) { Flags() = left.Flags(); T::ImportData( left); } + static bool HasFlags() { return true; } + static void Name(std::vector & name){name.push_back(std::string("BitFlags"));T::Name(name);} private: - int _flags; + int _flags; }; /*-------------------------- Color ----------------------------------*/ - /*! \brief \em Component: Per edge \b Color +/*! \brief \em Component: Per edge \b Color * * Usually most of the library expects a color stored as 4 unsigned chars (so the component you use is a \c vertex::Color4b) * but you can also use float for the color components. */ template class Color: public T { public: - Color():_color(vcg::Color4b::White) {} - typedef A ColorType; - ColorType &C() { return _color; } - const ColorType &C() const { return _color; } - const ColorType &cC() const { return _color; } - template < class LeftV> - void ImportData(const LeftV & left ) { C() = left.cC(); T::ImportData( left); } - static bool HasColor() { return true; } - static void Name(std::vector & name){name.push_back(std::string("Color"));T::Name(name);} + Color():_color(vcg::Color4b::White) {} + typedef A ColorType; + ColorType &C() { return _color; } + const ColorType &C() const { return _color; } + const ColorType &cC() const { return _color; } + template < class LeftV> + void ImportData(const LeftV & left ) { C() = left.cC(); T::ImportData( left); } + static bool HasColor() { return true; } + static void Name(std::vector & name){name.push_back(std::string("Color"));T::Name(name);} private: - ColorType _color; + ColorType _color; }; template class Color4b: public edge::Color { - public: static void Name(std::vector & name){name.push_back(std::string("Color4b"));TT::Name(name);} +public: static void Name(std::vector & name){name.push_back(std::string("Color4b"));TT::Name(name);} }; /*-------------------------- Quality ----------------------------------*/ - /*! \brief \em Component: Per edge \b quality +/*! \brief \em Component: Per edge \b quality * * The Quality Component is a generic place for storing a float. The term 'quality' is a bit misleading and it is due to its original storic meaning. You should intend it as a general purpose container. * \sa vcg::tri::UpdateColor for methods transforming quality into colors @@ -234,16 +242,16 @@ template class Color4b: public edge::Color { */ template class Quality: public TT { public: - typedef A QualityType; - QualityType &Q() { return _quality; } - const QualityType & cQ() const {return _quality; } - template < class LeftV> - void ImportData(const LeftV & left ) { Q() = left.cQ(); TT::ImportData( left); } - static bool HasQuality() { return true; } - static void Name(std::vector & name){name.push_back(std::string("Quality"));TT::Name(name);} + typedef A QualityType; + QualityType &Q() { return _quality; } + const QualityType & cQ() const {return _quality; } + template < class LeftV> + void ImportData(const LeftV & left ) { Q() = left.cQ(); TT::ImportData( left); } + static bool HasQuality() { return true; } + static void Name(std::vector & name){name.push_back(std::string("Quality"));TT::Name(name);} private: - QualityType _quality; + QualityType _quality; }; template class Qualitys: public Quality { @@ -257,34 +265,34 @@ public: static void Name(std::vector & name){name.push_back(std::st }; /*----------------------------- VEADJ ------------------------------*/ - /*! \brief \em Component: Per vertex \b Vertex-Edge adjacency relation companion component +/*! \brief \em Component: Per vertex \b Vertex-Edge adjacency relation companion component This component implement one element of the list of edges incident on a vertex. You must use this component only toghether with the corresponding \ref vcg::vertex::VEAdj component in the vertex type \sa vcg::tri::UpdateTopology for functions that compute this relation \sa iterators */ - template class VEAdj: public T { - public: - VEAdj(){_ep[0]=0;_ep[1]=0;_zp[0]=-1;_zp[1]=-1;} - typename T::EdgePointer &VEp(const int & i) {return _ep[i]; } - typename T::EdgePointer cVEp(const int & i) const {return _ep[i]; } - int &VEi(const int & i){ return _zp[i];} - int cVEi(const int &i )const {return _zp[i];} +template class VEAdj: public T { +public: + VEAdj(){_ep[0]=0;_ep[1]=0;_zp[0]=-1;_zp[1]=-1;} + typename T::EdgePointer &VEp(const int & i) {return _ep[i]; } + typename T::EdgePointer cVEp(const int & i) const {return _ep[i]; } + int &VEi(const int & i){ return _zp[i];} + int cVEi(const int &i )const {return _zp[i];} - template < class LeftV> - void ImportData(const LeftV & left ) { T::ImportData( left); } - static bool HasVEAdjacency() { return true; } - static bool HasVEAdjacencyOcc() { return true; } - static void Name(std::vector & name){name.push_back(std::string("VEAdj"));T::Name(name);} + template < class LeftV> + void ImportData(const LeftV & left ) { T::ImportData( left); } + static bool HasVEAdjacency() { return true; } + static bool HasVEAdjacencyOcc() { return true; } + static void Name(std::vector & name){name.push_back(std::string("VEAdj"));T::Name(name);} - private: - typename T::EdgePointer _ep[2] ; - int _zp[2] ; - }; +private: + typename T::EdgePointer _ep[2] ; + int _zp[2] ; +}; /*----------------------------- EEADJ ------------------------------*/ - /*! \brief \em Component: \b Edge-Edge adjacency relation +/*! \brief \em Component: \b Edge-Edge adjacency relation This component implement store the pointer (and index) of the adjacent edges. If the vertex is 1-manifold (as in a classical polyline) it holds that: @@ -299,42 +307,42 @@ public: static void Name(std::vector & name){name.push_back(std::st template class EEAdj: public T { public: - EEAdj(){_ep[0]=0;_ep[1]=0;_zp[0]=-1;_zp[1]=-1;} - typename T::EdgePointer &EEp(const int & i) {return _ep[i]; } - typename T::EdgePointer cEEp(const int & i) const {return _ep[i]; } - int &EEi(const int & i){ return _zp[i];} - int cEEi(const int &i )const {return _zp[i];} + EEAdj(){_ep[0]=0;_ep[1]=0;_zp[0]=-1;_zp[1]=-1;} + typename T::EdgePointer &EEp(const int & i) {return _ep[i]; } + typename T::EdgePointer cEEp(const int & i) const {return _ep[i]; } + int &EEi(const int & i){ return _zp[i];} + int cEEi(const int &i )const {return _zp[i];} - template < class LeftV> - void ImportData(const LeftV & left ) { T::ImportData( left); } - static bool HasEEAdjacency() { return true; } - static bool HasEEAdjacencyOcc() { return true; } - static void Name(std::vector & name){name.push_back(std::string("EEAdj"));T::Name(name);} + template < class LeftV> + void ImportData(const LeftV & left ) { T::ImportData( left); } + static bool HasEEAdjacency() { return true; } + static bool HasEEAdjacencyOcc() { return true; } + static void Name(std::vector & name){name.push_back(std::string("EEAdj"));T::Name(name);} private: - typename T::EdgePointer _ep[2] ; - int _zp[2] ; + typename T::EdgePointer _ep[2] ; + int _zp[2] ; }; /*----------------------------- EHADJ ------------------------------*/ template class EHAdj: public T { public: - EHAdj(){_hp=0;} - typename T::HEdgePointer &EHp( ) {return _hp ; } - const typename T::HEdgePointer cEHp( ) const {return _hp ; } + EHAdj(){_hp=0;} + typename T::HEdgePointer &EHp( ) {return _hp ; } + const typename T::HEdgePointer cEHp( ) const {return _hp ; } - template < class LeftV> - void ImportData(const LeftV & left ) { T::ImportData( left); } - static bool HasEHAdjacency() { return true; } - static bool HasEHAdjacencyOcc() { return true; } - static void Name(std::vector & name){name.push_back(std::string("EHAdj"));T::Name(name);} + template < class LeftV> + void ImportData(const LeftV & left ) { T::ImportData( left); } + static bool HasEHAdjacency() { return true; } + static bool HasEHAdjacencyOcc() { return true; } + static void Name(std::vector & name){name.push_back(std::string("EHAdj"));T::Name(name);} private: - typename T::HEdgePointer _hp ; + typename T::HEdgePointer _hp ; }; /*----------------------------- EFADJ ------------------------------*/ - /*! \brief \em Component: \b Edge-Face adjacency relation +/*! \brief \em Component: \b Edge-Face adjacency relation This component implement store the pointer to a face sharing this edge. \sa vcg::tri::UpdateTopology for functions that compute this relation @@ -343,23 +351,23 @@ private: template class EFAdj: public T { public: - EFAdj(){_fp=0;} - typename T::FacePointer &EFp() {return _fp; } - typename T::FacePointer cEFp() const {return _fp; } - int &EFi() {return _zp; } - int cEFi() const {return _zp; } - template < class LeftV> - void ImportData(const LeftV & left ) { T::ImportData( left); } - static bool HasEFAdjacency() { return true; } - static bool HasEFAdjacencyOcc() { return true; } - static void Name(std::vector & name){name.push_back(std::string("EFAdj"));T::Name(name);} + EFAdj(){_fp=0;} + typename T::FacePointer &EFp() {return _fp; } + typename T::FacePointer cEFp() const {return _fp; } + int &EFi() {return _zp; } + int cEFi() const {return _zp; } + template < class LeftV> + void ImportData(const LeftV & left ) { T::ImportData( left); } + static bool HasEFAdjacency() { return true; } + static bool HasEFAdjacencyOcc() { return true; } + static void Name(std::vector & name){name.push_back(std::string("EFAdj"));T::Name(name);} private: - typename T::FacePointer _fp ; - int _zp ; + typename T::FacePointer _fp ; + int _zp ; }; - /** @} */ // End Doxygen EdgeComponentGroup - } // end namespace edge +/** @} */ // End Doxygen EdgeComponentGroup +} // end namespace edge }// end namespace vcg #endif