public static List <Tuple <int, int> > ConvexHull(IEnumerable <Tuple <int, int> > input) { if (input == null) { throw new ArgumentNullException("input"); } List <Tuple <int, int> > points = new List <Tuple <int, int> >(input); Tuple <int, int> start = new Tuple <int, int>(int.MaxValue, int.MaxValue); List <int> indexes = new List <int>(); for (int i = 0; i < points.Count; i++) { if (points[i].Item2 < start.Item2 || points[i].Item2 == start.Item2 && points[i].Item1 < start.Item1) { start = points[i]; indexes.Clear(); indexes.Add(i); } else if (points[i] == start) { indexes.Add(i); } } for (int i = 0; i < indexes.Count; i++) { points.RemoveAt(indexes[i] - i); } AngleComparer comp = new AngleComparer(start); points.Sort(comp); List <Tuple <int, int> > temp = new List <Tuple <int, int> >(); for (int i = 0; i < points.Count; i++) { while (i < points.Count - 1 && comp.Compare(points[i], points[i + 1]) == 0) { if (Distance(points[i], start) - Distance(points[i + 1], start) <= 0) { i++; } else { Tuple <int, int> t = points[i]; points[i] = points[i + 1]; points[i + 1] = t; i++; } } temp.Add(points[i]); } points = temp; if (points.Count < 2) { return(null); } Stack <Tuple <int, int> > hull = new Stack <Tuple <int, int> >(); hull.Push(start); hull.Push(points[0]); hull.Push(points[1]); Tuple <int, int> top, belowTop; for (int i = 2; i < points.Count; i++) { top = hull.Pop(); belowTop = hull.Pop(); while (!LeftTurn(belowTop, top, points[i])) { top = belowTop; belowTop = hull.Pop(); } hull.Push(belowTop); hull.Push(top); hull.Push(points[i]); } points.Clear(); while (hull.Count > 0) { points.Add(hull.Pop()); } return(points); }
/// <summary> /// Returns the smallest polygon that contains all the points in the input. /// </summary> /// <param name="input">The set of points to calculate the convex hull of.</param> /// <returns>A list of points describing the convex hull in clockwise order.</returns> public static List <Vector2D> ConvexHull(IEnumerable <Vector2D> input) { if (input == null) { throw new ArgumentNullException("input"); } List <Vector2D> points = new List <Vector2D>(input); Vector2D start = new Vector2D(double.MaxValue, double.MaxValue); List <int> indexes = new List <int>(); for (int i = 0; i < points.Count; i++) { if (points[i].Y < start.Y || points[i].Y == start.Y && points[i].X < start.X) { start = points[i]; indexes.Clear(); indexes.Add(i); } else if (points[i] == start) { indexes.Add(i); } } for (int i = 0; i < indexes.Count; i++) { points.RemoveAt(indexes[i] - i); } AngleComparer comp = new AngleComparer(start); points.Sort(comp); List <Vector2D> temp = new List <Vector2D>(); for (int i = 0; i < points.Count; i++) { while (i < points.Count - 1 && comp.Compare(points[i], points[i + 1]) == 0) { if (Vector2D.Distance(points[i], start) - Vector2D.Distance(points[i + 1], start) <= 0) { i++; } else { Vector2D t = points[i]; points[i] = points[i + 1]; points[i + 1] = t; i++; } } temp.Add(points[i]); } points = temp; if (points.Count < 2) { return(null); } Stack <Vector2D> hull = new Stack <Vector2D>(); hull.Push(start); hull.Push(points[0]); hull.Push(points[1]); Vector2D top, belowTop; for (int i = 2; i < points.Count; i++) { top = hull.Pop(); belowTop = hull.Pop(); while (!LeftTurn(belowTop, top, points[i])) { top = belowTop; belowTop = hull.Pop(); } hull.Push(belowTop); hull.Push(top); hull.Push(points[i]); } points.Clear(); while (hull.Count > 0) { points.Add(hull.Pop()); } return(points); }