예제 #1
0
        public static Circle MakeCircle(IList <Point> points)
        {
            // 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 = Circle.INVALID;

            for (int i = 0; i < shuffled.Count; i++)
            {
                CustomPoint p = new CustomPoint(shuffled[i].X, shuffled[i].Y);
                if (c.r < 0 || !c.Contains(p))
                {
                    List <CustomPoint> shuffeledRange = new List <CustomPoint>();
                    foreach (var point in shuffled.GetRange(0, i + 1))
                    {
                        shuffeledRange.Add(new CustomPoint(point.X, point.Y));
                    }
                    c = MakeCircleOnePoint(shuffeledRange, p);
                }
            }
            return(c);
        }
예제 #2
0
        public double Distance(CustomPoint p)
        {
            double dx = x - p.x;
            double dy = y - p.y;

            return(Math.Sqrt(dx * dx + dy * dy));
        }
예제 #3
0
        // Two boundary points known
        private static Circle MakeCircleTwoPoints(List <CustomPoint> points, CustomPoint p, CustomPoint q)
        {
            Circle circ  = MakeDiameter(p, q);
            Circle left  = Circle.INVALID;
            Circle right = Circle.INVALID;

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

            foreach (CustomPoint 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);
            }
        }
예제 #4
0
        public static Circle MakeCircumcircle(CustomPoint a, CustomPoint b, CustomPoint c)
        {
            // Mathematical algorithm from Wikipedia: Circumscribed circle
            double ox = (Math.Min(Math.Min(a.x, b.x), c.x) + Math.Max(Math.Min(a.x, b.x), c.x)) / 2;
            double oy = (Math.Min(Math.Min(a.y, b.y), c.y) + Math.Max(Math.Min(a.y, b.y), c.y)) / 2;
            double ax = a.x - ox, ay = a.y - oy;
            double bx = b.x - ox, by = b.y - oy;
            double cx = c.x - ox, cy = c.y - oy;
            double d = (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) * 2;

            if (d == 0)
            {
                return(Circle.INVALID);
            }
            double      x = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
            double      y = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
            CustomPoint p = new CustomPoint(ox + x, oy + y);
            double      r = Math.Max(Math.Max(p.Distance(a), p.Distance(b)), p.Distance(c));

            return(new Circle(p, r));
        }
예제 #5
0
        private static Circle MakeCircleOnePoint(List <CustomPoint> points, CustomPoint p)
        {
            Circle c = new Circle(p, 0);

            for (int i = 0; i < points.Count; i++)
            {
                CustomPoint 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);
        }
예제 #6
0
 // Signed area / determinant thing
 public double Cross(CustomPoint p)
 {
     return(x * p.y - y * p.x);
 }
예제 #7
0
 public CustomPoint Subtract(CustomPoint p)
 {
     return(new CustomPoint(x - p.x, y - p.y));
 }
예제 #8
0
 public bool Contains(CustomPoint p)
 {
     return(c.Distance(p) <= r * MULTIPLICATIVE_EPSILON);
 }
예제 #9
0
        public double                 r; // Radius


        public Circle(CustomPoint c, double r)
        {
            this.c = c;
            this.r = r;
        }
예제 #10
0
        public static Circle MakeDiameter(CustomPoint a, CustomPoint b)
        {
            CustomPoint c = new CustomPoint((a.x + b.x) / 2, (a.y + b.y) / 2);

            return(new Circle(c, Math.Max(c.Distance(a), c.Distance(b))));
        }