コード例 #1
0
        /// <summary>
        /// Compute the Delaunay triangluation of the supplied points. Note that
        /// the supplied point array must be by 3 larger than the actual number of
        /// points.
        /// </summary>
        private static void Triangulate2d(V2d[] pa,
                                          out Triangle1i[] ta, out int triangleCount)
        {
            int vc    = pa.Length - 4;
            int tcMax = 2 * vc + 2; // sharp upper bound with no degenerates
            int ecMax = 6 * vc - 3; // sharp bound: last step replaces all tris

            ta = new Triangle1i[tcMax];
            var ra = new double[tcMax];
            var ca = new V2d[tcMax];
            var ea = new Line1i[ecMax];

            // -------------------------------------- set up the supertriangle
            ta[0] = new Triangle1i(vc, vc + 2, vc + 1);
            ra[0] = -1.0;
            ta[1] = new Triangle1i(vc, vc + 3, vc + 2);
            ra[1] = -1.0;
            int tc = 2, cc = 0; // triangle count, complete count

            // ------------- superquad vertices at the end of vertex array
            var box = new Box2d(pa.Take(vc)).EnlargedBy(0.1);
            V2d center = box.Center, size = box.Size;

            pa[vc + 0] = box.Min;
            pa[vc + 1] = new V2d(box.Min.X, box.Max.Y);
            pa[vc + 2] = box.Max;
            pa[vc + 3] = new V2d(box.Max.X, box.Min.Y);

            // ------------------------------ include the points one at a time
            for (int i = 0; i < vc; i++)
            {
                V2d p  = pa[i];
                int ec = 0;

                /*
                 * if the point lies inside the circumcircle then the triangle
                 * is removed and its edges are added to the edge array
                 */
                for (int ti = cc; ti < tc; ti++)
                {
                    var    tr = ta[ti];
                    double r2 = ra[ti];
                    if (r2 < 0.0)
                    {
                        Triangle2d.ComputeCircumCircleSquared(
                            pa[tr.I0], pa[tr.I1], pa[tr.I2],
                            out center, out r2);
                        ra[ti] = r2; ca[ti] = center;
                    }
                    else
                    {
                        center = ca[ti];
                    }

                    // ---------------- include this if points are sorted by X
                    if (center.X < p.X && (p.X - center.X).Square() > r2)
                    {
                        Fun.Swap(ref ta[ti], ref ta[cc]);
                        ra[ti] = ra[cc]; ca[ti] = ca[cc];
                        ++cc; continue;
                    }
                    if (V2d.DistanceSquared(p, center) <= r2)
                    {
                        int nec = ec + 3;
                        if (nec >= ecMax)
                        {
                            ecMax = Fun.Max(nec, (int)(1.1 * (double)ecMax));
                            Array.Resize(ref ea, ecMax);
                        }
                        ea[ec]   = tr.Line01; ea[ec + 1] = tr.Line12; ea[ec + 2] = tr.Line20;
                        --tc; ec = nec;
                        ta[ti]   = ta[tc]; ra[ti] = ra[tc]; ca[ti] = ca[tc];
                        --ti;
                    }
                }

                // ---------------------------------------- tag multiple edges
                for (int ei = 0; ei < ec - 1; ei++)
                {
                    for (int ej = ei + 1; ej < ec; ej++)
                    {
                        if (ea[ei].I0 == ea[ej].I1 && ea[ei].I1 == ea[ej].I0)
                        {
                            ea[ei] = Line1i.Invalid; ea[ej] = Line1i.Invalid;
                        }
                    }
                }

                // ------------------ form new triangles for the current point
                for (int ei = 0; ei < ec; ei++)
                {
                    var e = ea[ei];
                    if (e.I0 < 0 || e.I1 < 0)
                    {
                        continue;    // skip tagged edges
                    }
                    if (tc >= tcMax) // necessary for degenerate cases
                    {
                        tcMax = Fun.Max(tcMax + 1, (int)(1.1 * (double)tcMax));
                        Array.Resize(ref ta, tcMax);
                        Array.Resize(ref ra, tcMax);
                        Array.Resize(ref ca, tcMax);
                    }
                    ta[tc]   = new Triangle1i(e.I0, e.I1, i);
                    ra[tc++] = -1.0;
                }
            }

            // ------------------ remove triangles with supertriangle vertices
            for (int ti = 0; ti < tc; ti++)
            {
                if (ta[ti].I0 >= vc || ta[ti].I1 >= vc || ta[ti].I2 >= vc)
                {
                    ta[ti--] = ta[--tc];
                }
            }

            triangleCount = tc;
        }