/// <summary> /// Creates a new edge from eOrg->Dst to eDst->Org, and returns the corresponding half-edge eNew. /// If eOrg->Lface == eDst->Lface, this splits one loop into two, /// and the newly created loop is eNew->Lface. Otherwise, two disjoint /// loops are merged into one, and the loop eDst->Lface is destroyed. /// /// If (eOrg == eDst), the new face will have only two edges. /// If (eOrg->Lnext == eDst), the old face is reduced to a single edge. /// If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. /// </summary> public MeshUtils.Edge Connect(MeshUtils.Edge eOrg, MeshUtils.Edge eDst) { var eNew = MeshUtils.MakeEdge(eOrg); var eNewSym = eNew._Sym; 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); } // Connect the new edge appropriately MeshUtils.Splice(eNew, eOrg._Lnext); MeshUtils.Splice(eNewSym, eDst); // Set the vertex and face information eNew._Org = eOrg._Dst; eNewSym._Org = eDst._Org; eNew._Lface = eNewSym._Lface = eOrg._Lface; // Make sure the old face points to a valid half-edge eOrg._Lface._anEdge = eNewSym; if (!joiningLoops) { MeshUtils.MakeFace(new MeshUtils.Face(), eNew, eOrg._Lface); } return(eNew); }
/// <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> /// 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; } }