private void DrawFaceEdge(FaceEdge faceEdge, Vector2 faceAverageCenter) { Vector2 start = MoveTowardsCenter(GetImagePosition(faceEdge.FirstVertex.Position), faceAverageCenter); Vector2 end = MoveTowardsCenter(GetImagePosition(faceEdge.NextFaceEdge.FirstVertex.Position), faceAverageCenter); DrawEdgeLine(start, end, faceEdge.ID.ToString(), faceEdgeColor); graphics.Circle(start, 3, Color.Black); WriteStringAtPos("{0}".FormatWith(faceEdge.MeshEdge.ID), (start + end) / 2 + new Vector2(0, -12), meshEdgeColor); WriteStringAtPos("{0}".FormatWith(faceEdge.ContainingFace.ID), (start + end) / 2 + new Vector2(0, 12), faceColor); Vector2 delta = end - start; Vector2 normal = delta.GetNormal(); double length = delta.Length; Vector2 left = normal.GetPerpendicularLeft(); // draw the starting vertex info WriteStringAtPos("{0}".FormatWith(faceEdge.FirstVertex.ID), start + normal * length * .10, vertexColor); // draw the next and prev faceEdge info WriteStringAtPos("{0}".FormatWith(faceEdge.NextFaceEdge.ID), start + normal * length * .60, faceEdgeColor); WriteStringAtPos("{0}".FormatWith(faceEdge.PrevFaceEdge.ID), start + normal * length * .40, faceEdgeColor); // draw the radialFaceEdge info WriteStringAtPos("{0}".FormatWith(faceEdge.RadialNextFaceEdge.ID), start + new Vector2(0, 7) + normal * length * .90, faceEdgeColor); WriteStringAtPos("{0}".FormatWith(faceEdge.radialPrevFaceEdge.ID), start + new Vector2(0, -7) + normal * length * .90, faceEdgeColor); }
private static void CreateFaceEdges(Vertex[] verticesToUse, List <MeshEdge> edgesToUse, Face createdFace) { FaceEdge prevFaceEdge = null; for (int i = 0; i < verticesToUse.Length - 1; i++) { MeshEdge currentMeshEdge = edgesToUse[i]; FaceEdge currentFaceEdge = new FaceEdge(createdFace, currentMeshEdge, verticesToUse[i]); if (i == 0) { createdFace.firstFaceEdge = currentFaceEdge; } else { prevFaceEdge.nextFaceEdge = currentFaceEdge; currentFaceEdge.prevFaceEdge = prevFaceEdge; } currentFaceEdge.AddToRadialLoop(currentMeshEdge); prevFaceEdge = currentFaceEdge; } // make the last FaceEdge { MeshEdge currentMeshEdge = edgesToUse[verticesToUse.Length - 1]; FaceEdge currentFaceEdge = new FaceEdge(createdFace, currentMeshEdge, verticesToUse[verticesToUse.Length - 1]); prevFaceEdge.nextFaceEdge = currentFaceEdge; currentFaceEdge.prevFaceEdge = prevFaceEdge; currentFaceEdge.nextFaceEdge = createdFace.firstFaceEdge; createdFace.firstFaceEdge.prevFaceEdge = currentFaceEdge; currentFaceEdge.AddToRadialLoop(currentMeshEdge); } }
public void UnsplitFace(Face faceToKeep, Face faceToDelete, MeshEdge meshEdgeToDelete) { if (faceToKeep == faceToDelete) { throw new Exception("Can't join face to itself"); } // validate the edgeToDelete is in both faces, edgeToDelete is only in these two faces, the two faces only share this one edge and no other edges FaceEdge faceEdgeToDeleteOnFaceToKeep = meshEdgeToDelete.GetFaceEdge(faceToKeep); FaceEdge faceEdgeToDeleteOnFaceToDelete = meshEdgeToDelete.GetFaceEdge(faceToDelete); if (faceEdgeToDeleteOnFaceToKeep.firstVertex == faceEdgeToDeleteOnFaceToDelete.firstVertex) { throw new Exception("The faces have oposite windings and you cannot merge the edge"); } faceEdgeToDeleteOnFaceToKeep.prevFaceEdge.nextFaceEdge = faceEdgeToDeleteOnFaceToDelete.nextFaceEdge; faceEdgeToDeleteOnFaceToDelete.nextFaceEdge.prevFaceEdge = faceEdgeToDeleteOnFaceToKeep.prevFaceEdge; faceEdgeToDeleteOnFaceToKeep.nextFaceEdge.prevFaceEdge = faceEdgeToDeleteOnFaceToDelete.prevFaceEdge; faceEdgeToDeleteOnFaceToDelete.prevFaceEdge.nextFaceEdge = faceEdgeToDeleteOnFaceToKeep.nextFaceEdge; // if the face we are deleting is the one that the face to keep was looking at as its starting face edge, move it to the next face edge if (faceToKeep.firstFaceEdge == faceEdgeToDeleteOnFaceToKeep) { faceToKeep.firstFaceEdge = faceToKeep.firstFaceEdge.nextFaceEdge; } // make sure the FaceEdges all point to the kept face. foreach (FaceEdge faceEdge in faceToKeep.firstFaceEdge.NextFaceEdges()) { faceEdge.containingFace = faceToKeep; } // make sure we take the mesh edge out of the neighbors pointers meshEdgeToDelete.RemoveFromMeshEdgeLinksOfVertex(meshEdgeToDelete.VertexOnEnd[0]); meshEdgeToDelete.RemoveFromMeshEdgeLinksOfVertex(meshEdgeToDelete.VertexOnEnd[1]); // clear the data on the deleted face edge to help with debugging faceEdgeToDeleteOnFaceToKeep.meshEdge.VertexOnEnd[0] = null; faceEdgeToDeleteOnFaceToKeep.meshEdge.VertexOnEnd[1] = null; faceToDelete.firstFaceEdge = null; // take the face out of the face list faces.Remove(faceToDelete); // clear the data on the deleted mesh edge to help with debugging meshEdgeToDelete.firstFaceEdge = null; meshEdgeToDelete.VertexOnEnd[0] = null; meshEdgeToDelete.NextMeshEdgeFromEnd[0] = null; meshEdgeToDelete.VertexOnEnd[1] = null; meshEdgeToDelete.NextMeshEdgeFromEnd[1] = null; MeshEdges.Remove(meshEdgeToDelete); }
public FaceEdge(Face face, MeshEdge meshEdge, Vertex vertex) { this.containingFace = face; this.meshEdge = meshEdge; this.firstVertex = vertex; nextFaceEdge = null; prevFaceEdge = null; radialNextFaceEdge = radialPrevFaceEdge = this; }
public IEnumerable <FaceEdge> NextFaceEdges() { FaceEdge curFaceEdge = this; do { yield return(curFaceEdge); curFaceEdge = curFaceEdge.NextFaceEdge; } while (curFaceEdge != this); }
public IEnumerable <FaceEdge> RadialPrevFaceEdges() { FaceEdge curFaceEdge = this; do { yield return(curFaceEdge); curFaceEdge = curFaceEdge.radialPrevFaceEdge; } while (curFaceEdge != this); }
public FaceEdge(Face face, MeshEdge meshEdge, IVertex vertex) { this.ContainingFace = face; this.MeshEdge = meshEdge; this.FirstVertex = vertex; NextFaceEdge = null; PrevFaceEdge = null; RadialNextFaceEdge = radialPrevFaceEdge = this; }
public void SplitMeshEdge(MeshEdge meshEdgeToSplit, out Vertex vertexCreatedDuringSplit, out MeshEdge meshEdgeCreatedDuringSplit) { // create our new Vertex and MeshEdge { // make a new vertex between the existing ones // TODO: make this create an interpolated vertex, check if it exits and add it or use the right one. //vertexCreatedDuringSplit = meshEdgeToSplit.edgeEndVertex[0].CreateInterpolated(meshEdgeToSplit.edgeEndVertex[1], .5); vertexCreatedDuringSplit = CreateVertex((meshEdgeToSplit.VertexOnEnd[0].Position + meshEdgeToSplit.VertexOnEnd[1].Position) / 2); // TODO: check if the mesh edge exits and use the existing one (or not) meshEdgeCreatedDuringSplit = new MeshEdge(); } // Set the new firstMeshEdge on the new Vertex vertexCreatedDuringSplit.firstMeshEdge = meshEdgeCreatedDuringSplit; Vertex existingVertexToConectTo = meshEdgeToSplit.VertexOnEnd[1]; // fix the Vertex references on the MeshEdges { // and set the edges to point to this new one meshEdgeCreatedDuringSplit.VertexOnEnd[0] = vertexCreatedDuringSplit; meshEdgeCreatedDuringSplit.VertexOnEnd[1] = existingVertexToConectTo; meshEdgeToSplit.VertexOnEnd[1] = vertexCreatedDuringSplit; } // fix the MeshEdgeLinks on the MeshEdges { // set the created edge to be connected to the old edges other mesh edges meshEdgeCreatedDuringSplit.NextMeshEdgeFromEnd[0] = meshEdgeToSplit; // make anything that pointed to the split edge point to the new mesh edge meshEdgeToSplit.NextMeshEdgeFromEnd[1] = meshEdgeCreatedDuringSplit; } // if the MeshEdge is part of a face than we have to fix the face up FaceEdge faceEdgeToSplit = meshEdgeToSplit.firstFaceEdge; if (faceEdgeToSplit != null) { foreach (FaceEdge faceEdge in meshEdgeToSplit.FaceEdgesSharingMeshEdge()) { Face currentFace = faceEdge.containingFace; FaceEdge newFaceEdge = new FaceEdge(currentFace, meshEdgeCreatedDuringSplit, vertexCreatedDuringSplit); newFaceEdge.AddToRadialLoop(meshEdgeCreatedDuringSplit); // and inject it into the face loop for this face newFaceEdge.prevFaceEdge = faceEdge; newFaceEdge.nextFaceEdge = faceEdge.nextFaceEdge; faceEdge.nextFaceEdge.prevFaceEdge = newFaceEdge; faceEdge.nextFaceEdge = newFaceEdge; } } }
public IEnumerable <FaceEdge> FaceEdgesSharingMeshEdge() { FaceEdge curFaceEdge = this.firstFaceEdge; if (curFaceEdge != null) { do { yield return(curFaceEdge); curFaceEdge = curFaceEdge.RadialNextFaceEdge; } while (curFaceEdge != this.firstFaceEdge); } }
static public FaceEdgeTextureUvData Get(FaceEdge faceEdgeToGetTextureUvDataFor) { FaceEdgeTextureUvData plugin; faceEdgesWithTextureUvData.TryGetValue(faceEdgeToGetTextureUvDataFor, out plugin); if (plugin == null) { FaceEdgeTextureUvData newPlugin = new FaceEdgeTextureUvData(); faceEdgesWithTextureUvData.Add(faceEdgeToGetTextureUvDataFor, newPlugin); return(newPlugin); } return(plugin); }
public void CalculateNormal() { FaceEdge faceEdge0 = firstFaceEdge; FaceEdge faceEdge1 = faceEdge0.NextFaceEdge; Vector3 faceEdge1Minus0 = faceEdge1.FirstVertex.Position - faceEdge0.FirstVertex.Position; FaceEdge faceEdge2 = faceEdge1; bool collinear = false; do { faceEdge2 = faceEdge2.NextFaceEdge; collinear = Vector3.Collinear(faceEdge0.FirstVertex.Position, faceEdge1.FirstVertex.Position, faceEdge2.FirstVertex.Position); } while (collinear && faceEdge2 != faceEdge0); Vector3 face2Minus0 = faceEdge2.FirstVertex.Position - faceEdge0.FirstVertex.Position; Normal = Vector3.Cross(faceEdge1Minus0, face2Minus0).GetNormal(); }
public void ReverseFaceEdges(Face faceToReverse) { FaceEdge temp = null; FaceEdge current = faceToReverse.firstFaceEdge; // swap next and prev for all nodes of // doubly linked list do { temp = current.prevFaceEdge; current.prevFaceEdge = current.nextFaceEdge; current.nextFaceEdge = temp; current = current.prevFaceEdge; // go to the next } while (current != faceToReverse.firstFaceEdge); faceToReverse.CalculateNormal(); }
static public FaceEdgeTextureUvData Get(FaceEdge faceEdgeToGetTextureUvDataFor) { FaceEdgeTextureUvData plugin = null; lock(faceEdgesWithTextureUvData) { faceEdgesWithTextureUvData.TryGetValue(faceEdgeToGetTextureUvDataFor, out plugin); if (plugin == null) { FaceEdgeTextureUvData newPlugin = new FaceEdgeTextureUvData(); faceEdgesWithTextureUvData.Add(faceEdgeToGetTextureUvDataFor, newPlugin); return newPlugin; } } return plugin; }
public void AddToRadialLoop(MeshEdge currentMeshEdge) { if (currentMeshEdge.firstFaceEdge == null) { // This is the first face edge of this mesh edge. Add it. currentMeshEdge.firstFaceEdge = this; } else { // There was a face on this mesh edge so add this one in. // First set the new face edge radias pointers this.radialPrevFaceEdge = currentMeshEdge.firstFaceEdge; this.radialNextFaceEdge = currentMeshEdge.firstFaceEdge.radialNextFaceEdge; // then fix the insertion point to point to this new face edge. this.radialPrevFaceEdge.radialNextFaceEdge = this; this.radialNextFaceEdge.radialPrevFaceEdge = this; } }
static public FaceEdgeTextureUvData Get(FaceEdge faceEdgeToGetTextureUvDataFor) { FaceEdgeTextureUvData plugin = null; using (TimedLock.Lock(faceEdgesWithTextureUvData, "Get FaceEdgeTextureUvData")) { faceEdgesWithTextureUvData.TryGetValue(faceEdgeToGetTextureUvDataFor, out plugin); if (plugin == null) { FaceEdgeTextureUvData newPlugin = new FaceEdgeTextureUvData(); faceEdgesWithTextureUvData.Add(faceEdgeToGetTextureUvDataFor, newPlugin); return(newPlugin); } } return(plugin); }
private void DrawFaceEdge(FaceEdge faceEdge, Vector2 faceAverageCenter) { Vector2 start = MoveTowardsCenter(GetImagePosition(faceEdge.firstVertex.Position), faceAverageCenter); Vector2 end = MoveTowardsCenter(GetImagePosition(faceEdge.nextFaceEdge.firstVertex.Position), faceAverageCenter); DrawEdgeLine(start, end, faceEdge.Data.ID.ToString(), faceEdgeColor); graphics.Circle(start, 3, RGBA_Bytes.Black); WriteStringAtPos("{0}".FormatWith(faceEdge.meshEdge.Data.ID), (start + end) / 2 + new Vector2(0, -12), meshEdgeColor); WriteStringAtPos("{0}".FormatWith(faceEdge.containingFace.Data.ID), (start + end) / 2 + new Vector2(0, 12), faceColor); Vector2 delta = end - start; Vector2 normal = delta.GetNormal(); double length = delta.Length; Vector2 left = normal.GetPerpendicularLeft(); // draw the starting vertex info WriteStringAtPos("{0}".FormatWith(faceEdge.firstVertex.Data.ID), start + normal * length * .10, vertexColor); // draw the next and prev faceEdge info WriteStringAtPos("{0}".FormatWith(faceEdge.nextFaceEdge.Data.ID), start + normal * length * .60, faceEdgeColor); WriteStringAtPos("{0}".FormatWith(faceEdge.prevFaceEdge.Data.ID), start + normal * length * .40, faceEdgeColor); // draw the radialFaceEdge info WriteStringAtPos("{0}".FormatWith(faceEdge.radialNextFaceEdge.Data.ID), start + new Vector2(0, 7) + normal * length * .90, faceEdgeColor); WriteStringAtPos("{0}".FormatWith(faceEdge.radialPrevFaceEdge.Data.ID), start + new Vector2(0, -7) + normal * length * .90, faceEdgeColor); }
public bool GetCutLine(Plane cutPlane, ref Vector3 start, ref Vector3 end) { int splitCount = 0; FaceEdge prevEdge = null; bool prevInFront = false; bool first = true; FaceEdge firstEdge = null; bool firstInFront = false; foreach (FaceEdge faceEdge in FaceEdges()) { if (first) { prevEdge = faceEdge; prevInFront = cutPlane.GetDistanceFromPlane(prevEdge.FirstVertex.Position) > 0; first = false; firstEdge = prevEdge; firstInFront = prevInFront; } else { FaceEdge curEdge = faceEdge; bool curInFront = cutPlane.GetDistanceFromPlane(curEdge.FirstVertex.Position) > 0; if (prevInFront != curInFront) { // we crossed over the cut line Vector3 directionNormal = (curEdge.FirstVertex.Position - prevEdge.FirstVertex.Position).GetNormal(); Ray edgeRay = new Ray(prevEdge.FirstVertex.Position, directionNormal); double distanceToHit; bool hitFrontOfPlane; if (cutPlane.RayHitPlane(edgeRay, out distanceToHit, out hitFrontOfPlane)) { splitCount++; if (splitCount == 1) { start = edgeRay.origin + edgeRay.directionNormal * distanceToHit; } else { end = edgeRay.origin + edgeRay.directionNormal * distanceToHit; } } } prevEdge = curEdge; prevInFront = curInFront; if (splitCount == 2) { break; } } } if (splitCount == 1 && prevInFront != firstInFront) { // we crossed over the cut line Vector3 directionNormal = (firstEdge.FirstVertex.Position - prevEdge.FirstVertex.Position).GetNormal(); Ray edgeRay = new Ray(prevEdge.FirstVertex.Position, directionNormal); double distanceToHit; bool hitFrontOfPlane; if (cutPlane.RayHitPlane(edgeRay, out distanceToHit, out hitFrontOfPlane)) { splitCount++; end = edgeRay.origin + edgeRay.directionNormal * distanceToHit; } } if (splitCount == 2) { return(true); } return(false); }
public void SplitFace(Face faceToSplit, Vertex splitStartVertex, Vertex splitEndVertex, out MeshEdge meshEdgeCreatedDuringSplit, out Face faceCreatedDuringSplit) { if (!ContainsVertex(splitStartVertex) || !ContainsVertex(splitEndVertex)) { throw new Exception("The mesh must contain the vertices you intend to split between."); } // we may want to be able to double up an edge for some operations (we'll have to see). if (FindMeshEdges(splitStartVertex, splitEndVertex).Count > 0) { // this also ensures that the face is more than 2 sided. throw new Exception("You cannot split a face on an existing edge."); } FaceEdge faceEdgeAfterSplitStart = null; FaceEdge faceEdgeAfterSplitEnd = null; int count = 0; foreach (FaceEdge faceEdge in faceToSplit.FaceEdges()) { if (faceEdge.firstVertex == splitStartVertex) { faceEdgeAfterSplitStart = faceEdge; count++; } else if (faceEdge.firstVertex == splitEndVertex) { faceEdgeAfterSplitEnd = faceEdge; count++; } if (count == 2) { break; // stop if we found both face edges } } meshEdgeCreatedDuringSplit = CreateMeshEdge(splitStartVertex, splitEndVertex); faceCreatedDuringSplit = new Face(faceToSplit); faces.Add(faceCreatedDuringSplit); FaceEdge newFaceEdgeExistingFace = new FaceEdge(faceToSplit, meshEdgeCreatedDuringSplit, splitStartVertex); FaceEdge newFaceEdgeForNewFace = new FaceEdge(faceCreatedDuringSplit, meshEdgeCreatedDuringSplit, splitEndVertex); // get the new edges injected into the existing loop, spliting it in two. newFaceEdgeExistingFace.prevFaceEdge = faceEdgeAfterSplitStart.prevFaceEdge; newFaceEdgeForNewFace.prevFaceEdge = faceEdgeAfterSplitEnd.prevFaceEdge; faceEdgeAfterSplitStart.prevFaceEdge.nextFaceEdge = newFaceEdgeExistingFace; faceEdgeAfterSplitEnd.prevFaceEdge.nextFaceEdge = newFaceEdgeForNewFace; newFaceEdgeExistingFace.nextFaceEdge = faceEdgeAfterSplitEnd; newFaceEdgeForNewFace.nextFaceEdge = faceEdgeAfterSplitStart; faceEdgeAfterSplitStart.prevFaceEdge = newFaceEdgeForNewFace; faceEdgeAfterSplitEnd.prevFaceEdge = newFaceEdgeExistingFace; // make sure the first face edge of each face is valid faceToSplit.firstFaceEdge = newFaceEdgeExistingFace; faceCreatedDuringSplit.firstFaceEdge = newFaceEdgeForNewFace; // make sure the FaceEdges of the new face all point to the new face. foreach (FaceEdge faceEdge in faceCreatedDuringSplit.firstFaceEdge.NextFaceEdges()) { faceEdge.containingFace = faceCreatedDuringSplit; } newFaceEdgeExistingFace.AddToRadialLoop(meshEdgeCreatedDuringSplit); newFaceEdgeForNewFace.AddToRadialLoop(meshEdgeCreatedDuringSplit); }
private static void DeleteFaceEdge(FaceEdge faceEdgeToDelete) { }
private static void CreateFaceEdges(Vertex[] verticesToUse, List<MeshEdge> edgesToUse, Face createdFace) { FaceEdge prevFaceEdge = null; for (int i = 0; i < verticesToUse.Length - 1; i++) { MeshEdge currentMeshEdge = edgesToUse[i]; FaceEdge currentFaceEdge = new FaceEdge(createdFace, currentMeshEdge, verticesToUse[i]); if (i == 0) { createdFace.firstFaceEdge = currentFaceEdge; } else { prevFaceEdge.nextFaceEdge = currentFaceEdge; currentFaceEdge.prevFaceEdge = prevFaceEdge; } currentFaceEdge.AddToRadialLoop(currentMeshEdge); prevFaceEdge = currentFaceEdge; } // make the last FaceEdge { MeshEdge currentMeshEdge = edgesToUse[verticesToUse.Length - 1]; FaceEdge currentFaceEdge = new FaceEdge(createdFace, currentMeshEdge, verticesToUse[verticesToUse.Length - 1]); prevFaceEdge.nextFaceEdge = currentFaceEdge; currentFaceEdge.prevFaceEdge = prevFaceEdge; currentFaceEdge.nextFaceEdge = createdFace.firstFaceEdge; createdFace.firstFaceEdge.prevFaceEdge = currentFaceEdge; currentFaceEdge.AddToRadialLoop(currentMeshEdge); } }
/// <summary> /// Unsplit (merge) the edgeToJoin and the edge that it is connected to through vertexToDelete. /// Only unsplit the edge if we are reversing what would have been a split (a single vertex connecting only two edges). /// </summary> /// <param name="edgeToJoin"></param> /// <param name="vertexToDelete"></param> /// <returns></returns> public void UnsplitMeshEdge(MeshEdge edgeToJoin, Vertex vertexToDelete) { int endToJoinIndex = edgeToJoin.GetVertexEndIndex(vertexToDelete); MeshEdge edgeToDelete = edgeToJoin.GetNextMeshEdgeConnectedTo(vertexToDelete); if (edgeToDelete.GetNextMeshEdgeConnectedTo(vertexToDelete) != edgeToJoin) { // make sure the edgeToJoin is a valid unsplit (only one connection) throw new Exception("The edge that is being unsplit must be connected to only one other MeshEdge across the vertexToDelete."); } int otherEndOfEdgeToDelete = edgeToDelete.GetOpositeVertexEndIndex(vertexToDelete); MeshEdge edgeToJoinTo = edgeToDelete.NextMeshEdgeFromEnd[otherEndOfEdgeToDelete]; // if the MeshEdge is part of any faces than we have to fix the faces. if (edgeToJoin.firstFaceEdge != null) { // The edge we split was part of one or more faces, we need to fix the FaceEdge loops foreach (FaceEdge faceEdge in edgeToJoin.FaceEdgesSharingMeshEdge()) { FaceEdge faceEdgeToDelete = null; if (faceEdge.nextFaceEdge.meshEdge == edgeToDelete) { faceEdgeToDelete = faceEdge.nextFaceEdge; FaceEdge newNextFaceEdge = faceEdgeToDelete.nextFaceEdge; newNextFaceEdge.prevFaceEdge = faceEdge; faceEdge.nextFaceEdge = newNextFaceEdge; } else if (faceEdge.prevFaceEdge.meshEdge == edgeToDelete) { faceEdgeToDelete = faceEdge.prevFaceEdge; FaceEdge newPrevFaceEdge = faceEdgeToDelete.prevFaceEdge; newPrevFaceEdge.nextFaceEdge = faceEdge; faceEdge.prevFaceEdge = newPrevFaceEdge; } else { throw new Exception("Either the next or prev edge must be the same as the edge to delete."); } // if the FaceEdge we are deleting is the one that the face was using as its firstFaceEdge, change it. if (faceEdge.containingFace.firstFaceEdge == faceEdgeToDelete) { faceEdge.containingFace.firstFaceEdge = faceEdge; } // and clear out the FaceEdge we are deleting to help debugging and other references to it. faceEdgeToDelete.nextFaceEdge = null; faceEdgeToDelete.prevFaceEdge = null; faceEdgeToDelete.radialNextFaceEdge = null; faceEdgeToDelete.radialPrevFaceEdge = null; faceEdgeToDelete.meshEdge = null; faceEdgeToDelete.containingFace = null; faceEdgeToDelete.firstVertex = null; } } // fix the MeshEdgeLinks on the edgeToJoin { edgeToJoin.VertexOnEnd[endToJoinIndex] = edgeToDelete.VertexOnEnd[otherEndOfEdgeToDelete]; edgeToJoin.NextMeshEdgeFromEnd[endToJoinIndex] = edgeToDelete.NextMeshEdgeFromEnd[otherEndOfEdgeToDelete]; } // Clear all the data on the deleted vertex and edge so we have less code that will work if it continues to use them. vertexToDelete.firstMeshEdge = null; edgeToDelete.firstFaceEdge = null; edgeToDelete.VertexOnEnd[0] = null; edgeToDelete.NextMeshEdgeFromEnd[0] = null; edgeToDelete.VertexOnEnd[1] = null; edgeToDelete.NextMeshEdgeFromEnd[1] = null; }