From d8e79083e031d1de608ecc3b699a1ef65ffdc910 Mon Sep 17 00:00:00 2001 From: cnr-isti-vclab Date: Tue, 11 Oct 2005 16:03:40 +0000 Subject: [PATCH] Added new functions belonging to triMeshInfo Started the Self-Intersection routine --- vcg/complex/trimesh/clean.h | 714 ++++++++++++++++++++++++++++++------ 1 file changed, 600 insertions(+), 114 deletions(-) diff --git a/vcg/complex/trimesh/clean.h b/vcg/complex/trimesh/clean.h index 6a6bfa02..9ec8b988 100644 --- a/vcg/complex/trimesh/clean.h +++ b/vcg/complex/trimesh/clean.h @@ -21,9 +21,12 @@ * * ****************************************************************************/ /**************************************************************************** - History +History $Log: not supported by cvs2svn $ +Revision 1.7 2005/10/03 15:57:53 rita_borgo +Alligned with TriMeshInfo Code + Revision 1.6 2005/01/28 11:59:35 cignoni Add std:: to stl containers @@ -51,130 +54,613 @@ Initial Release #include #include +#include +#include +#include +#include + #include + + namespace vcg { -namespace tri { -/// -/** \addtogroup trimesh */ -/*@{*/ -/// Class of static functions to clean/correct/restore meshs. -template -class Clean -{ - public: - typedef CleanMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; -/* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/ -template -class RemoveDuplicateVert_Compare{ -public: - inline bool operator() (VertexIterator a, VertexIterator b) + namespace tri{ + /// + /** \addtogroup trimesh */ + /*@{*/ + /// Class of static functions to clean/correct/restore meshs. + template + class Clean { - return *a < *b; - } -}; + public: + typedef CleanMeshType 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::FaceContainer FaceContainer; -/** This function removes all duplicate vertices of the mesh by looking only at their spatial positions. - 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 RemoveDuplicateVertex( MeshType & m ) // V1.0 -{ - if(m.vert.size()==0 || m.vn==0) return 0; + typedef GridStaticPtr TriMeshGrid; + typedef Point3 Point3x; - std::map mp; - int i,j; - VertexIterator vi; - int deleted=0; - int k=0; - int num_vert = m.vert.size(); - std::vector perm(num_vert); - for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi, ++k) - perm[k] = &(*vi); + TriMeshGrid gM; + FaceIterator fi; + FaceIterator gi; + vcg::face::Pos he; + vcg::face::Pos hei; - 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; - (*t).SetD(); - deleted++; - } - else - { - j = i; - ++i; - } - } - FaceIterator fi; - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - for(k = 0; k < 3; ++k) - if( !(*fi).IsD() ) - if( mp.find( (typename MeshType::VertexPointer)(*fi).V(k) ) != mp.end() ) + /* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/ + template + class RemoveDuplicateVert_Compare{ + public: + inline bool operator() (VertexIterator a, VertexIterator b) { - (*fi).V(k) = &*mp[ (*fi).V(k) ]; + return *a < *b; } - m.vn -= deleted; - return deleted; -} + }; + + static void Initialize(MeshType& m) + { + FaceIterator fi; + for(fi=m.face.begin();fi!=m.face.end();fi++) + { + (*fi).ClearB(0); + (*fi).ClearB(1); + (*fi).ClearB(2); + (*fi).ClearS(); + } + } + + static int DetectUnreferencedVertex( MeshType& m ) // V1.0 + { + int count_uv = 0; + MeshType::VertexIterator v; + FaceIterator fi; + + for(v=m.vert.begin();v!=m.vert.end();++v) + (*v).ClearV(); + + for(fi=m.face.begin();fi!=m.face.end();++fi) + for(int j=0;j<3;++j) + (*fi).V(j)->SetV(); + + for(v=m.vert.begin();v!=m.vert.end();++v) + if( !(*v).IsV() ) + ++count_uv; + return count_uv; + + } + + /** This function removes all duplicate vertices of the mesh by looking only at their spatial positions. + 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 RemoveDuplicateVertex( MeshType & m ) // V1.0 + { + if(m.vert.size()==0 || m.vn==0) return 0; + + std::map mp; + int i,j; + VertexIterator vi; + int deleted=0; + int k=0; + int 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; + (*t).SetD(); + deleted++; + } + else + { + j = i; + ++i; + } + } + FaceIterator fi; + for(fi = m.face.begin(); fi!=m.face.end(); ++fi) + for(k = 0; k < 3; ++k) + if( !(*fi).IsD() ) + if( mp.find( (typename MeshType::VertexPointer)(*fi).V(k) ) != mp.end() ) + { + (*fi).V(k) = &*mp[ (*fi).V(k) ]; + } + m.vn -= deleted; + return deleted; + } -/** This function removes that are not referenced by any face. The function updates the vn counter. - @param m The mesh - @return The number of removed vertices -*/ -static int RemoveUnreferencedVertex( CleanMeshType& m ) // V1.0 -{ - FaceIterator fi; - VertexIterator vi; - int referredBit = VertexType::NewBitFlag(); - - int j; - int deleted = 0; + /** This function removes that are not referenced by any face. The function updates the vn counter. + @param m The mesh + @return The number of removed vertices + */ + static int RemoveUnreferencedVertex( MeshType& m ) // V1.0 + { + FaceIterator fi; + VertexIterator vi; + int referredBit = VertexType::NewBitFlag(); + + int j; + int deleted = 0; + + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + (*vi).ClearUserBit(referredBit); + + for(fi=m.face.begin();fi!=m.face.end();++fi) + if( !(*fi).IsD() ) + for(j=0;j<3;++j) + (*fi).V(j)->SetUserBit(referredBit); + + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if( (!(*vi).IsD()) && (!(*vi).IsUserBit(referredBit))) + { + (*vi).SetD(); + ++deleted; + } + m.vn -= deleted; + VertexType::DeleteBitFlag(referredBit); + return deleted; + } + + + static bool IsComplexManifold( MeshType & m ) + { + FaceIterator fi; + bool Manifold = true; + for( fi=m.face.begin();fi!=m.face.end();++fi) + { + for (int j=0;j<3;j++) + { + if(!IsManifold(*fi,j)) + { + Manifold = false; + fi= m.face.end(); + --fi; + j=3; + } + } + if((BorderCount(*fi)>0)) + { + Manifold = false; + fi= m.face.end(); + --fi; + } + } + return Manifold; + } + + static void CountEdges( MeshType & m, int &count_e, int &boundary_e ) + { + FaceIterator fi; + vcg::face::Pos he; + vcg::face::Pos hei; + bool counted =false; + for(fi=m.face.begin();fi!=m.face.end();fi++) + { + (*fi).SetS(); + count_e +=3; //assume that we have to increase the number of edges with three + for(int j=0; j<3; j++) + { + if (fi->IsBorder(j)) //If this edge is a border edge + boundary_e++; // then increase the number of boundary edges + else if (IsManifold(*fi,j))//If this edge is manifold + { + if((*fi).FFp(j)->IsS()) //If the face on the other side of the edge is already selected + count_e--; // we counted one edge twice + } + else//We have a non-manifold edge + { + hei.Set(&(*fi), j , fi->V(j)); + he=hei; + he.NextF(); + while (he.f!=hei.f)// so we have to iterate all faces that are connected to this edge + { + if (he.f->IsS())// if one of the other faces was already visited than this edge was counted already. + { + counted=true; + break; + } + else + { + he.NextF(); + } + } + if (counted) + { + count_e--; + counted=false; + } + } + } + } + } + + + static int CountHoles( MeshType & m) + { + int numholes=0; + int numholev=0; + int BEdges=0; + FaceIterator fi; + FaceIterator gi; + vcg::face::Pos he; + vcg::face::Pos hei; + + vector > holes; //indices of vertices + + for(fi=m.face.begin();fi!=m.face.end();++fi) + (*fi).ClearS(); + gi=m.face.begin(); fi=gi; + + + + for(fi=m.face.begin();fi!=m.face.end();fi++)//for all faces do + { + for(int j=0;j<3;j++)//for all edges + { + if(fi->V(j)->IsS()) continue; + + if((*fi).IsBorder(j))//found an unvisited border edge + { + he.Set(&(*fi),j,fi->V(j)); //set the face-face iterator to the current face, edge and vertex + vector hole; //start of a new hole + hole.push_back(fi->P(j)); // including the first vertex + numholev++; + he.v->SetS(); //set the current vertex as selected + he.NextB(); //go to the next boundary edge + + + while(fi->V(j) != he.v)//will we do not encounter the first boundary edge. + { + Point3x newpoint = he.v->P(); //select its vertex. + if(he.v->IsS())//check if this vertex was selected already, because then we have an additional hole. + { + //cut and paste the additional hole. + vector hole2; + int index = find(hole.begin(),hole.end(),newpoint) - hole.begin(); + for(int i=index; iSetS(); //set the current vertex as selected + he.NextB(); //go to the next boundary edge + } + holes.push_back(hole); + } + } + } + return holes.size(); + } + + static int BorderEdges( MeshType & m, int numholes) + { + int BEdges = 0; + for(int i=0; i he; + vcg::face::Pos hei; + + vector nrfaces; + nrfaces.reserve(1); + + for(fi=m.face.begin();fi!=m.face.end();++fi) + (*fi).ClearS(); + gi=m.face.begin(); fi=gi; + int Compindex=0; + stack sf; + MeshType::FaceType *l; + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + if (!(*fi).IsS()) + { + (*fi).SetS(); + //(*fi).Q()=Compindex; + nrfaces.push_back(1); + sf.push(fi); + while (!sf.empty()) + { + gi=sf.top(); + he.Set(&(*gi),0,gi->V(0)); + sf.pop(); + for(int j=0;j<3;++j) + { + if( !(*gi).IsBorder(j) ) + { + l=he.f->FFp(j); + if( !(*l).IsS() ) + { + (*l).SetS(); + sf.push(l); + } + } + } + } + Compindex++; + } + } + return Compindex; + } + + static int DegeneratedFaces(MeshType& m) + { + FaceIterator fi; + int count_fd = 0; + + + for(fi=m.face.begin(); fi!=m.face.end();++fi) + if((*fi).Area() == 0) + count_fd++; + return count_fd; + } + + static float MeshGenus(MeshType &m, int count_uv, int numholes, int numcomponents, int count_e) + { + int eulernumber = (m.vn-count_uv) + m.fn - count_e; + return(-( 0.5 * (eulernumber - numholes) - numcomponents )); + } + + static void IsRegularMesh(MeshType &m, bool Regular, bool Semiregular) + { + int inc=0; + VertexIterator v; + FaceIterator fi; + vcg::face::Pos he; + vcg::face::Pos hei; + for(v=m.vert.begin();v!=m.vert.end();++v) + (*v).ClearS(); + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + for (int j=0; j<3; j++) + { + he.Set(&(*fi),j,fi->V(j)); + if (!(*fi).IsBorder(j) && !(*fi).IsBorder((j+2)%3) && !fi->V(j)->IsS()) + { + hei=he; + inc=1; + he.FlipE(); + he.NextF(); + while (he.f!=hei.f) + { + he.FlipE(); + if (he.IsBorder()) + { + inc=6; + break; + } + he.NextF(); + inc++; + } + if (inc!=6) + Regular=false; + if (inc!=6 && inc!=5) + Semiregular=false; + fi->V(j)->SetS(); + + } + else + fi->V(j)->SetS(); + } + if (Semiregular==false) + break; + + } + + } + + static void IsOrientedMesh(MeshType &m, bool Oriented, bool Orientable) + { + FaceIterator fi; + FaceIterator gi; + vcg::face::Pos he; + vcg::face::Pos hei; + stack sf; + MeshType::FacePointer l; + + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + (*fi).ClearS(); + (*fi).ClearUserBit(0); + } + gi=m.face.begin(); fi=gi; + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + if (!(*fi).IsS()) + { + (*fi).SetS(); + sf.push(fi); + + while (!sf.empty()) + { + gi=sf.top(); + sf.pop(); + for(int j=0;j<3;++j) + { + if( !(*gi).IsBorder(j) ) + { + he.Set(&(*gi),0,gi->V(0)); + l=he.f->FFp(j); + he.Set(&(*gi),j,gi->V(j)); + hei.Set(he.f->FFp(j),he.f->FFi(j), (he.f->FFp(j))->V(he.f->FFi(j))); + if( !(*gi).IsUserBit(0) ) + { + if (he.v!=hei.v)// bene + { + if ((*l).IsS() && (*l).IsUserBit(0)) + { + Orientable=false; + break; + } + else if (!(*l).IsS()) + { + (*l).SetS(); + sf.push(l); + } + } + else if (!(*l).IsS()) + { + Oriented=false; + (*l).SetS(); + (*l).SetUserBit(0); + sf.push(l); + } + else if ((*l).IsS() && !(*l).IsUserBit(0)) + { + Orientable=false; + break; + } + } + else if (he.v==hei.v)// bene + { + if ((*l).IsS() && (*l).IsUserBit(0)) + { + Orientable=false; + break; + } + else if (!(*l).IsS()) + { + (*l).SetS(); + sf.push(l); + } + } + else if (!(*l).IsS()) + { + Oriented=false; + (*l).SetS(); + (*l).SetUserBit(0); + sf.push(l); + } + else if ((*l).IsS() && !(*l).IsUserBit(0)) + { + Orientable=false; + break; + } + } + } + } + } + if (!Orientable) + break; + } + } + + static bool SelfIntersections(MeshType &m) + { + + Box3< ScalarType> bbox; + TriMeshGrid gM; + + int nelem; + bbox = m.bbox; + double bdiag = bbox.Diag(); + + FaceType *f=0; + Point3x normf, bestq, ip,p; + FaceIterator fi; + + + + std::vector ret; + std::vector inCell; + gM.Set::iterator>(m.face.begin(),m.face.end()); + + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + + // f = vcg::trimesh::GetClosestFace(m, gM, p, bdiag, bdiag, normf, bestq, ip); + // fill the cell +/*....*/ + nelem = inCell.size(); + if (nelem>=2)// in a cell + { + //test combinations of elements + for (int i=0;iIsD())&&(!inCell[j]->IsD())&&(TestIntersection(inCell[i],inCell[j]))) + { + ret.push_back(inCell[i]); + ret.push_back(inCell[j]); + } + } + } + return false; + } + + + //test real intersection between faces +static bool TestIntersection(FaceType *f0,FaceType *f1) + { + assert((!f0->IsD())&&(!f1->IsD())); + //no adiacent faces + if ((f0!=f1)&& (!ShareEdge(f0,f1)) + && (!ShareVertex(f0,f1))) + return (vcg::Intersection((*f0),(*f1))); + return false; + } + + //control if two faces share an edge +static bool ShareEdge(FaceType *f0,FaceType *f1) + { + assert((!f0->IsD())&&(!f1->IsD())); + for (int i=0;i<3;i++) + if (f0->FFp(i)==f1) + return (true); + + return(false); + } + + //control if two faces share a vertex +static bool ShareVertex(FaceType *f0,FaceType *f1) + { + assert((!f0->IsD())&&(!f1->IsD())); + for (int i=0;i<3;i++) + for (int j=0;j<3;j++) + if (f0->V(i)==f1->V(j)) + return (true); + + return(false); + } + + + }; // end class + /*@}*/ - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - (*vi).ClearUserBit(referredBit); - - for(fi=m.face.begin();fi!=m.face.end();++fi) - if( !(*fi).IsD() ) - for(j=0;j<3;++j) - (*fi).V(j)->SetUserBit(referredBit); - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if( (!(*vi).IsD()) && (!(*vi).IsUserBit(referredBit))) - { - (*vi).SetD(); - ++deleted; - } - m.vn -= deleted; - VertexType::DeleteBitFlag(referredBit); - return deleted; -} - - - - - -}; // end class -/*@}*/ -} // End Namespace TriMesh + } //End Namespace Tri } // End Namespace vcg #endif