Пример #1
0
        private static void solve(List <Point> points, Hull hull, List <Triad> triads, bool hullOnly)
        {
            int N = points.Count;

            double[] distSqCentre = new double[N];
            int[]    sortedInd    = new int[N];
            for (int i = 0; i < N; i++)
            {
                distSqCentre[i] = points[0].distSqTo(points[i]);
                sortedInd[i]    = i;
            }
            Array.Sort(distSqCentre, sortedInd);
            int    mid = -1;
            double rmin2 = double.PositiveInfinity, circumcentreX = 0, circumcentreY = 0;
            Triad  tri = new Triad(sortedInd[0], sortedInd[1], sortedInd[2]);

            for (int i = 2; i < N; i++)
            {
                tri.c = sortedInd[i];
                if (tri.findCircumcircle(points) && tri.circumcircleR2 < rmin2)
                {
                    mid           = i;
                    rmin2         = tri.circumcircleR2;
                    circumcentreX = tri.circumcircleX;
                    circumcentreY = tri.circumcircleY;
                }
                else if (rmin2 * 4 < distSqCentre[i])
                {
                    break;
                }
            }
            if (mid != 2)
            {
                int    midInd    = sortedInd[mid];
                double distSqMid = distSqCentre[mid];
                Array.Copy(sortedInd, 2, sortedInd, 3, mid - 2);
                Array.Copy(distSqCentre, 2, distSqCentre, 3, mid - 2);
                sortedInd[2]    = midInd;
                distSqCentre[2] = distSqMid;
            }
            tri.c = sortedInd[2];
            tri.makeClockwise(points);
            tri.findCircumcircle(points);
            triads.Add(tri);
            hull.Add(new HullPoint(points, tri.a));
            hull.Add(new HullPoint(points, tri.b));
            hull.Add(new HullPoint(points, tri.c));
            Point centre = new Point(circumcentreX, circumcentreY);

            for (int i = 3; i < N; i++)
            {
                distSqCentre[i] = points[sortedInd[i]].distSqTo(centre);
            }
            Array.Sort(distSqCentre, sortedInd, 3, N - 3);
            int T = 0;

            for (int i = 3; i < N; i++)
            {
                int        pInd = sortedInd[i];
                HullPoint  p = new HullPoint(points, pInd);
                double     dx = p.x - hull[0].x, dy = p.y - hull[0].y;
                int        H = hull.Count, hInd = 0;
                List <int> pInds = new List <int>(), tInds = new List <int>();
                if (hull.edgeVisibleFrom(0, dx, dy))
                {
                    hInd = 0;
                    if (hull.edgeVisibleFrom(H - 1, dx, dy))
                    {
                        pInds.Add(hull[H - 1].pInd);
                        tInds.Add(hull[H - 1].tInd);
                        for (int h = 0; h < H - 1; h++)
                        {
                            pInds.Add(hull[h].pInd);
                            tInds.Add(hull[h].tInd);
                            if (hull.edgeVisibleFrom(h, p))
                            {
                                hull.RemoveAt(h);
                                h--;
                                H--;
                            }
                            else
                            {
                                hull.Insert(0, p);
                                H++;
                                break;
                            }
                        }
                        for (int h = H - 2; h > 0; h--)
                        {
                            if (hull.edgeVisibleFrom(h, p))
                            {
                                pInds.Insert(0, hull[h].pInd);
                                tInds.Insert(0, hull[h].tInd);
                                hull.RemoveAt(h + 1);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        hInd = 1;
                        pInds.Add(hull[0].pInd);
                        tInds.Add(hull[0].tInd);
                        for (int h = 1; h < H; h++)
                        {
                            pInds.Add(hull[h].pInd);
                            tInds.Add(hull[h].tInd);
                            if (hull.edgeVisibleFrom(h, p))
                            {
                                hull.RemoveAt(h);
                                h--;
                                H--;
                            }
                            else
                            {
                                hull.Insert(h, p);
                                break;
                            }
                        }
                    }
                }
                else
                {
                    int e1 = -1, e2 = H;
                    for (int h = 1; h < H; h++)
                    {
                        if (hull.edgeVisibleFrom(h, p))
                        {
                            if (e1 < 0)
                            {
                                e1 = h;
                            }
                        }
                        else
                        {
                            if (e1 > 0)
                            {
                                e2 = h;
                                break;
                            }
                        }
                    }
                    if (e2 < H)
                    {
                        for (int e = e1; e <= e2; e++)
                        {
                            pInds.Add(hull[e].pInd);
                            tInds.Add(hull[e].tInd);
                        }
                    }
                    else
                    {
                        for (int e = e1; e < e2; e++)
                        {
                            pInds.Add(hull[e].pInd);
                            tInds.Add(hull[e].tInd);
                        }
                        pInds.Add(hull[0].pInd);
                    }
                    if (e1 < e2 - 1)
                    {
                        hull.RemoveRange(e1 + 1, e2 - e1 - 1);
                    }
                    hull.Insert(e1 + 1, p);
                    hInd = e1 + 1;
                }
                if (hullOnly)
                {
                    continue;
                }
                int a = pInd, T0;
                int P = pInds.Count();
                T = T0 = triads.Count();
                for (int j = 0; j < P - 1; j++)
                {
                    Triad t = new Triad(a, pInds[j], pInds[j + 1]);
                    t.findCircumcircle(points);
                    t.bc = tInds[j];
                    if (j > 0)
                    {
                        t.ab = T - 1;
                    }
                    t.ac = T + 1;
                    Triad u = triads[tInds[j]];
                    if ((t.b == u.a && t.c == u.b) || (t.b == u.b && t.c == u.a))
                    {
                        u.ab = T;
                    }
                    else if ((t.b == u.a && t.c == u.c) || (t.b == u.c && t.c == u.a))
                    {
                        u.ac = T;
                    }
                    else if ((t.b == u.b && t.c == u.c) || (t.b == u.c && t.c == u.b))
                    {
                        u.bc = T;
                    }
                    triads.Add(t);
                    T++;
                }
                triads[T - 1].ac = -1;
                hull[hInd].tInd  = T - 1;
                if (hInd > 0)
                {
                    hull[hInd - 1].tInd = T0;
                }
                else
                {
                    H = hull.Count;
                    hull[hull.Count - 1].tInd = T0;
                }
            }
        }