// Pivot an edge clockwise around its implicit near vertex. // // \ / \ / // o-------o o-------o // | | | | // 2 N | 2 N | // | | | | // B V --> B<--E---V // / \ / \ / \ \ // 1 E \ 1 \ // \ v \ / \ \ / // A o A o // | P | | P | // 0 | 0 | // | | | | // o-------o o-------o // / \ / \ // // E: edge passed in as parameter // V: vertex to pivot E around clockwise // A: old vertex that E is originally pointing at // B: new vertex that E will now point at // P: previous face on the counter-clockwise side of E // N: next face on the clockwise side of E // 0: outer edge 0 points at A, inner edge 0 points away from A // 1: outer edge 1 points at B, inner edge 1 points at A, at N before pivot, at P after pivot // 2: outer edge 2 points away from B // Note: inner edges point downward, outer edges point upward private void PivotVertexEdgeForwardUnchecked(int edgeIndex, int twinEdgeIndex, int outerEdgeIndex1, int innerEdgeIndex1) { var innerEdgeIndex0 = edgeData[twinEdgeIndex].vNext; var outerEdgeIndex0 = edgeData[innerEdgeIndex0].twin; var outerEdgeIndex2 = edgeData[outerEdgeIndex1].fNext; var prevFaceIndex = edgeData[edgeIndex].face; var nextFaceIndex = edgeData[twinEdgeIndex].face; var oldVertexIndex = edgeData[edgeIndex].vertex; var newVertexIndex = edgeData[outerEdgeIndex1].vertex; // The edge was pointing at the old vertex, will now point at the new vertex. edgeData[edgeIndex].vertex = newVertexIndex; // The second inner edge was pointing at the next face, will now point at the previous face. edgeData[innerEdgeIndex1].face = prevFaceIndex; // Remove twin edge from old vertex linked list by skipping over it. edgeData[outerEdgeIndex1].vNext = innerEdgeIndex0; // Insert twin edge into new vertex linked list. edgeData[outerEdgeIndex2].vNext = twinEdgeIndex; edgeData[twinEdgeIndex].vNext = innerEdgeIndex1; // Remove second outer edge from next face linked list by skipping over it. edgeData[edgeIndex].fNext = outerEdgeIndex2; // Insert second outer edge into the previous face linked list. edgeData[outerEdgeIndex0].fNext = outerEdgeIndex1; edgeData[outerEdgeIndex1].fNext = twinEdgeIndex; // Reroot the vertex and face that just lost edges with edges guaranteed to still belong. vertexFirstEdgeIndices[oldVertexIndex] = outerEdgeIndex1; faceFirstEdgeIndices[nextFaceIndex] = edgeIndex; // Adjust neighbor counts. vertexNeighborCounts[oldVertexIndex] -= 1; vertexNeighborCounts[newVertexIndex] += 1; faceNeighborCounts[nextFaceIndex] -= 1; // Dropping below 0 is undefined behavior; it better not ever happen. faceNeighborCounts[prevFaceIndex] += 1; // Surpassing 32767 is undefined behavior; it better not ever happen. // Adjust edge wrap information, coallescing multiple edges together as appropriate. edgeData[edgeIndex].wrap = EdgeWrapUtility.ModifyTargetVertEdgeRelations(edgeData[edgeIndex].wrap, edgeData[outerEdgeIndex1].wrap); // Edge's target vertex changed, according to Inner Edge 1. edgeData[twinEdgeIndex].wrap = EdgeWrapUtility.ModifySourceVertEdgeRelations(edgeData[twinEdgeIndex].wrap, edgeData[innerEdgeIndex1].wrap); // Twin Edge's source vertex changed, according to Outer Edge 1. edgeData[innerEdgeIndex1].wrap = EdgeWrapUtility.ModifyTargetFaceEdgeRelations(edgeData[innerEdgeIndex1].wrap, edgeData[edgeIndex].wrap); // Inner Edge 1's target face changed, according to Twin Edge. edgeData[outerEdgeIndex1].wrap = EdgeWrapUtility.ModifySourceFaceEdgeRelations(edgeData[outerEdgeIndex1].wrap, edgeData[twinEdgeIndex].wrap); // Outer Edge 1's source face changed, according to Edge. }