/// <summary> /// 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. /// </summary> public void Delete(MeshUtils.Edge eDel) { var eDelSym = eDel._Sym; // First step: disconnect the origin vertex eDel->Org. We make all // changes to get a consistent mesh in this "intermediate" state. bool joiningLoops = false; if (eDel._Lface != eDel._Rface) { // We are joining two loops into one -- remove the left face joiningLoops = true; MeshUtils.KillFace(eDel._Lface, eDel._Rface); } if (eDel._Onext == eDel) { MeshUtils.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; MeshUtils.Splice(eDel, eDel._Oprev); if (!joiningLoops) { // We are splitting one loop into two -- create a new loop for eDel. MeshUtils.MakeFace(new MeshUtils.Face(), 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) { MeshUtils.KillVertex(eDelSym._Org, null); MeshUtils.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; MeshUtils.Splice(eDelSym, eDelSym._Oprev); } // Any isolated vertices or faces have already been freed. MeshUtils.KillEdge(eDel); }
/// <summary> /// 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! /// </summary> public void ZapFace(MeshUtils.Face fZap) { var eStart = fZap._anEdge; // walk around face, deleting edges whose right face is also NULL var eNext = eStart._Lnext; MeshUtils.Edge e, eSym; do { e = eNext; eNext = e._Lnext; e._Lface = null; if (e._Rface == null) { // delete the edge -- see TESSmeshDelete above if (e._Onext == e) { MeshUtils.KillVertex(e._Org, null); } else { // Make sure that e._Org points to a valid half-edge e._Org._anEdge = e._Onext; MeshUtils.Splice(e, e._Oprev); } eSym = e._Sym; if (eSym._Onext == eSym) { MeshUtils.KillVertex(eSym._Org, null); } else { // Make sure that eSym._Org points to a valid half-edge eSym._Org._anEdge = eSym._Onext; MeshUtils.Splice(eSym, eSym._Oprev); } MeshUtils.KillEdge(e); } } while (e != eStart); /* delete from circular doubly-linked list */ var fPrev = fZap._prev; var fNext = fZap._next; fNext._prev = fPrev; fPrev._next = fNext; }
/// <summary> /// Splice 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. /// </summary> public void Splice(MeshUtils.Edge eOrg, MeshUtils.Edge eDst) { if (eOrg == eDst) { return; } bool joiningVertices = false; if (eDst._Org != eOrg._Org) { // We are merging two disjoint vertices -- destroy eDst->Org joiningVertices = true; MeshUtils.KillVertex(eDst._Org, eOrg._Org); } bool joiningLoops = false; if (eDst._Lface != eOrg._Lface) { // We are connecting two disjoint loops -- destroy eDst->Lface joiningLoops = true; MeshUtils.KillFace(eDst._Lface, eOrg._Lface); } // Change the edge structure MeshUtils.Splice(eDst, eOrg); if (!joiningVertices) { // We split one vertex into two -- the new vertex is eDst->Org. // Make sure the old vertex points to a valid half-edge. MeshUtils.MakeVertex(new MeshUtils.Vertex(), eDst, eOrg._Org); eOrg._Org._anEdge = eOrg; } if (!joiningLoops) { // We split one loop into two -- the new loop is eDst->Lface. // Make sure the old face points to a valid half-edge. MeshUtils.MakeFace(new MeshUtils.Face(), eDst, eOrg._Lface); eOrg._Lface._anEdge = eOrg; } }