/*
         * Returns the smallest circle that encloses all the given points. Runs in expected O(n) time, randomized.
         * Note: If 0 points are given, a circle of radius -1 is returned. If 1 point is given, a circle of radius 0 is returned.
         */
        // Initially: No boundary points known
        public static Circle GetMinimumCoverCircle(List <Dot> dots)
        {
            List <Point> points = new List <Point>();

            foreach (Dot d in dots)
            {
                points.Add(new Point(d.Position.X, d.Position.Y));
            }
            // Clone list to preserve the caller's data, do Durstenfeld shuffle
            List <Point> shuffled = new List <Point>(points);
            Random       rand     = new Random();

            for (int i = shuffled.Count - 1; i > 0; i--)
            {
                int   j    = rand.Next(i + 1);
                Point temp = shuffled[i];
                shuffled[i] = shuffled[j];
                shuffled[j] = temp;
            }

            // Progressively add points to circle or recompute circle
            Circle c = new Circle(new Point(0, 0), -1);

            for (int i = 0; i < shuffled.Count; i++)
            {
                Point p = shuffled[i];
                if (c.r < 0 || !c.Contains(p))
                {
                    c = MakeCircleOnePoint(shuffled.GetRange(0, i + 1), p);
                }
            }
            return(c);
        }
        // Two boundary points known
        private static Circle MakeCircleTwoPoints(List <Point> points, Point p, Point q)
        {
            Circle circ  = MakeDiameter(p, q);
            Circle left  = new Circle(new Point(0, 0), -1);
            Circle right = new Circle(new Point(0, 0), -1);

            // For each point not in the two-point circle
            Point pq = q.Subtract(p);

            foreach (Point r in points)
            {
                if (circ.Contains(r))
                {
                    continue;
                }

                // Form a circumcircle and classify it on left or right side
                double cross = pq.Cross(r.Subtract(p));
                Circle c     = MakeCircumcircle(p, q, r);
                if (c.r < 0)
                {
                    continue;
                }
                else if (cross > 0 && (left.r < 0 || pq.Cross(c.c.Subtract(p)) > pq.Cross(left.c.Subtract(p))))
                {
                    left = c;
                }
                else if (cross < 0 && (right.r < 0 || pq.Cross(c.c.Subtract(p)) < pq.Cross(right.c.Subtract(p))))
                {
                    right = c;
                }
            }

            // Select which circle to return
            if (left.r < 0 && right.r < 0)
            {
                return(circ);
            }
            else if (left.r < 0)
            {
                return(right);
            }
            else if (right.r < 0)
            {
                return(left);
            }
            else
            {
                return(left.r <= right.r ? left : right);
            }
        }
        // One boundary point known
        private static Circle MakeCircleOnePoint(List <Point> points, Point p)
        {
            Circle c = new Circle(p, 0);

            for (int i = 0; i < points.Count; i++)
            {
                Point q = points[i];
                if (!c.Contains(q))
                {
                    if (c.r == 0)
                    {
                        c = MakeDiameter(p, q);
                    }
                    else
                    {
                        c = MakeCircleTwoPoints(points.GetRange(0, i + 1), p, q);
                    }
                }
            }
            return(c);
        }