public static Voronoi FromDelaunay(Adjacency adjacency) { Voronoi v = new Voronoi(); int[] triangleRemapping = new int[adjacency.triangles.Count]; for (int i = 0; i < adjacency.triangles.Count; i++) { Adjacency.Triangle t = adjacency.triangles[i]; if (!t.valid) { triangleRemapping[i] = -1; continue; } Vertex c; float r; t.CircumCircle(adjacency.vertices, out c, out r); triangleRemapping[i] = v.vertices.Count; v.vertices.Add(c); } for (int i = 0; i < adjacency.triangles.Count; i++) { Adjacency.Triangle t = adjacency.triangles[i]; if (!t.valid) { continue; } for (int e = 0; e < 3; e++) { int adjT = adjacency.AdjacentTriangle(i, e); if (adjT < 0 || adjacency.triangles[adjT].valid == false) { continue; } if (triangleRemapping[adjT] < 0) { continue; // already processed } int voronoiV0 = triangleRemapping[i]; int voronoiV1 = triangleRemapping[adjT]; Debug.Assert(voronoiV0 >= 0 && voronoiV1 >= 0); // the 2 vertices shared by the adjacent triangles will become // the voronoi cells divided by the edge we're creating int cellA = adjacency.edges[Math.Abs(t.edges[e]) - 1].vertices[0]; int cellB = adjacency.edges[Math.Abs(t.edges[e]) - 1].vertices[1]; v.edges.Add(new Edge(voronoiV0, voronoiV1, cellA, cellB)); } triangleRemapping[i] = -1; } return(v); }
private static bool Delaunay2DInsertPoints(List <Vertex> vertices, Adjacency adjacency) { // Insert points HashSet <int> toCheck = new HashSet <int>(); for (int i = 0; i < vertices.Count; i++) { // Insert Vi Vertex Vi = vertices[i]; bool skip = false; for (int j = 0; j < adjacency.vertices.Count; j++) { if ((Vi - adjacency.vertices[j]).Length() <= COINCIDENT_POINTS_DISTANCE_EPSILON) { // the point has already been inserted. Skip it skip = true; break; } } if (skip) { continue; } if (OnDelaunayInsertPoint != null) { OnDelaunayInsertPoint(adjacency, Vi); } int tri = adjacency.PointInTriangle(Vi); if (tri < 0) { Debug.Assert(false); return(false); } // check whether the point lies exactly on one edge of the triangle int edgeIdx = adjacency.PointInTriangleEdge(Vi, tri); if (edgeIdx >= 0) { // split the edge by Vi int[] result; adjacency.SplitEdge(edgeIdx, Vi, out result); for (int j = 0; j < 4; j++) { if (result[j] >= 0) { toCheck.Add(result[j]); } } } else { // split the triangle in 3 int[] result; adjacency.SplitTriangle(tri, Vi, out result); for (int j = 0; j < 3; j++) { toCheck.Add(result[j]); } } while (toCheck.Count > 0) { int t = toCheck.Last <int>(); toCheck.Remove(t); Adjacency.Triangle triangle = adjacency.triangles[t]; if (!triangle.valid) { continue; } if (OnDelaunayTriangleCheck != null) { OnDelaunayTriangleCheck(adjacency, t); } // check Delaunay condition for (int e = 0; e < 3; e++) { if (!adjacency.triangles[t].valid) { continue; } int adjacentIdx = adjacency.AdjacentTriangle(t, e); if (adjacentIdx < 0) { continue; } int globalEdgeIndex = Math.Abs(triangle.edges[e]) - 1; Adjacency.Triangle adjacent = adjacency.triangles[adjacentIdx]; if (!adjacent.valid) { continue; } Debug.Assert(adjacent.valid); int edgeFromAdjacent = adjacent.LocalEdgeIndex(globalEdgeIndex); Debug.Assert(edgeFromAdjacent >= 0); int v = adjacency.VertexOutOfTriEdge(adjacentIdx, edgeFromAdjacent); Debug.Assert(v >= 0); Debug.Assert(!triangle.Contains(v)); if (triangle.InsideCircumcircle(adjacency.vertices[v], adjacency.vertices) > INSIDE_CIRCUMCIRCLE_EPSILON) { int[] result; if (adjacency.FlipTriangles(t, adjacentIdx, out result)) { toCheck.Add(result[0]); toCheck.Add(result[1]); //break; } } } } if (OnDelaunayStep != null) { OnDelaunayStep(adjacency); } } return(true); }
private static void Delaunay2DRemoveSuperTriangle(Adjacency adjacency, int stIdx1, int stIdx2, int stIdx3, out List <int> outTriangles, List <Vertex> vertices) { outTriangles = new List <int>(); // remove triangles containing vertices from the supertriangle for (int i = 0; i < adjacency.triangles.Count; i++) { Adjacency.Triangle triangle = adjacency.triangles[i]; if (!triangle.valid) { continue; } if (triangle.Contains(stIdx1) || triangle.Contains(stIdx2) || triangle.Contains(stIdx3)) { adjacency.RemoveTriangle(i); } else { for (int j = 0; j < 3; j++) { Debug.Assert(triangle.vertices[j] >= 0 && triangle.vertices[j] < adjacency.vertices.Count); outTriangles.Add(triangle.vertices[j]); } } } adjacency.invalidTriangles.Clear(); // remove first 3 vertices (belonging to the supertriangle) and remap all remaining tris for (int i = 0; i < outTriangles.Count; i++) { outTriangles[i] -= 3; } int numTris = adjacency.triangles.Count; for (int i = 0; i < numTris; i++) { if (!adjacency.triangles[i].valid) { int remappedTriangle = numTris - 1; if (remappedTriangle > i) { adjacency.triangles[i] = adjacency.triangles[remappedTriangle]; numTris--; // remap edges pointing to this triangle for (int e = 0; e < 3; e++) { int edgeIndex = Math.Abs(adjacency.triangles[i].edges[e]) - 1; if (adjacency.edges[edgeIndex].triangles[0] == remappedTriangle) { adjacency.edges[edgeIndex].triangles[0] = i; } if (adjacency.edges[edgeIndex].triangles[1] == remappedTriangle) { adjacency.edges[edgeIndex].triangles[1] = i; } } #if false for (int e = 0; e < adjacency.edges.Count; e++) { Adjacency.Edge edge = adjacency.edges[e]; for (int et = 0; et < 2; et++) { Debug.Assert(edge.triangles[et] != i); if (edge.triangles[et] == remappedTriangle) { edge.triangles[et] = i; } } } #endif i--; } } else { Adjacency.Triangle t = adjacency.triangles[i]; t.vertices[0] -= 3; t.vertices[1] -= 3; t.vertices[2] -= 3; } } adjacency.triangles.RemoveRange(numTris, adjacency.triangles.Count - numTris); adjacency.vertices = vertices; for (int i = 0; i < adjacency.edges.Count; i++) { adjacency.edges[i].vertices[0] -= 3; adjacency.edges[i].vertices[1] -= 3; } }