Exemplo n.º 1
0
 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
             });
         }
     }
 }
Exemplo n.º 2
0
 public IEnumerable <DelaunatorEdge> GetEdgesOfTriangle(int t) => CreateHull(EdgesOfTriangle(t).Select(p => InputPoints.ElementAtOrDefault(p)));
Exemplo n.º 3
0
 public IEnumerable <Vector> GetTrianglePoints(int t) => PointsOfTriangle(t).Select(p => InputPoints.ElementAtOrDefault(p));
Exemplo n.º 4
0
 public IEnumerable <Vector> GetHullPoints() => hull.Select(x => InputPoints.ElementAtOrDefault(x));
Exemplo n.º 5
0
        //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);
                }
            }
        }