/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; * the newly created loop will contain eDel->Dst. If the deletion of eDel * would create isolated vertices, those are deleted as well. * * This function could be implemented as two calls to __gl_meshSplice * plus a few calls to memFree, but this would allocate and delete * unnecessary vertices and faces. */ int __gl_meshDelete(GLUhalfEdge* eDel) { GLUhalfEdge* eDelSym=eDel->Sym; int joiningLoops=FALSE; /* First step: disconnect the origin vertex eDel->Org. We make all * changes to get a consistent mesh in this "intermediate" state. */ if (eDel->Lface!=eDel->Rface) { /* We are joining two loops into one -- remove the left face */ joiningLoops=TRUE; KillFace(eDel->Lface, eDel->Rface); } if (eDel->Onext==eDel) { KillVertex(eDel->Org, NULL); } else { /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ eDel->Rface->anEdge=eDel->Oprev; eDel->Org->anEdge=eDel->Onext; Splice(eDel, eDel->Oprev); if (!joiningLoops) { GLUface* newFace=allocFace(); if (newFace==NULL) { return 0; } /* We are splitting one loop into two -- create a new loop for eDel. */ MakeFace(newFace, eDel, eDel->Lface); } } /* Claim: the mesh is now in a consistent state, except that eDel->Org * may have been deleted. Now we disconnect eDel->Dst. */ if (eDelSym->Onext==eDelSym) { KillVertex(eDelSym->Org, NULL); KillFace(eDelSym->Lface, NULL); } else { /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ eDel->Lface->anEdge=eDelSym->Oprev; eDelSym->Org->anEdge=eDelSym->Onext; Splice(eDelSym, eDelSym->Oprev); } /* Any isolated vertices or faces have already been freed. */ KillEdge(eDel); return 1; }
/* tessMeshDelete (eDel) removes the edge eDel. There are several cases: * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; * the newly created loop will contain eDel->Dst. If the deletion of eDel * would create isolated vertices, those are deleted as well. * * This function could be implemented as two calls to tessMeshSplice * plus a few calls to memFree, but this would allocate and delete * unnecessary vertices and faces. */ int tessMeshDelete (TMesh *mesh, THalfEdge *eDel) { THalfEdge *eDelSym = eDel->Sym; int joiningLoops = false; /* First step: disconnect the origin vertex eDel->Org. We make all * changes to get a consistent mesh in this "intermediate" state. */ if (eDel->Lface != eDel->Rface) { /* We are joining two loops into one -- remove the left face */ joiningLoops = true; KillFace (mesh, eDel->Lface, eDel->Rface) ; } if (eDel->Onext == eDel) { KillVertex (mesh, eDel->pOrigin, NULL) ; } else { /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ eDel->Rface->pHalfEdge = eDel->Oprev; eDel->pOrigin->pHalfEdge = eDel->Onext; Splice (eDel, eDel->Oprev) ; if (! joiningLoops) { TFace *newFace= (TFace*)BucketAlloc (mesh->pFaceBucket) ; if (newFace == NULL) return 0; /* We are splitting one loop into two -- create a new loop for eDel. */ MakeFace (newFace, eDel, eDel->Lface) ; } } /* Claim: the mesh is now in a consistent state, except that eDel->Org * may have been deleted. Now we disconnect eDel->Dst. */ if (eDelSym->Onext == eDelSym) { KillVertex (mesh, eDelSym->pOrigin, NULL) ; KillFace (mesh, eDelSym->Lface, NULL) ; } else { /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ eDel->Lface->pHalfEdge = eDelSym->Oprev; eDelSym->pOrigin->pHalfEdge = eDelSym->Onext; Splice (eDelSym, eDelSym->Oprev) ; } /* Any isolated vertices or faces have already been freed. */ KillEdge (mesh, eDel) ; return 1; }
/* __gl_meshZapFace(fZap) destroys a face and removes it from the * global face list. All edges of fZap will have a NULL pointer as their * left face. Any edges which also have a NULL pointer as their right face * are deleted entirely (along with any isolated vertices this produces). * An entire mesh can be deleted by zapping its faces, one at a time, * in any order. Zapped faces cannot be used in further mesh operations! */ void __gl_meshZapFace(GLUface* fZap) { GLUhalfEdge* eStart=fZap->anEdge; GLUhalfEdge* e, *eNext, *eSym; GLUface* fPrev, *fNext; /* walk around face, deleting edges whose right face is also NULL */ eNext=eStart->Lnext; do { e=eNext; eNext=e->Lnext; e->Lface=NULL; if (e->Rface==NULL) { /* delete the edge -- see __gl_MeshDelete above */ if (e->Onext==e) { KillVertex(e->Org, NULL); } else { /* Make sure that e->Org points to a valid half-edge */ e->Org->anEdge=e->Onext; Splice(e, e->Oprev); } eSym=e->Sym; if (eSym->Onext==eSym) { KillVertex(eSym->Org, NULL); } else { /* Make sure that eSym->Org points to a valid half-edge */ eSym->Org->anEdge=eSym->Onext; Splice(eSym, eSym->Oprev); } KillEdge(e); } } while(e!=eStart); /* delete from circular doubly-linked list */ fPrev=fZap->prev; fNext=fZap->next; fNext->prev=fPrev; fPrev->next=fNext; memFree(fZap); }
/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the * mesh connectivity and topology. It changes the mesh so that * eOrg->Onext <- OLD(eDst->Onext) * eDst->Onext <- OLD(eOrg->Onext) * where OLD(...) means the value before the meshSplice operation. * * This can have two effects on the vertex structure: * - if eOrg->Org != eDst->Org, the two vertices are merged together * - if eOrg->Org == eDst->Org, the origin is split into two vertices * In both cases, eDst->Org is changed and eOrg->Org is untouched. * * Similarly (and independently) for the face structure, * - if eOrg->Lface == eDst->Lface, one loop is split into two * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. * * Some special cases: * If eDst == eOrg, the operation has no effect. * If eDst == eOrg->Lnext, the new face will have a single edge. * If eDst == eOrg->Lprev, the old face will have a single edge. * If eDst == eOrg->Onext, the new vertex will have a single edge. * If eDst == eOrg->Oprev, the old vertex will have a single edge. */ int __gl_meshSplice(GLUhalfEdge* eOrg, GLUhalfEdge* eDst) { int joiningLoops=FALSE; int joiningVertices=FALSE; if (eOrg==eDst) { return 1; } if (eDst->Org!=eOrg->Org) { /* We are merging two disjoint vertices -- destroy eDst->Org */ joiningVertices=TRUE; KillVertex(eDst->Org, eOrg->Org); } if (eDst->Lface!=eOrg->Lface) { /* We are connecting two disjoint loops -- destroy eDst->Lface */ joiningLoops=TRUE; KillFace(eDst->Lface, eOrg->Lface); } /* Change the edge structure */ Splice(eDst, eOrg); if (!joiningVertices) { GLUvertex* newVertex=allocVertex(); if (newVertex==NULL) { return 0; } /* We split one vertex into two -- the new vertex is eDst->Org. * Make sure the old vertex points to a valid half-edge. */ MakeVertex(newVertex, eDst, eOrg->Org); eOrg->Org->anEdge=eOrg; } if (!joiningLoops) { GLUface* newFace=allocFace(); if (newFace==NULL) { return 0; } /* We split one loop into two -- the new loop is eDst->Lface. * Make sure the old face points to a valid half-edge. */ MakeFace(newFace, eDst, eOrg->Lface); eOrg->Lface->anEdge=eOrg; } return 1; }
/* tessMeshZapFace (fZap) destroys a face and removes it from the * global face list. All edges of fZap will have a NULL pointer as their * left face. Any edges which also have a NULL pointer as their right face * are deleted entirely (along with any isolated vertices this produces). * An entire mesh can be deleted by zapping its faces, one at a time, * in any order. Zapped faces cannot be used in further mesh operations! */ void tessMeshZapFace (TMesh *mesh, TFace *fZap) { THalfEdge *eStart = fZap->pHalfEdge; THalfEdge *e, *eNext, *eSym; TFace *fPrev, *fNext; /* walk around face, deleting edges whose right face is also NULL */ eNext = eStart->Lnext; do { e = eNext; eNext = e->Lnext; e->Lface = NULL; if (e->Rface == NULL) { /* delete the edge -- see TESSmeshDelete above */ if (e->Onext == e) { KillVertex (mesh, e->pOrigin, NULL) ; } else { /* Make sure that e->Org points to a valid half-edge */ e->pOrigin->pHalfEdge = e->Onext; Splice (e, e->Oprev) ; } eSym = e->Sym; if (eSym->Onext == eSym) { KillVertex (mesh, eSym->pOrigin, NULL) ; } else { /* Make sure that eSym->Org points to a valid half-edge */ eSym->pOrigin->pHalfEdge = eSym->Onext; Splice (eSym, eSym->Oprev) ; } KillEdge (mesh, e) ; } } while (e != eStart) ; /* delete from circular doubly-linked list */ fPrev = fZap->pPrev; fNext = fZap->pNext; fNext->pPrev = fPrev; fPrev->pNext = fNext; BucketFree (mesh->pFaceBucket, fZap) ; }
/* tessMeshSplice (eOrg, eDst) is the basic operation for changing the * mesh connectivity and topology. It changes the mesh so that * eOrg->Onext <- OLD (eDst->Onext) * eDst->Onext <- OLD (eOrg->Onext) * where OLD(...) means the value before the meshSplice operation. * * This can have two effects on the vertex structure: * - if eOrg->Org != eDst->Org, the two vertices are merged together * - if eOrg->Org == eDst->Org, the origin is split into two vertices * In both cases, eDst->Org is changed and eOrg->Org is untouched. * * Similarly (and independently) for the face structure, * - if eOrg->Lface == eDst->Lface, one loop is split into two * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. * * Some special cases: * If eDst == eOrg, the operation has no effect. * If eDst == eOrg->Lnext, the new face will have a single edge. * If eDst == eOrg->Lprev, the old face will have a single edge. * If eDst == eOrg->Onext, the new vertex will have a single edge. * If eDst == eOrg->Oprev, the old vertex will have a single edge. */ int tessMeshSplice(TMesh* pMesh, THalfEdge *pEdgeOrg, THalfEdge *pEdgeDst) { int bJoiningLoops = false; int bJoiningVertices = false; if (pEdgeOrg == pEdgeDst) return 1; if (pEdgeDst->pOrigin != pEdgeOrg->pOrigin) { /* We are merging two disjoint vertices -- destroy eDst->Org */ bJoiningVertices = true; KillVertex(pMesh, pEdgeDst->pOrigin, pEdgeOrg->pOrigin); } if (pEdgeDst->Lface != pEdgeOrg->Lface) { /* We are connecting two disjoint loops -- destroy eDst->Lface */ bJoiningLoops = true; KillFace(pMesh, pEdgeDst->Lface, pEdgeOrg->Lface); } /* Change the edge structure */ Splice(pEdgeDst, pEdgeOrg); if (!bJoiningVertices) { TVertex *pNewVertex = (TVertex*)BucketAlloc(pMesh->pVertexBucket); if (pNewVertex == NULL) return 0; /* We split one vertex into two -- the new vertex is eDst->Org. * Make sure the old vertex points to a valid half-edge. */ MakeVertex(pNewVertex, pEdgeDst, pEdgeOrg->pOrigin); pEdgeOrg->pOrigin->pHalfEdge = pEdgeOrg; } if (!bJoiningLoops) { TFace *pNewFace = (TFace*)BucketAlloc(pMesh->pFaceBucket); if (pNewFace == NULL) return 0; /* We split one loop into two -- the new loop is eDst->Lface. * Make sure the old face points to a valid half-edge. */ MakeFace(pNewFace, pEdgeDst, pEdgeOrg->Lface); pEdgeOrg->Lface->pHalfEdge = pEdgeOrg; } return 1; }
/* tessMeshSplice( eOrg, eDst ) is the basic operation for changing the * mesh connectivity and topology. It changes the mesh so that * eOrg->Onext <- OLD( eDst->Onext ) * eDst->Onext <- OLD( eOrg->Onext ) * where OLD(...) means the value before the meshSplice operation. * * This can have two effects on the vertex structure: * - if eOrg->Org != eDst->Org, the two vertices are merged together * - if eOrg->Org == eDst->Org, the origin is split into two vertices * In both cases, eDst->Org is changed and eOrg->Org is untouched. * * Similarly (and independently) for the face structure, * - if eOrg->Lface == eDst->Lface, one loop is split into two * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. * * Some special cases: * If eDst == eOrg, the operation has no effect. * If eDst == eOrg->Lnext, the new face will have a single edge. * If eDst == eOrg->Lprev, the old face will have a single edge. * If eDst == eOrg->Onext, the new vertex will have a single edge. * If eDst == eOrg->Oprev, the old vertex will have a single edge. */ int tessMeshSplice( TESSmesh* mesh, TESShalfEdge *eOrg, TESShalfEdge *eDst ) { int joiningLoops = FALSE; int joiningVertices = FALSE; if( eOrg == eDst ) return 1; if( eDst->Org != eOrg->Org ) { /* We are merging two disjoint vertices -- destroy eDst->Org */ joiningVertices = TRUE; KillVertex( mesh, eDst->Org, eOrg->Org ); } if( eDst->Lface != eOrg->Lface ) { /* We are connecting two disjoint loops -- destroy eDst->Lface */ joiningLoops = TRUE; KillFace( mesh, eDst->Lface, eOrg->Lface ); } /* Change the edge structure */ Splice( eDst, eOrg ); if( ! joiningVertices ) { TESSvertex *newVertex = (TESSvertex*)bucketAlloc( mesh->vertexBucket ); if (newVertex == NULL) return 0; /* We split one vertex into two -- the new vertex is eDst->Org. * Make sure the old vertex points to a valid half-edge. */ MakeVertex( newVertex, eDst, eOrg->Org ); eOrg->Org->anEdge = eOrg; } if( ! joiningLoops ) { TESSface *newFace = (TESSface*)bucketAlloc( mesh->faceBucket ); if (newFace == NULL) return 0; /* We split one loop into two -- the new loop is eDst->Lface. * Make sure the old face points to a valid half-edge. */ MakeFace( newFace, eDst, eOrg->Lface ); eOrg->Lface->anEdge = eOrg; } return 1; }