/// <summary> /// Finds the ConvexHull of a series of points. See /// http://www.cs.princeton.edu/courses/archive/spr10/cos226/demo/ah/GrahamScan.html /// for further information. /// </summary> /// <param name="points">The points to compute the ConvexHull for</param> /// <returns>a collection of points that represents the polygon /// of the ConvexHull</returns> public static ICollection <Point> CalculateConvexHull(ICollection <Point> points) { if (points.Count <= 3) { return(points); } List <ConvexHullPoint> chPoints = new List <ConvexHullPoint>(); // Get the current anchor point anchor = new ConvexHullPoint(DetermineAnchorPoint(points), 0, null); // Loop over the points foreach (Point currentPoint in points) { // Ensure that this point is not the anchor if (currentPoint != anchor.Point) { // Create a new ConvexHUllPoint and save it for later use ConvexHullPoint newConvexHullPoint = new ConvexHullPoint(currentPoint, CalculateCartesianAngle(currentPoint.X - anchor.Point.X, currentPoint.Y - anchor.Point.Y), anchor); chPoints.Add(newConvexHullPoint); } } // Sort the points chPoints.Sort(); // Actually calculate and return the ConvexHull return(GrahamScan(chPoints)); }
/// <summary> /// Finds the ConvexHull of a series of points. See /// http://www.cs.princeton.edu/courses/archive/spr10/cos226/demo/ah/GrahamScan.html /// for further information. /// </summary> /// <param name="points">The points to compute the ConvexHull for</param> /// <returns>a collection of points that represents the polygon /// of the ConvexHull</returns> private static ICollection <Point> GrahamScan(List <ConvexHullPoint> chPoints) { Stack <ConvexHullPoint> chPointStack = new Stack <ConvexHullPoint>(); IEnumerator <ConvexHullPoint> enumerator = chPoints.GetEnumerator(); chPointStack.Push(anchor); chPointStack.Push(chPoints[0]); // Advance the enumerator to account for the two points // that we already got enumerator.MoveNext(); enumerator.MoveNext(); int i = 1; // Loop over all the points that were provided while (i < chPoints.Count) { // Ensure that stack contains points if (chPointStack.Count > 1) { ConvexHullPoint firstCHPoint = chPointStack.Pop(); ConvexHullPoint secondCHPoint = chPointStack.Pop(); chPointStack.Push(secondCHPoint); chPointStack.Push(firstCHPoint); if (Orientation(secondCHPoint, firstCHPoint, enumerator.Current) == COUNTER_CLOCKWISE) { chPointStack.Push(enumerator.Current); enumerator.MoveNext(); i++; } else { chPointStack.Pop(); } } else // No points in stack { chPointStack.Push(enumerator.Current); enumerator.MoveNext(); i++; } } return(GetSortedPoints(chPointStack)); }
/// <summary> /// Determines the orientation of the provided points /// </summary> /// <param name="chPoint1">The first ConvexHullPoint</param> /// <param name="chPoint2">The second ConvexHullPoint</param> /// <param name="chPoint3">The third ConvexHullPoint</param> /// <returns>a value indicating how the provided points are oriented</returns> private static int Orientation(ConvexHullPoint chPoint1, ConvexHullPoint chPoint2, ConvexHullPoint chPoint3) { return(Orientation(chPoint1.Point.X, chPoint1.Point.Y, chPoint2.Point.X, chPoint2.Point.Y, chPoint3.Point.X, chPoint3.Point.Y)); }