138 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Drawing;
 | 
						|
using System.Text;
 | 
						|
 | 
						|
namespace DevComponents.DotNetBar.Charts
 | 
						|
{
 | 
						|
    // Monotone Chain Convex Hull.
 | 
						|
    // It takes O(NlogN) in sorting & O(N) in actual convex hull calc for N points.
 | 
						|
 | 
						|
    public static class ConvexHull
 | 
						|
    {
 | 
						|
        #region GetConvexHull
 | 
						|
 | 
						|
        public static Point[] GetConvexHull(Point[] points)
 | 
						|
        {
 | 
						|
            int n = points.Length;
 | 
						|
 | 
						|
            Array.Sort(points, 0, n, new PointComparer());
 | 
						|
 | 
						|
            Point[] ans = new Point[2 * n];
 | 
						|
 | 
						|
            int k = 0;
 | 
						|
            int start = 0;
 | 
						|
 | 
						|
            // Bottom hull
 | 
						|
 | 
						|
            Point lpt = Point.Empty;
 | 
						|
 | 
						|
            for (int i = 0; i < n; i++)
 | 
						|
            {
 | 
						|
                Point p = points[i];
 | 
						|
 | 
						|
                if (PtCompare(p, lpt) == 0)
 | 
						|
                    continue;
 | 
						|
 | 
						|
                lpt = p;
 | 
						|
 | 
						|
                while (k - start >= 2)
 | 
						|
                {
 | 
						|
                    Point sp1 = PtSub(p, ans[k - 1]);
 | 
						|
                    Point sp2 = PtSub(p, ans[k - 2]);
 | 
						|
 | 
						|
                    if (PtCross(sp1, sp2) <= 0)
 | 
						|
                        break;
 | 
						|
 | 
						|
                    k--;
 | 
						|
                }
 | 
						|
 | 
						|
                ans[k++] = p;
 | 
						|
            }
 | 
						|
 | 
						|
            k--;
 | 
						|
 | 
						|
            // Top hull
 | 
						|
 | 
						|
            start = k;
 | 
						|
            lpt = Point.Empty;
 | 
						|
 | 
						|
            for (int i = n - 1; i >= 0; i--)
 | 
						|
            {
 | 
						|
                Point p = points[i];
 | 
						|
 | 
						|
                if (PtCompare(p, lpt) == 0)
 | 
						|
                    continue;
 | 
						|
 | 
						|
                lpt = p;
 | 
						|
 | 
						|
                while (k - start >= 2)
 | 
						|
                {
 | 
						|
                    Point sp1 = PtSub(p, ans[k - 1]);
 | 
						|
                    Point sp2 = PtSub(p, ans[k - 2]);
 | 
						|
 | 
						|
                    if (PtCross(sp1, sp2) <= 0)
 | 
						|
                        break;
 | 
						|
 | 
						|
                    k--;
 | 
						|
                }
 | 
						|
 | 
						|
                ans[k++] = p;
 | 
						|
            }
 | 
						|
 | 
						|
            k--;
 | 
						|
 | 
						|
            Point[] hullPoints = new Point[k + 1];
 | 
						|
            Array.Copy(ans, hullPoints, k);
 | 
						|
 | 
						|
            hullPoints[k] = hullPoints[0];
 | 
						|
 | 
						|
            return (hullPoints);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region PointComparer
 | 
						|
 | 
						|
        private class PointComparer : IComparer<Point>
 | 
						|
        {
 | 
						|
            public int Compare(Point pt1, Point pt2)
 | 
						|
            {
 | 
						|
                return (ConvexHull.PtCompare(pt1, pt2));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region PtCompare
 | 
						|
 | 
						|
        private static int PtCompare(Point pt1, Point pt2)
 | 
						|
        {
 | 
						|
            if (pt1.X == pt2.X)
 | 
						|
                return (pt1.Y - pt2.Y);
 | 
						|
 | 
						|
            return (pt1.X - pt2.X);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region PtCross
 | 
						|
 | 
						|
        private static int PtCross(Point pt1, Point pt2)
 | 
						|
        {
 | 
						|
            return (pt1.X * pt2.Y - pt1.Y * pt2.X);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region PtSub
 | 
						|
 | 
						|
        private static Point PtSub(Point pt1, Point pt2)
 | 
						|
        {
 | 
						|
            return (new Point(pt1.X - pt2.X, pt1.Y - pt2.Y));
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
    }
 | 
						|
}
 |