public IEnumerable <DelaunatorEdge> GetEdges() { for (var e = 0; e < Triangles.Length; e++) { if (e > Halfedges[e]) { var p = InputPoints.ElementAtOrDefault(Triangles[e]); var q = InputPoints.ElementAtOrDefault(Triangles[NextHalfedge(e)]); yield return(new DelaunatorEdge { Index = e, P = p, Q = q }); } } }
public IEnumerable <DelaunatorEdge> GetEdgesOfTriangle(int t) => CreateHull(EdgesOfTriangle(t).Select(p => InputPoints.ElementAtOrDefault(p)));
public IEnumerable <Vector> GetTrianglePoints(int t) => PointsOfTriangle(t).Select(p => InputPoints.ElementAtOrDefault(p));
public IEnumerable <Vector> GetHullPoints() => hull.Select(x => InputPoints.ElementAtOrDefault(x));
//public Delaunator(IEnumerable<DelaunatorPoint> points) public override void Run() { if (InputPoints.Count() < 2) { throw new ArgumentOutOfRangeException("Need at least 3 points"); } //Points = points.ToList(); coords = new double[InputPoints.Count * 2]; for (var i = 0; i < InputPoints.Count; i++) { var p = InputPoints.ElementAtOrDefault(i); coords[2 * i] = p.X; coords[2 * i + 1] = p.Y; } var n = coords.Length >> 1; var maxTriangles = 2 * n - 5; Triangles = new int[maxTriangles * 3]; Halfedges = new int[maxTriangles * 3]; hashSize = (int)Math.Ceiling(Math.Sqrt(n)); hullPrev = new int[n]; hullNext = new int[n]; hullTri = new int[n]; hullHash = new int[hashSize]; var ids = new int[n]; var minX = double.PositiveInfinity; var minY = double.PositiveInfinity; var maxX = double.NegativeInfinity; var maxY = double.NegativeInfinity; for (var i = 0; i < n; i++) { var x = coords[2 * i]; var y = coords[2 * i + 1]; if (x < minX) { minX = x; } if (y < minY) { minY = y; } if (x > maxX) { maxX = x; } if (y > maxY) { maxY = y; } ids[i] = i; } var cx = (minX + maxX) / 2; var cy = (minY + maxY) / 2; var minDist = double.PositiveInfinity; int i0 = 0, i1 = 0, i2 = 0; // pick a seed point close to the center for (int i = 0; i < n; i++) { var d = Dist(cx, cy, coords[2 * i], coords[2 * i + 1]); if (d < minDist) { i0 = i; minDist = d; } } var i0x = coords[2 * i0]; var i0y = coords[2 * i0 + 1]; minDist = double.PositiveInfinity; // find the point closest to the seed for (int i = 0; i < n; i++) { if (i == i0) { continue; } var d = Dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]); if (d < minDist && d > 0) { i1 = i; minDist = d; } } var i1x = coords[2 * i1]; var i1y = coords[2 * i1 + 1]; var minRadius = double.PositiveInfinity; // find the third point which forms the smallest circumcircle with the first two for (int i = 0; i < n; i++) { if (i == i0 || i == i1) { continue; } var r = Circumradius(i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]); if (r < minRadius) { i2 = i; minRadius = r; } } var i2x = coords[2 * i2]; var i2y = coords[2 * i2 + 1]; if (minRadius == double.PositiveInfinity) { throw new Exception("No Delaunay triangulation exists for this input."); } if (Orient(i0x, i0y, i1x, i1y, i2x, i2y)) { var i = i1; var x = i1x; var y = i1y; i1 = i2; i1x = i2x; i1y = i2y; i2 = i; i2x = x; i2y = y; } var center = Circumcenter(i0x, i0y, i1x, i1y, i2x, i2y); _cx = center.X; _cy = center.Y; var dists = new double[n]; for (var i = 0; i < n; i++) { dists[i] = Dist(coords[2 * i], coords[2 * i + 1], center.X, center.Y); } // sort the points by distance from the seed triangle circumcenter Quicksort(ids, dists, 0, n - 1); // set up the seed triangle as the starting hull hullStart = i0; hullSize = 3; hullNext[i0] = hullPrev[i2] = i1; hullNext[i1] = hullPrev[i0] = i2; hullNext[i2] = hullPrev[i1] = i0; hullTri[i0] = 0; hullTri[i1] = 1; hullTri[i2] = 2; hullHash[HashKey(i0x, i0y)] = i0; hullHash[HashKey(i1x, i1y)] = i1; hullHash[HashKey(i2x, i2y)] = i2; trianglesLen = 0; AddTriangle(i0, i1, i2, -1, -1, -1); double xp = 0; double yp = 0; for (var k = 0; k < ids.Length; k++) { var i = ids[k]; var x = coords[2 * i]; var y = coords[2 * i + 1]; // skip near-duplicate points if (k > 0 && Math.Abs(x - xp) <= EPSILON && Math.Abs(y - yp) <= EPSILON) { continue; } xp = x; yp = y; // skip seed triangle points if (i == i0 || i == i1 || i == i2) { continue; } // find a visible edge on the convex hull using edge hash var start = 0; for (var j = 0; j < hashSize; j++) { var key = HashKey(x, y); start = hullHash[(key + j) % hashSize]; if (start != -1 && start != hullNext[start]) { break; } } start = hullPrev[start]; var e = start; var q = hullNext[e]; while (!Orient(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1])) { e = q; if (e == start) { e = int.MaxValue; break; } q = hullNext[e]; } if (e == int.MaxValue) { continue; // likely a near-duplicate point; skip it } // add the first triangle from the point var t = AddTriangle(e, i, hullNext[e], -1, -1, hullTri[e]); // recursively flip triangles from the point until they satisfy the Delaunay condition hullTri[i] = Legalize(t + 2); hullTri[e] = t; // keep track of boundary triangles on the hull hullSize++; // walk forward through the hull, adding more triangles and flipping recursively var next = hullNext[e]; q = hullNext[next]; while (Orient(x, y, coords[2 * next], coords[2 * next + 1], coords[2 * q], coords[2 * q + 1])) { t = AddTriangle(next, i, q, hullTri[i], -1, hullTri[next]); hullTri[i] = Legalize(t + 2); hullNext[next] = next; // mark as removed hullSize--; next = q; q = hullNext[next]; } // walk backward from the other side, adding more triangles and flipping if (e == start) { q = hullPrev[e]; while (Orient(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1])) { t = AddTriangle(q, i, e, -1, hullTri[e], hullTri[q]); Legalize(t + 2); hullTri[q] = t; hullNext[e] = e; // mark as removed hullSize--; e = q; q = hullPrev[e]; } } // update the hull indices hullStart = hullPrev[i] = e; hullNext[e] = hullPrev[next] = i; hullNext[i] = next; // save the two new edges in the hash table hullHash[HashKey(x, y)] = i; hullHash[HashKey(coords[2 * e], coords[2 * e + 1])] = e; } hull = new int[hullSize]; var s = hullStart; for (var i = 0; i < hullSize; i++) { hull[i] = s; s = hullNext[s]; } hullPrev = hullNext = hullTri = null; // get rid of temporary arrays //// trim typed triangle mesh arrays Triangles = Triangles.Take(trianglesLen).ToArray(); Halfedges = Halfedges.Take(trianglesLen).ToArray(); var layer = History.CreateAndAddNewLayer("Final Result"); //AddEdgesToLayer(layer); if (!voronoiOperation) { foreach (var edge in GetEdges()) { var v1 = edge.P; var v2 = edge.Q; AddLineCommand(layer, v1, v2); } } else { //foreach (var edge in GetVoronoDelaunatorEdges()) //{ // var v1 = edge.P; // var v2 = edge.Q; // AddNonIndexedLineCommand(layer, v1, v2); //} foreach (var cell in GetVoronoiCells()) { var poly = new PolygonModel(); //foreach (var p in cell.Points) for (int i = 0; i < cell.Points.Count; i++) { var sp = cell.Points[i]; var np = cell.Points[(i + 1) % cell.Points.Count]; poly.Lines.Add(new LineModel { StartPoint = new Vector { X = sp.X, Y = sp.Y }, EndPoint = new Vector { X = np.X, Y = np.Y } }); } AddNonIndexedPolygonCommand(layer, poly); } } }