diff --git a/vcg/complex/trimesh/update/halfedge_topology.h b/vcg/complex/trimesh/update/halfedge_topology.h new file mode 100644 index 00000000..8eb1913d --- /dev/null +++ b/vcg/complex/trimesh/update/halfedge_topology.h @@ -0,0 +1,1309 @@ +#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 +