#ifndef VCG_HEDGE_TOPOLOGY #define VCG_HEDGE_TOPOLOGY #include #include #include #include using namespace std; using namespace vcg::hedge; using namespace vcg::tri; namespace vcg { namespace tri { /*! * \brief Class containing functions to modify the topology of a halfedge based mesh * */ template class HalfEdgeTopology { public: typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::EdgePointer EdgePointer; typedef typename MeshType::HEdgePointer HEdgePointer; typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::VertexIterator VertexIterator; typedef typename MeshType::EdgeIterator EdgeIterator; typedef typename MeshType::HEdgeIterator HEdgeIterator; typedef typename MeshType::FaceIterator FaceIterator; /*! * Collpases an edge shared by two quads, generating only quads. * Made by a series of a vertex rotation and a diagonal collapse. * * \param m Mesh * \param ep Edge to be collapsed * \param vp Vertex that will be rotated * * \return Pointer to the new vertex */ static VertexPointer edge_collapse_quad(MeshType &m, EdgePointer ep, VertexPointer vp) { assert(vp); assert(ep); assert(MeshType::EdgeType::HasEHAdjacency()); assert(MeshType::HEdgeType::HasHEAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency()); assert(ep->EHp()->HVp() == vp || ep->EHp()->HOp()->HVp() == vp); assert(ep->EHp()->HFp()->VN() == 4); assert(ep->EHp()->HOp()->HFp()->VN() == 4); VertexPointer vp_opp = ep->EHp()->HOp()->HVp(); VertexPointer vp_rot = vertex_rotate( m, vp ); assert(vp_rot == vp); FacePointer fp; //retrieve right face Pos p(vp->VHp(),true); while(p.HE()->HNp->HOp()->HVp() != vp_opp) { p.FlipE(); p.FlipF(); } fp = p.F(); return diagonal_collapse( m, fp, vp ); } /*! * Collpases a diagonal in a quad. * * * \param m Mesh * \param fp Face where diagonal resides * \param vp One of the two vertices of the diagonal * * \return Pointer to the new vertex */ static VertexPointer diagonal_collapse(MeshType &m, FacePointer fp, VertexPointer vp) { assert(MeshType::VertexType::HasVHAdjacency()); assert(MeshType::EdgeType::HasEHAdjacency()); assert(MeshType::FaceType::HasFHAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency()); assert(MeshType::HEdgeType::HasHEAdjacency()); assert(MeshType::HEdgeType::HasHFAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHPrevAdjacency()); assert(fp); assert(fp->FHp()); assert(fp->VN() == 4); if( !can_remove_face(fp) ) return NULL; HEdgePointer hp; vector vps = getVertices(fp); VertexPointer opp_vert = NULL; for(unsigned int i = 0; i< vps.size(); i++) if(vps[i] == vp) opp_vert = vps[(i+2)%vps.size()]; assert(opp_vert); if( fp->FHp()->HVp() == vp || fp->FHp()->HVp() == opp_vert) hp = fp->FHp(); else hp = fp->FHp()->HNp(); vector hps = getHEdges(fp,hp); int edge_cnt = 0; if(hps[0]->HOp()->HFp() || hps[1]->HOp()->HFp()) edge_cnt++; if(hps[2]->HOp()->HFp() || hps[3]->HOp()->HFp()) edge_cnt++; VertexIterator vi; if(edge_cnt > 0) { typename Allocator::template PointerUpdater puv; if(m.vert.empty()) puv.oldBase = 0; else { puv.oldBase = &*(m.vert.begin()); puv.oldEnd = &m.vert.back()+1; } vi = Allocator::AddVertices(m,1); EdgeIterator ei = Allocator::AddEdges(m,edge_cnt); puv.newBase = &*(m.vert.begin()); puv.newEnd = &m.vert.back()+1; if( puv.NeedUpdate() ) { puv.Update(vp); puv.Update(opp_vert); for(typename vector::iterator vpi = vps.begin(); vpi != vps.end(); ++vpi) puv.Update(*vpi); } typename Allocator::template PointerUpdater puh; if(m.hedge.empty()) puh.oldBase = 0; else { puh.oldBase = &*(m.hedge.begin()); puh.oldEnd = &m.hedge.back()+1; } HEdgeIterator hi = Allocator::AddHEdges(m,2*edge_cnt); puh.newBase = &*(m.hedge.begin()); puh.newEnd = &m.hedge.back()+1; if( puh.NeedUpdate() ) for(typename vector::iterator hpi = hps.begin(); hpi != hps.end(); ++hpi) puh.Update(*hpi); HEdgeIterator hi1 = hi; HEdgeIterator hi2 = hi; ++hi2; (*vi).VHp() = &(*hi1); change_vertex( hps[0]->HVp(), &(*vi)); change_vertex( hps[2]->HVp(), &(*vi)); for( int count = 0; count < 2; count++ ) { int i = 2*count; FacePointer fp1 = hps[i+1]->HOp()->HFp(); FacePointer fp2 = hps[i]->HOp()->HFp(); if( fp1 || fp2 ) { // HOp (*hi1).HOp() = &(*hi2); (*hi2).HOp() = &(*hi1); // EH (*ei).EHp() = &(*hi1); // HE (*hi1).HEp() = &(*ei); (*hi2).HEp() = &(*ei); // HV (*hi1).HVp() = &(*vi); (*hi2).HVp() = hps[i+1]->HVp(); // FH if( fp1 && ( fp1->FHp() == hps[i+1]->HOp() ) ) fp1->FHp() = &(*hi1); if( fp2 && ( fp2->FHp() == hps[i]->HOp() ) ) fp2->FHp() = &(*hi2); //HF (*hi1).HFp() = fp1; (*hi2).HFp() = fp2; //HNp (*hi1).HNp() = hps[i+1]->HOp()->HNp(); (*hi2).HNp() = hps[i]->HOp()->HNp(); (*hi1).HNp()->HPp() = &(*hi1); (*hi2).HNp()->HPp() = &(*hi2); //HPp (*hi1).HPp() = hps[i+1]->HOp()->HPp(); (*hi2).HPp() = hps[i]->HOp()->HPp(); (*hi1).HPp()->HNp() = &(*hi1); (*hi2).HPp()->HNp() = &(*hi2); //VH VertexPointer tmp = hps[i+1]->HVp(); if( tmp->VHp() == hps[i+1] || tmp->VHp() == hps[i]->HOp() ) tmp->VHp() = &(*hi2); ++ei; ++hi1; ++hi1; ++hi2; ++hi2; } else { hps[i+1]->HOp()->HPp()->HNp() = hps[i]->HOp()->HNp(); hps[i]->HOp()->HNp()->HPp() = hps[i+1]->HOp()->HPp(); hps[i+1]->HVp()->VHp() = NULL; } } } Allocator::DeleteFace(m, *(fp) ); Allocator::DeleteVertex(m, *(vp) ); Allocator::DeleteVertex(m, *(opp_vert) ); for(typename vector::iterator hpi = hps.begin(); hpi != hps.end(); ++hpi) { if(! (*hpi)->HEp()->IsD() ) Allocator::DeleteEdge(m, *((*hpi)->HEp()) ); if(! (*hpi)->IsD()) { Allocator::DeleteHEdge(m, *(*hpi) ); Allocator::DeleteHEdge(m, *((*hpi)->HOp()) ); } } if(edge_cnt > 0) return &(*vi); for(typename vector::iterator vpi = vps.begin(); vpi != vps.end(); ++vpi) if(!(*vpi)->IsD()) Allocator::DeleteVertex(m, *(*vpi) ); return NULL; } /*! * Removes a doublet merging the two quads in one * * \param m Mesh * \param vp Vertex shared by the two consecutive edges of the doublet * * \return Pointer to the new face */ static FacePointer doublet_remove(MeshType &m, VertexPointer vp) { assert(vp); HEdgePointer hp = vp->VHp(); assert(hp); FacePointer fp1 = hp->HFp(); FacePointer fp2 = hp->HOp()->HFp(); // check if face is a doublet assert( fp1 ); assert( fp1 == hp->HPp()->HFp() ); assert( fp2 ); assert( fp2 == hp->HOp()->HNp()->HFp() ); assert( hp->HOp()->HNp()->HOp() == hp->HPp() ); assert( fp1->VN() == 4); assert( fp2->VN() == 4); // end of check vector vert_face1 = getVertices(fp1, hp); vector vert_face2 = getVertices(fp2, hp->HOp()->HNp()); remove_face_unsafe(m, fp1 ); remove_face_unsafe(m, fp2 ); Allocator::DeleteVertex(m, *vp); vector new_face_vert; new_face_vert.push_back( vert_face1[1] ); new_face_vert.push_back( vert_face1[2] ); new_face_vert.push_back( vert_face1[3] ); new_face_vert.push_back( vert_face2[2] ); return add_face_unsafe(m, new_face_vert ); } /*! * Removes a singlet replacing it with an edge * * \param m Mesh * \param vp Vertex shared by the two consecutive edges inside the singlet * * \return Pointer to the new edge */ static EdgePointer singlet_remove(MeshType &m, VertexPointer vp) { assert( vp ); HEdgePointer hp = vp->VHp(); assert( hp ); FacePointer fp1 = hp->HFp(); FacePointer fp2 = hp->HOp()->HFp(); assert( fp1 && fp2 && fp1 == fp2 ); // the faces pointed by the halfedges must be the same HEdgePointer hp1 = hp->HNp()->HOp(); HEdgePointer hp2 = hp->HNp()->HNp()->HOp(); // pointers to the near faces FacePointer fp3 = hp1->HFp(); FacePointer fp4 = hp2->HFp(); Allocator::DeleteFace( m, *fp1 ); Allocator::DeleteEdge( m, *(hp->HEp()) ); Allocator::DeleteHEdge( m, *hp ); Allocator::DeleteHEdge( m, *(hp->HOp()) ); Allocator::DeleteVertex(m, *(vp) ); Allocator::DeleteEdge(m, *(hp1->HEp()) ); Allocator::DeleteEdge(m, *(hp2->HEp()) ); Allocator::DeleteHEdge( m, *(hp1->HOp()) ); Allocator::DeleteHEdge( m, *(hp2->HOp()) ); if(!fp3 && !fp4) // there are no faces, nothing has to be created { Allocator::DeleteHEdge( m, *hp1 ); Allocator::DeleteHEdge( m, *hp2 ); return NULL; } EdgeIterator ei = Allocator::AddEdges(m,1); (*ei).EHp() = hp1; hp1->HEp() = &(*ei); hp2->HEp() = &(*ei); hp1->HOp() = hp2; hp2->HOp() = hp1; return &(*ei); } /*! * Rotates a non-border edge shared by two quads * * \param m Mesh * \param ep Edge to be rotated * \param cw flag denoting a clockwise or counter-clockwise rotation * * \return Pointer to the rotated edge */ static EdgePointer edge_rotate(MeshType &m, EdgePointer ep, bool cw) { assert( MeshType::EdgeType::HasEHAdjacency() ); assert( MeshType::HEdgeType::HasHFAdjacency() ); assert( MeshType::HEdgeType::HasHOppAdjacency() ); assert( MeshType::FaceType::HasFHAdjacency() ); assert( ep->EHp()->HFp() ); assert( ep->EHp()->HFp()->VN() == 4 ); assert( ep->EHp()->HOp()->HFp() ); assert( ep->EHp()->HOp()->HFp()->VN() == 4 ); FacePointer fp1 = ep->EHp()->HFp(); FacePointer fp2 = ep->EHp()->HOp()->HFp(); vector old_face1 = getVertices( fp1, ep->EHp() ); vector old_face2 = getVertices( fp2, ep->EHp()->HOp() ); remove_face_unsafe(m, fp1); remove_face_unsafe(m, fp2); vector new_face1; vector new_face2; if(cw) { new_face1.push_back( old_face1[3] ); new_face1.push_back( old_face2[3] ); new_face1.push_back( old_face1[1] ); new_face1.push_back( old_face1[2] ); new_face2.push_back( old_face2[3] ); new_face2.push_back( old_face1[3] ); new_face2.push_back( old_face2[1] ); new_face2.push_back( old_face2[2] ); } else { new_face1.push_back( old_face1[2] ); new_face1.push_back( old_face1[3] ); new_face1.push_back( old_face1[0] ); new_face1.push_back( old_face2[2] ); new_face2.push_back( old_face2[2] ); new_face2.push_back( old_face2[3] ); new_face2.push_back( old_face2[0] ); new_face2.push_back( old_face1[2] ); } fp1 = add_face_unsafe(m, new_face1); fp2 = add_face_unsafe(m, new_face2); // retrieve inserted edge Pos p1( fp1->FHp(), true); while( p1.HE()->HOp()->HFp() != fp2 ) { p1.FlipV(); p1.FlipE(); } return p1.E(); } /*! * Rotates a non-border vertex shared by only quads * * \param m Mesh * \param vp Vertex to be rotated * * \return Pointer to the rotated vertex */ static VertexPointer vertex_rotate(MeshType &m, VertexPointer vp) { assert(MeshType::VertexType::HasVHAdjacency()); vector old_faces; typedef vector vert_vect; vector< vert_vect > old_face_verts; assert( vp->VHp() ); Pos p(vp->VHp(), true); HEdgePointer hep = p.HE(); do { assert( p.F() ); assert( p.F()->VN() == 4); old_faces.push_back(p.F()); old_face_verts.push_back( getVertices( p.F(), p.HE() ) ); p.FlipE(); p.FlipF(); }while(p.HE() != hep); assert( old_faces.size() == old_face_verts.size() ); int size = old_faces.size(); vector new_face_verts; for(int i = 0; i < size; i++) { new_face_verts.push_back(vector()); new_face_verts.back().push_back( old_face_verts[i][0] ); new_face_verts.back().push_back( old_face_verts[i][2] ); new_face_verts.back().push_back( old_face_verts[i][3] ); new_face_verts.back().push_back( old_face_verts[(i+1)%size][2] ); } for(typename vector::iterator fi = old_faces.begin(); fi != old_faces.end(); ++fi) remove_face_unsafe( m, *fi ); for(typename vector::iterator vi = new_face_verts.begin(); vi != new_face_verts.end(); ++vi) add_face_unsafe(m, *vi); return vp; } /*! * Collapses a generic edge * * \param m Mesh * \param ep Edge to be collapsed * \param vp Vertex to be deleted * * \return Pointer to the other vertex belonging to the collapsed edge */ static VertexPointer edge_collapse(MeshType &m, EdgePointer ep, VertexPointer vp) { assert(MeshType::EdgeType::HasEHAdjacency()); assert(MeshType::VertexType::HasVHAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency()); assert(MeshType::HEdgeType::HasHPrevAdjacency()); if( ep->EHp()->HFp() ) assert(ep->EHp()->HFp()->VN() > 3); if( ep->EHp()->HOp()->HFp()) assert(ep->EHp()->HOp()->HFp()->VN() > 3); assert(ep->EHp()->HFp() || ep->EHp()->HOp()->HFp()); assert(ep->EHp()->HVp() == vp || ep->EHp()->HOp()->HVp() == vp); HEdgePointer he = ep->EHp(); HEdgePointer hopp = he->HOp(); VertexPointer vp1; if( he->HVp() == vp ) vp1 = hopp->HVp(); else vp1 = he->HVp(); change_vertex( vp, vp1); //HP he->HNp()->HPp() = he->HPp(); hopp->HNp()->HPp() = hopp->HPp(); //HN he->HPp()->HNp() = he->HNp(); hopp->HPp()->HNp() = hopp->HNp(); //FH if( he->HFp() ) if( he->HFp()->FHp() == he ) he->HFp()->FHp() = he->HNp(); if( hopp->HFp() ) if( hopp->HFp()->FHp() == hopp ) hopp->HFp()->FHp() = hopp->HNp(); // VH if( vp1->VHp() == hopp ) vp1->VHp() = hopp->HNp(); Allocator::DeleteEdge(m,*ep); Allocator::DeleteHEdge(m,*he); Allocator::DeleteHEdge(m,*hopp); Allocator::DeleteVertex(m,*vp); return vp1; } /*! * Adds a face in a mesh, checking if the operation is possible. * * \param m Mesh * \param vps Vector of vertices (in ccw order) that will belong to the new face * * \return Pointer to the new face if it has been inserted, NULL otherwise */ static FacePointer add_face(MeshType &m, vector &vps) { assert(MeshType::VertexType::HasVHAdjacency()); assert(MeshType::EdgeType::HasEHAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency()); assert(MeshType::HEdgeType::HasHEAdjacency()); assert(MeshType::HEdgeType::HasHFAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHPrevAdjacency()); unsigned int size = vps.size(); assert(size >= 3); //there must be at least 3 vertices for(unsigned int i = 0; i< size; i++) { // all vertices must be different assert( count(vps.begin(), vps.end(), vps[i]) == 1 ); } vector hps; while(hps.size() < size) if( !can_add_hedge(vps, hps) ) return NULL; vector non_manifold_vertices(size, false); return add_face_unsafe( m,vps, hps, non_manifold_vertices ); } /*! * Removes a face in a mesh, checking if the operation is possible * * \param m Mesh * \param fp face to be removed * * \retval true if face has been removed * \retval false otherwise */ static bool remove_face(MeshType &m, FacePointer fp) { assert(MeshType::VertexType::HasVHAdjacency()); assert(MeshType::EdgeType::HasEHAdjacency()); assert(MeshType::FaceType::HasFHAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency()); assert(MeshType::HEdgeType::HasHEAdjacency()); assert(MeshType::HEdgeType::HasHFAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHPrevAdjacency()); if( can_remove_face(fp) ) { remove_face_unsafe(m, fp); return true; } return false; } protected: /*! * Adds a face in a mesh without any check * * \param m Mesh * \param vps Vector of vertices (in ccw order) that will belong to the new face * * \return Pointer to the new face */ static FacePointer add_face_unsafe(MeshType &m, vector &vps) { unsigned int size = vps.size(); vector hps; vector non_manifold_vertices; while(hps.size() < size) { if( can_add_hedge(vps, hps) ) non_manifold_vertices.push_back( false ); else non_manifold_vertices.push_back( hps.back() == NULL ); } return add_face_unsafe(m,vps,hps, non_manifold_vertices); } /*! * Adds a face in a mesh without any check * * \param m Mesh * \param vps Vector of vertices (in ccw order) that will belong to the new face * \param non_manifold_vertices Vector of booleans denoting on the i-th position if the i-th vertex is non-manifold * * \return Pointer to the new face */ static FacePointer add_face_unsafe(MeshType &m, vector &vps, vector &hps, vector &non_manifold_vertices) { assert(MeshType::VertexType::HasVHAdjacency()); assert(MeshType::EdgeType::HasEHAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency()); assert(MeshType::HEdgeType::HasHEAdjacency()); assert(MeshType::HEdgeType::HasHFAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHPrevAdjacency()); unsigned int size = vps.size(); assert(size >= 3); //there must be at least 3 vertices // for(unsigned int i = 0; i< size; i++) // { // // all vertices must be different // assert( count(vps.begin(), vps.end(), vps[i]) == 1 ); // } HEdgeIterator hi; assert(hps.size() == size); HEdgePointer nullPointer = NULL; int edge_n = count(hps.begin(), hps.end(), nullPointer); FaceIterator fi = Allocator::AddFaces(m,1); m.face.back().Alloc( size ); if(edge_n > 0) { (*fi).SetD(); EdgeIterator ei = Allocator::AddEdges(m,edge_n); for(EdgeIterator ei1 = ei; ei1 != m.edge.end(); ++ei1) (*ei1).SetD(); typename Allocator::template PointerUpdater pu; if(m.hedge.empty()) pu.oldBase = 0; else { pu.oldBase = &*(m.hedge.begin()); pu.oldEnd = &m.hedge.back()+1; } hi = Allocator::AddHEdges(m,2*edge_n); pu.newBase = &*(m.hedge.begin()); pu.newEnd = &m.hedge.back()+1; //undelete face (*fi).ClearD(); //undelete edges for(EdgeIterator ei1 = ei; ei1 != m.edge.end(); ++ei1) (*ei1).ClearD(); HEdgeIterator hi1 = hi; HEdgeIterator hi2 = hi; ++hi2; for(EdgeIterator ei1 = ei; ei1 != m.edge.end(); ++ei1, ++hi1, ++hi2) { // EH (*ei1).EHp() = &(*hi1); // HE (*hi1).HEp() = &(*ei1); (*hi2).HEp() = &(*ei1); //HO (*hi1).HOp() = &(*hi2); (*hi2).HOp() = &(*hi1); // HF (*hi1).HFp() = &(*fi); ++hi1; ++hi2; } // update hedge pointers (if needed) if( pu.NeedUpdate() ) for(typename vector::iterator hpsi = hps.begin(); hpsi != hps.end(); ++hpsi) { if((*hpsi)) pu.Update(*hpsi); } } vector hps1; for(unsigned int i = 0; i < size; i++) { if(hps[i] == NULL) { hps1.push_back(&(*hi)); ++hi; ++hi; } else hps1.push_back(hps[i]); } assert( hps1.size() == size ); for(unsigned int i = 0; i < size; i++) { int next = (i+1)%size; // hedge already exisitng if(hps[i]) { hps1[i]->HFp() = &(*fi); // next hedge was disconnected if(!hps[next]) { hps1[next]->HOp()->HNp() = hps1[i]->HNp(); hps1[i]->HNp()->HPp() = hps1[next]->HOp(); hps1[i]->HNp() = hps1[next]; hps1[next]->HPp() = hps1[i]; } } // hedge wasn't existing, vertex was disconnected else { //HV hps1[i]->HVp() = vps[i]; hps1[i]->HOp()->HVp() = vps[next]; hps1[i]->HNp() = hps1[next]; // next hedge was existing (vertex was disconnected) if(hps[next]) { hps1[i]->HOp()->HPp() = hps1[next]->HPp(); hps1[next]->HPp()->HNp() = hps1[i]->HOp(); } //vertex was detached else { // after face insertion vertex will become non-manifold if(non_manifold_vertices[next]) { Pos p(vps[next]->VHp(), true); while(p.F()) { p.FlipE(); p.FlipF(); if(p.HE() == vps[next]->VHp()) assert(0); //can't add a connection, there is no space } p.HE()->HPp()->HNp() = hps1[i]->HOp(); hps1[i]->HOp()->HPp() = p.HE()->HPp(); p.HE()->HPp() = hps1[next]->HOp(); hps1[next]->HOp()->HNp() = p.HE(); } else { hps1[i]->HOp()->HPp() = hps1[next]->HOp(); hps1[next]->HOp()->HNp() = hps1[i]->HOp(); } } hps1[next]->HPp() = hps1[i]; //VH if( !vps[i]->VHp()) vps[i]->VHp() = hps1[i]; } } //FH (*fi).FHp() = hps1.front(); return &(*fi); } /*! * Removes a face in a mesh, without any check * * \param m Mesh * \param fp Face to be removed * */ static void remove_face_unsafe (MeshType &m, FacePointer fp) { vector hps = getHEdges(fp); int size = hps.size(); for( int i = 0; i< size; i++ ) { if( hps[i]->HOp()->HFp() ) { hps[i]->HFp() = NULL; if( !hps[(i+size-1)%size]->HOp()->HFp() ) { // HP hps[i]->HPp() = hps[(i+size-1)%size]->HOp()->HPp(); hps[(i+size-1)%size]->HOp()->HPp()->HNp() = hps[i]; } if( !hps[(i+1)%size]->HOp()->HFp() ) { // HN hps[i]->HNp() = hps[(i+1)%size]->HOp()->HNp(); hps[(i+1)%size]->HOp()->HNp()->HPp() = hps[i]; } } else { Allocator::DeleteHEdge( m, *hps[i] ); Allocator::DeleteHEdge( m, *(hps[i]->HOp()) ); Allocator::DeleteEdge( m, *(hps[i]->HEp()) ); if( !hps[(i+size-1)%size]->HOp()->HFp() ) { hps[i]->HOp()->HNp()->HPp() = hps[(i+size-1)%size]->HOp()->HPp(); hps[(i+size-1)%size]->HOp()->HPp()->HNp() = hps[i]->HOp()->HNp(); } } } for( int i = 0; i< size; i++ ) { if( hps[i]->HVp()->VHp()->IsD() ) { if( !hps[i]->IsD() ) hps[i]->HVp()->VHp() = hps[i]; else if( !hps[(i+size-1)%size]->IsD() ) hps[i]->HVp()->VHp() = hps[(i+size-1)%size]->HOp(); else //search for a hedge (hedge can be found only if the vertex is non-manifold) { bool manifold = true; Pos p(hps[i]->HVp()->VHp(), true); p.HE()->SetV(); p.FlipE(); p.FlipF(); while( !p.HE()->IsV() ) { if( !p.HE()->IsD() ) { manifold = false; hps[i]->HVp()->VHp() = p.HE(); break; } p.FlipE(); p.FlipF(); } p.HE()->ClearV(); if(manifold) hps[i]->HVp()->VHp() = NULL; } } } Allocator::DeleteFace(m,*fp); } /*! * Checks if the next hedge can be inserted into hps. * If true, inserts the hedge into hps. If false, inserts NULL. * * \param vps Vector of vertices (in ccw order) that will belong to the new face * \param hps Vector of hedges already checked * * \retval true if hedge can be inserted * \retval false otherwise */ static bool can_add_hedge( vector &vps, vector &hps ) { unsigned int i = hps.size(); assert( i < vps.size() ); HEdgePointer he = vps[i]->VHp(); if(!he) //vertex is detached { hps.push_back(NULL); return true; } else { bool disconnected = false; bool hasEdge = false; unsigned int size = vps.size(); Pos p(he, false); he->SetV(); while(p.V() != vps[(i+1)%size]) { if(!hasEdge) hasEdge= ( find( vps.begin(), vps.end(), p.V()) != (vps.end() ) ); p.FlipV(); p.FlipE(); p.FlipF(); p.FlipV(); if(p.HE()->IsV()) { disconnected = true; break; } } he->ClearV(); if(disconnected) // edge does not exist { hps.push_back(NULL); // if hasEdge is false after inserting the face there will be a non-manifold vertex return hasEdge; } else //edge already existing { // try to insert consecutve hedges if they will belong to the new face while( (p.V() == vps[(i+1)%size]) && (i < size) ) { hps.push_back( p.HE() ); if(p.HE()->HFp() != NULL) return false; i++; p.FlipE(); p.FlipV(); } return true; } } } /*! * Checks if a face can be removed * * \param fp Face to check * * \retval true if the face can be removed * \retval false otherwise */ static bool can_remove_face(FacePointer fp) { Pos p(fp->FHp(), true); do { vector incident_faces = get_incident_faces( p.V() ); unsigned int size = incident_faces.size(); if(size > 2) { for(unsigned int i = 0; i < size; i++) { if(incident_faces[i] == NULL) if(incident_faces[(i+1)%size] != fp && incident_faces[((i+size)-1)%size] != fp ) return false; } } p.FlipV(); p.FlipE(); }while( p.HE() != fp->FHp() ); return true; } /*! * Gets all vertices incident to a face * * \param fp Face * \param starting_he A hedge in the face from which to start * * \return Vector containing the incident vertices */ static vector getVertices(FacePointer fp, HEdgePointer starting_he = NULL) { if(starting_he) assert( starting_he->HFp() == fp ); else starting_he = fp->FHp(); Pos p( starting_he, true ); vector ret; if( fp ) { do { ret.push_back( p.V() ); p.FlipV(); p.FlipE(); }while(p.HE() != starting_he); } return ret; } /*! * Gets all edges incident to a face * * \param fp Face * \param starting_he A hedge in the face from which to start * * \return Vector containing the incident edges */ static vector getHEdges(FacePointer fp, HEdgePointer starting_he = NULL) { if(starting_he) assert( starting_he->HFp() == fp ); else starting_he = fp->FHp(); Pos p( starting_he, true ); vector ret; if( fp ) { do { ret.push_back( p.HE() ); p.FlipV(); p.FlipE(); }while(p.HE() != starting_he); } return ret; } /*! * Gets all faces incident to a vertex * * \param fp Vertex * \param starting_he A hedge from which to start * * \return Vector containing the incident faces */ static vector get_incident_faces(VertexPointer vp, HEdgePointer starting_he = NULL) { assert(vp); if(starting_he) assert( starting_he->HVp() == vp ); else starting_he = vp->VHp(); Pos p( starting_he, true ); vector ret; do { ret.push_back( p.F() ); p.FlipE(); p.FlipF(); }while(p.HE() != starting_he); return ret; } /*! * Connects to a new vertex all hedges incident to a vertex * * \param old_vp the old vertex to be disconnected * \param new_vp the new vertex to be connected * */ static void change_vertex(VertexPointer old_vp, VertexPointer new_vp) { assert(old_vp); assert(new_vp); assert(old_vp != new_vp); Pos p(old_vp->VHp(),true); p.HE()->SetV(); do { p.HE()->HVp() = new_vp; p.FlipE(); p.FlipF(); }while( !p.HE()->IsV() ); p.HE()->ClearV(); if( !new_vp->VHp() ) new_vp->VHp() = old_vp->VHp(); } }; } } #endif // VCG_HEDGE_TOPOLOGY