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
}
}