/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCGLIB_HALFEDGE_ #define __VCGLIB_HALFEDGE_ #include #include #include #include #include #include namespace vcg { namespace tri{ /// \ingroup trimesh /// \headerfile edge_support.h vcg/complex/algorithms/edge_support.h /// \brief This class is used to build edge based data structure from indexed data structure and viceversa /** */ template class UpdateHalfEdges{ public: typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::VertexIterator VertexIterator; typedef typename MeshType::HEdgePointer HEdgePointer; typedef typename MeshType::HEdgeType HEdgeType; typedef typename MeshType::EdgePointer EdgePointer; typedef typename MeshType::EdgeType EdgeType; typedef typename MeshType::EdgeIterator EdgeIterator; typedef typename MeshType::HEdgeIterator HEdgeIterator; typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceType FaceType; struct VertexPairEdgePtr{ VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,HEdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);} const bool operator <(const VertexPairEdgePtr &o) const {return (v0 == o.v0)? (v1 BitVector; /** build a half-edge data structure from an indexed data structure. Note that the half-edges are allocated here for the first time. If you have a mesh where there are already edges, they will be removed and the data lost, so do not use this function to just "update" the topology of half edges. **/ static void FromIndexed(MeshType & m){ assert(HasFVAdjacency(m)); assert(HasHOppAdjacency(m)); assert(HasHNextAdjacency(m)); typename MeshType::template PerFaceAttributeHandle flagVisited = vcg::tri::Allocator::template AddPerFaceAttribute(m,""); std::vector borderEdges; // allocate all new half edges FaceIterator fi; unsigned int n_edges = 0; // count how many half edge to allocate for(fi = m.face.begin(); fi != m.face.end(); ++fi) if(! (*fi).IsD()) {n_edges+=(*fi).VN(); for(int i = 0; i < (*fi).VN(); ++i) if(vcg::face::IsBorder((*fi),(i))) ++n_edges; } m.hedge.clear(); m.hn = 0; // allocate the half edges typename MeshType::HEdgeIterator ei = vcg::tri::Allocator::AddHEdges(m,n_edges); std::vector all; int firstEdge = 0; for(fi = m.face.begin(); fi != m.face.end(); ++fi)if(!(*fi).IsD()){ assert((*fi).VN()>2); if(flagVisited[*fi].empty()) {flagVisited[*fi].resize((*fi).VN());} for(int i = 0; i < (*fi).VN(); ++i,++ei) { (*ei).HVp() = (*fi).V(i); (*ei).HNp() = &m.hedge[firstEdge + (i +1) % (*fi).VN()]; if(MeshType::HEdgeType::HasHFAdjacency()) (*ei).HFp() = &(*fi); if( MeshType::FaceType::HasFHAdjacency()) (*fi).FHp() = &(*ei); if(MeshType::HEdgeType::HasHPrevAdjacency()) (*ei).HPp() = &m.hedge[firstEdge + (i +(*fi).VN()-1) % (*fi).VN()]; if(HasVHAdjacency(m)) (*ei).HVp()->VHp() = &(*ei); all.push_back(VertexPairEdgePtr((*fi).V(i), (*fi).V((*fi).Next(i)),&(*ei)));// it will be used to link the hedges if( vcg::face::IsBorder((*fi),(i))) borderEdges.push_back(FacePtrInt(&(*fi),i)); } firstEdge += (*fi).VN(); } // add all the border hedges int borderLength; typename std::vector::iterator ebi; for( ebi = borderEdges.begin(); ebi != borderEdges.end(); ++ebi) if( !flagVisited[(*ebi).f][(*ebi).i])// not already inserted { borderLength = 0; vcg::face::Pos bp((*ebi).f,(*ebi).i); //FaceType * start = (*ebi).f; VertexType * start = ((*ebi).f)->V((*ebi).i); do{ all.push_back( VertexPairEdgePtr ( bp.f->V( bp.f->Next(bp.z) ),bp.f->V( bp.z ),&(*ei))); (*ei).HVp() = bp.f->V(bp.f->Next(bp.z)) ; flagVisited[bp.f][bp.z] = true; ++ei; bp.NextB(); ++borderLength; }while (bp.v != start); //}while (bp.f != start); // run over the border edges to link the adjacencies for(int be = 0; be < borderLength; ++be) { if(MeshType::HEdgeType::HasHFAdjacency()) m.hedge[firstEdge + be].HFp() = NULL; if(MeshType::HEdgeType::HasHPrevAdjacency()) m.hedge[firstEdge + be].HPp() = &m.hedge[firstEdge + (be +borderLength-1) % borderLength]; m.hedge[firstEdge + be].HNp() = &m.hedge[firstEdge + (be +1) % borderLength]; } firstEdge+=borderLength; } vcg::tri::Allocator:: template DeletePerFaceAttribute(m,flagVisited ); std::sort(all.begin(),all.end()); assert(all.size() == n_edges); for(unsigned int i = 0 ; i < all.size(); ) if(all[i] == all[i+1]) { all[i].ep->HOp() = all[i+1].ep; all[i+1].ep->HOp() = all[i].ep; i+=2; } else { all[i].ep->HOp() = all[i].ep; i+=1; } if(HasEHAdjacency(m) && HasHEAdjacency(m)) { assert(m.edge.size() == 0 || m.edge.size() == n_edges/2); if ( m.edge.size() == 0 ) { m.en = 0; // allocate the edges typename MeshType::EdgeIterator edge_i = vcg::tri::Allocator::AddEdges(m,n_edges/2); for(ei = m.hedge.begin(); ei != m.hedge.end(); ++ei) { if((*ei).HEp() == NULL) { (*ei).HEp() = &(*edge_i); (*ei).HOp()->HEp() = &(*edge_i); (*edge_i).EHp() = &(*ei); ++edge_i; } } } else { if(HasEVAdjacency(m) && HasHEAdjacency(m) && HasEHAdjacency(m)) { //update edge relations for(typename MeshType::EdgeIterator ei1 = m.edge.begin(); ei1 != m.edge.end(); ++ei1 ) { vector hedges = HalfEdgeTopology::get_incident_hedges((*ei1).V(0)); for(typename vector::iterator hi = hedges.begin(); hi != hedges.end(); ++hi) { if((*hi)->HOp()->HVp() == (*ei1).V(1)) { assert((*hi)->HEp() == NULL); assert((*hi)->HOp()->HEp() == NULL); // EH (*ei1).EHp() = *hi; // HE (*hi)->HEp() = &(*ei1); (*hi)->HOp()->HEp() = &(*ei1); break; } } } } } } } /** Checks pointers FHEp() are valid **/ static bool CheckConsistency_FHp(MeshType & m){ assert(MeshType::FaceType::HasFHAdjacency()); FaceIterator fi; for(fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD()){ if((*fi).FHp() < &(*m.hedge.begin())) return false; if((*fi).FHp() > &(m.hedge.back())) return false; } return true; } /** Checks that half edges and face relation are consistent **/ static bool CheckConsistency(MeshType & m){ assert(MeshType::HEdgeType::HasHNextAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency()); assert(MeshType::FaceType::HasFHAdjacency()); //bool hasHEF = ( MeshType::HEdgeType::HasHFAdjacency()); bool hasHP = ( MeshType::HEdgeType::HasHPrevAdjacency()); FaceIterator fi; HEdgePointer ep,ep1; int cnt = 0; if( MeshType::HEdgeType::HasHFAdjacency() ) { int iDb = 0; for(fi = m.face.begin(); fi != m.face.end(); ++fi,++iDb) if(!(*fi).IsD()) { ep = ep1 = (*fi).FHp(); do{ if(ep->IsD()) return false; // the hedge should not be connected, it has been deleted if( ! ep->HFp()) return false; if(ep->HFp() != &(*fi)) return false;// hedge is not pointing to the rigth face ep = ep->HNp(); if(cnt++ > m.hn) return false; // hedges are ill connected (HENp()) }while(ep!=ep1); } } HEdgePointer epPrev; HEdgeIterator hi; //bool extEdge ; for( hi = m.hedge.begin(); hi != m.hedge.end(); ++hi) if(!(*hi).IsD()) { //cnt = 0; epPrev = ep = ep1 = &(*hi); //do{ //extEdge = (ep->HFp()==NULL); if(hasHP) { if( !ep->HPp()) return false; if( ep->HPp() == ep) return false; // the previous of an edge cannot be the edge itself if( ep->HNp()->HPp() != ep) return false; // next and prev relation are not mutual if( ep->HPp()->IsD()) return false; // } if( ! ep->HOp() ) return false; if( ep->HOp() == ep) return false; // opposite relation is not mutual if( ep->HOp()->IsD()) return false; if( ep->HOp()->HOp() != ep) return false; // opposite relation is not mutual if( HasHFAdjacency(m) ) { if(ep->HFp()) { if( ep->HFp()->IsD()) return false; // pointed face must not be deleted } } if( HasHEAdjacency(m) && (m.en!=0)) { if( ! ep->HEp()) return false; //halfedge must point to an edge if( ep->HEp()->IsD()) return false; // pointed edge must not be deleted if(ep->HEp() != ep->HOp()->HEp()) return false; // he and opposite he must point to the same edge if(ep->HEp()->EHp() != ep && ep->HEp()->EHp() != ep->HOp() ) return false; // halfedge points to an edge not pointing it or its opposite } if( !ep->HNp() ) return false; if( ep->HNp() == ep ) return false; // the next of an hedge cannot be the hedge itself if( ep->HNp()->IsD()) return false; // if(hasHP) if( ep->HNp()->HPp() != ep) return false; // if( HasHVAdjacency(m) ) { if( ! ep->HVp() ) return false; // halfedge must point to a vertex if( ep->HVp()->IsD() ) return false; // pointed vertex must not be deleted if( HasVHAdjacency(m) ) if( ! (ep->HVp()->VHp()) ) return false; // halfedge points to a vertex pointing NULL } ep = ep->HNp(); if( ep->HVp() != epPrev->HOp()->HVp()) return false; epPrev = ep; // if(cnt++ > m.hn) // return false; // edges are ill connected (HENp()) //}while(ep!=ep1); } if(HasEHAdjacency(m) && HasHEAdjacency(m)) for(EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) { if(!(*ei).IsD()) { if( !(*ei).EHp()) return false; //edge must have a valid pointer to his halfedge if( (*ei).EHp()->HEp() != &(*ei) ) return false; // edge's halfedge must point to the edge itself if( (*ei).EHp()->IsD()) return false; } } if(HasVHAdjacency(m)) for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) { if( !(*vi).IsD() ) if( (*vi).VHp() ) { if( (*vi).VHp()->HVp() != &(*vi) ) return false; if( (*vi).VHp()->IsD()) return false; } } return true; } /** Set the relations HFp(), FHp() from a loop of edges to a face */ private: static void SetRelationsLoopFace(HEdgeType * e0, FaceType * f){ assert(HEdgeType::HasHNextAdjacency()); assert(FaceType::HasFHAdjacency()); HEdgeType *e = e0; assert(e!=NULL); do{ e->HFp() = f; e = e->HNp(); } while(e != e0); f->FHp() = e0; } /** Merge the two faces. This will probably become a class template or a functor */ static void MergeFaces(FaceType *, FaceType *){} /** Find previous hedge in the loop */ static HEdgeType * PreviousEdge(HEdgeType * e0){ HEdgeType * ep = e0; do{ if(ep->HNp() == e0) return ep; ep = ep->HNp(); }while(ep!=e0); assert(0); // degenerate loop return 0; } public: /** Adds an edge between the sources of e0 and e1 and set all the topology relations. If the edges store the pointers to the faces then a new face is created. <--- e1 ---- X <------e1_HEPp--- ^ || ei0 || ei1 || v ----e0_HEPp-> X ----- e0 ------> */ static void AddHEdge(MeshType &m, HEdgeType * e0, HEdgeType * e1){ HEdgeType *iii =e0->HNp(); assert(e1!=e0->HNp()); assert(e0!=e1->HNp()); HEdgePointer tmp; bool hasP = MeshType::HEdgeType::HasHPrevAdjacency(); assert(e0->HOp() != e1); // the hedge already exists assert(e0!=e1->HNp()); std::vector toUpdate; toUpdate.push_back(&e0); toUpdate.push_back(&e1); HEdgeIterator ei0 = vcg::tri::Allocator::AddHEdges(m,2,toUpdate); HEdgeIterator ei1 = ei0; ++ei1; (*ei0).HNp() = e1;(*ei0).HVp() = e0->HVp(); (*ei1).HNp() = e0;(*ei1).HVp() = e1->HVp(); HEdgePointer e0_HEPp = 0,e1_HEPp = 0,ep =0; if(hasP){ e0_HEPp = e0->HPp(); e1_HEPp = e1->HPp(); }else{// does not have pointer to previous, it must be computed ep = e0; do{ if(ep->HNp() == e0) e0_HEPp = ep; if(ep->HNp() == e1) e1_HEPp = ep; ep = ep->HNp(); }while(ep!=e0); } if(hasP){ (*ei0).HPp() = e0->HPp(); (*ei1).HPp() = e1->HPp(); e0->HPp() = &(*ei1); e1->HPp() = &(*ei0); } e0_HEPp -> HNp() = &(*ei0); e1_HEPp -> HNp() = &(*ei1); (*ei0).HOp() = &(*ei1); (*ei1).HOp() = &(*ei0); if( HEdgeType::HasHFAdjacency() && FaceType::HasFHAdjacency()){ FaceIterator fi0 = vcg::tri::Allocator::AddFaces(m,1); m.face.back().ImportData(*e0->HFp()); SetRelationsLoopFace(&(*ei0),e1->HFp()); // one loop to the old face SetRelationsLoopFace(&(*ei1),&m.face.back()); // the other to the new face } } /** Detach the topology relations of a given edge <--- e->HENPp -X --- <---------eO_HEPp--- ^ || e || e->HEOp() || v ----e_HEPp--> X ----- e->HEOp->HENPp() ------> */ static void RemoveHEdge(MeshType &m, HEdgeType * e){ assert(MeshType::HEdgeType::HasHNextAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::FaceType::HasFHAdjacency()); bool hasP = MeshType::HEdgeType::HasHPrevAdjacency(); HEdgePointer e_HEPp,eO_HEPp; if(hasP){ e_HEPp = e->HPp(); eO_HEPp = e->HOp()->HPp(); }else{ e_HEPp = PreviousEdge(e); eO_HEPp = PreviousEdge(e->HOp()); } assert(e_HEPp->HNp() == e); assert(eO_HEPp->HNp() == e->HOp()); e_HEPp->HNp() = e->HOp()->HNp(); eO_HEPp->HNp() = e-> HNp(); if(hasP) { e->HOp()->HNp()->HPp() = e_HEPp; e->HNp()->HPp() = eO_HEPp; e->HPp() = NULL; e-> HOp()->HPp() = NULL; } // take care of the faces if(MeshType::HEdgeType::HasHFAdjacency()){ MergeFaces(e_HEPp->HFp(),eO_HEPp->HFp()); vcg::tri::Allocator::DeleteFace(m,*eO_HEPp->HFp()); SetRelationsLoopFace(e_HEPp,e_HEPp->HFp()); } vcg::tri::Allocator::DeleteHEdge(m,*e->HOp()); vcg::tri::Allocator::DeleteHEdge(m,*e); } };// end class template struct UpdateIndexed{ typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::HEdgePointer HEdgePointer; typedef typename MeshType::HEdgeType HEdgeType; typedef typename MeshType::HEdgeIterator HEdgeIterator; typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceType FaceType; struct VertexPairEdgePtr{ VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,HEdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);} const bool operator <(const VertexPairEdgePtr &o) const {return (v0 == o.v0)? (v1 hV = Allocator::template AddPerHEdgeAttribute(m,""); typename MeshType::HEdgeIterator ei; typename MeshType::FacePointer fp; typename MeshType::FaceIterator fi; typename MeshType::HEdgePointer ep,epF; //int vi = 0; vcg::SimpleTempData hV(m.hedge); hasHEF = (MeshType::HEdgeType::HasHFAdjacency()); assert( !hasHEF || (hasHEF && m.fn>0)); // if the edgetype has the pointer to face // it is assumed the the edget2face pointer (HEFp) are correct // and the faces are allocated for ( ei = m.hedge.begin(); ei != m.hedge.end(); ++ei) if(!(*ei).IsD()) // it has not been deleted if(!hasHEF || ( hasHEF && (*ei).HFp()!=NULL)) // if it has a pointer to the face it is // not null (i.e. it is not a border edge) if(!hV[(*ei)] ) // it has not be visited yet { if(!hasHEF)// if it has fp = &(* Allocator::AddFaces(m,1)); else fp = (*ei).HFp(); ep = epF = &(*ei); std::vector vpts; do{vpts.push_back((*ep).HVp()); ep=ep->HNp();}while(ep!=epF); //int idbg =fp->VN(); if(fp->VN() != vpts.size()){ fp->Dealloc(); fp ->Alloc(vpts.size()); } //int idbg1 =fp->VN(); for(unsigned int i = 0; i < vpts.size();++i) fp ->V(i) = vpts[i];// set the pointer from face to vertex hV[(*ei)] = true; } //Allocator::DeletePerHEdgeAttribute(m,hV); } }; } // end namespace vcg } #endif // __VCGLIB_EDGE_SUPPORT