public Edge(SimplifiedEdge e, int rightPoly) { P0 = e.P0; P1 = e.P1; IsBidirectional = false; RightPoly = rightPoly; }
// Note: allows output to have consecutive colinear edges in a partition public DTMesh ExecuteToMesh(DTMesh input) { List <int> clearedPolys = new List <int>(); Dictionary <SimplifiedEdge, Edge> realEdges = new Dictionary <SimplifiedEdge, Edge>(); List <int>[] tempPartitions = new List <int> [input.Partitions.Count]; int[] polyRemapper = new int[input.Partitions.Count]; // Local function that gets the remapped polygon index for the given original index int getRemappedIndex(int i) { Stack <int> collapseStack = new Stack <int>(); while (i != polyRemapper[i]) { collapseStack.Push(i); i = polyRemapper[i]; } // Lazily collapse remapping chains (entries that remap multiple times should remap only once) while (collapseStack.Count > 0) { polyRemapper[collapseStack.Pop()] = i; } return(i); } // Determine internal edges and map them to their connected polygons for (int polyIndex = 0; polyIndex < input.Partitions.Count; polyIndex++) { List <int> poly = input.Partitions[polyIndex]; tempPartitions[polyIndex] = new List <int>(poly); polyRemapper[polyIndex] = polyIndex; // Add all the initial partitions (triangles if the input was a triangulation) for (int vertexIndex = 0; vertexIndex < poly.Count; vertexIndex++) { int v = poly[vertexIndex]; int vNext = poly.GetCircular(vertexIndex + 1); SimplifiedEdge e = new SimplifiedEdge(v, vNext); if (!realEdges.ContainsKey(e)) { // If this is the first time visiting this edge, make a new entry and add the right polygon realEdges[e] = new Edge(e, polyIndex); } else { // If we have already visited this edge, add the left polygon and make the edge bidirectional realEdges[e].IsBidirectional = true; realEdges[e].LeftPoly = polyIndex; } } } // Iterate internal edges and check if they can be removed without creating concave partitions foreach (var internalEdgePair in realEdges.Where(edgePair => edgePair.Value.IsBidirectional)) { SimplifiedEdge simpleEdge = internalEdgePair.Key; Edge realEdge = internalEdgePair.Value; // Find the index within the right polygon where the shared edge ends (P1) int rightPolyIndex = getRemappedIndex(realEdge.RightPoly); List <int> rightPoly = tempPartitions[rightPolyIndex]; int rightPolyStart = -1; for (int i = 0; i < rightPoly.Count; i++) { int p = rightPoly[i]; if (p == simpleEdge.P1) { rightPolyStart = i; break; } } // Find the index within the left polygon where the shared edge ends (P0) int leftPolyIndex = getRemappedIndex(realEdge.LeftPoly); List <int> leftPoly = tempPartitions[leftPolyIndex]; int leftPolyStart = -1; for (int i = 0; i < leftPoly.Count; i++) { int p = leftPoly[i]; if (p == simpleEdge.P0) { leftPolyStart = i; break; } } // Determine if the angle at the edge's P0 would become reflex if this edge were removed Vector2 rightPolyLastEdge = input.Vertices[rightPoly.GetCircular(rightPolyStart - 1)] - input.Vertices[rightPoly.GetCircular(rightPolyStart - 2)]; Vector2 leftPolyFirstEdge = input.Vertices[leftPoly.GetCircular(leftPolyStart + 1)] - input.Vertices[leftPoly.GetCircular(leftPolyStart)]; bool p0Reflex = Vector3.Cross(rightPolyLastEdge, leftPolyFirstEdge).z > 0; // Determine if the angle at the edge's P1 would become reflex if this edge were removed Vector2 leftPolyLastEdge = input.Vertices[leftPoly.GetCircular(leftPolyStart - 1)] - input.Vertices[leftPoly.GetCircular(leftPolyStart - 2)]; Vector2 rightPolyFirstEdge = input.Vertices[rightPoly.GetCircular(rightPolyStart + 1)] - input.Vertices[rightPoly.GetCircular(rightPolyStart)]; bool p1Reflex = Vector3.Cross(leftPolyLastEdge, rightPolyFirstEdge).z > 0; if (!p0Reflex && !p1Reflex) { // Remove the edge and merge the two polygons since the result will be convex // Add points from rightPoly in CW order from the removed edge's P1 to P0, including P1 but not P0 List <int> newPoly = rightPoly.GetRange(rightPolyStart, rightPoly.Count - rightPolyStart); newPoly.AddRange(rightPoly.GetRange(0, rightPolyStart)); newPoly.RemoveAt(newPoly.Count - 1); // Add points from left in CW order from the removed edge's P0 to P1, including P0 but not P1 newPoly.AddRange(leftPoly.GetRange(leftPolyStart, leftPoly.Count - leftPolyStart)); newPoly.AddRange(leftPoly.GetRange(0, leftPolyStart)); newPoly.RemoveAt(newPoly.Count - 1); // Modify the right polygon rightPoly.Clear(); rightPoly.AddRange(newPoly); // Clear the left polygon leftPoly.Clear(); clearedPolys.Add(leftPolyIndex); // Remap the left polygon index to match the right polyRemapper[leftPolyIndex] = rightPolyIndex; } } // Return a new mesh that copies the vertices of the original, but uses the merged partitions // (ignores the left partitions that we cleared) return(new DTMesh(new List <Vector2>(input.Vertices), tempPartitions.Where(partition => partition.Count > 0).ToList())); }