/// <summary> /// Takes all the hull points and strings them together /// </summary> /// <param name="p_cho"></param> /// <returns></returns> private static List <Point> connectTheDots(ConvexHullObject p_cho) { List <Point> hullPoints = new List <Point>(); //add all of Q1 hullPoints.AddRange(p_cho.m_Q1.hullPoints); //remove duplicates if (hullPoints.Last().Equals(p_cho.m_Q4.hullPoints.First())) { hullPoints.RemoveAt(hullPoints.Count - 1); } hullPoints.AddRange(p_cho.m_Q4.hullPoints); if (hullPoints.Last().Equals(p_cho.m_Q3.hullPoints.First())) { hullPoints.RemoveAt(hullPoints.Count - 1); } hullPoints.AddRange(p_cho.m_Q3.hullPoints); if (hullPoints.Last().Equals(p_cho.m_Q2.hullPoints.First())) { hullPoints.RemoveAt(hullPoints.Count - 1); } //rinse and repeat hullPoints.AddRange(p_cho.m_Q2.hullPoints); if (hullPoints.Last().Equals(hullPoints.First())) { hullPoints.RemoveAt(hullPoints.Count - 1); } return(hullPoints); }
/// <summary> /// Using Liu and Chen's Convex shell algorithm to quicly find the outside points of the hand /// </summary> /// <param name="p_dataPoints"></param> /// <returns>List of hull points</returns> /// <seealso cref="http://www.codeproject.com/Articles/775753/A-Convex-Hull-Algorithm-and-its-implementation-in"/> public static List <Point> getConvexHull(List <Point> p_dataPoints) { ConvexHullObject cho = new ConvexHullObject(); //get root points getRoots(p_dataPoints, ref cho); //Get the shell in each quadrant getShell(p_dataPoints, cho); return(connectTheDots(cho)); }
/// <summary> /// prepare the data and send it off to be worked on in parallel /// </summary> /// <param name="p_dataPoints"></param> /// <param name="p_cho"></param> private static void getShell(List <Point> p_dataPoints, ConvexHullObject p_cho) { List <Point> ySortedList = p_dataPoints.OrderBy(p => p.Y).ThenBy(p => p.X).ToList(); List <Point> xSortedList = p_dataPoints.OrderBy(p => p.X).ThenBy(p => p.Y).ToList(); Parallel.Invoke( () => { p_cho.m_Q1.evaluate(ySortedList); }, () => { p_cho.m_Q2.evaluate(ySortedList); }, () => { p_cho.m_Q3.evaluate(xSortedList); }, () => { p_cho.m_Q4.evaluate(xSortedList); }); }
/// <summary> /// This part is to find the vertex of the extreme points thus creating 4 areas with shell points. /// </summary> /// <param name="p_dataPoints">data points to search</param> /// <param name="p_cho">object that stores data</param> private static void getRoots(List <Point> p_dataPoints, ref ConvexHullObject p_cho) { int xMin, yMin, xMax, yMax; xMax = yMax = 0; xMin = yMin = Int32.MaxValue; foreach (Point point in p_dataPoints) { #region Setting Left Roots //If this is the leftmost point set both roots Y to its Y if (point.X < xMin) { //I'm worried about them having references to each other // becuase they are not always the same p_cho.m_Q2.xPoint = point; p_cho.m_Q3.xPoint = point; xMin = point.X; } //If the X point equals the min set the Y values to the extremes else if (point.X == xMin) { if (point.Y < p_cho.m_Q2.xPoint.Y) { p_cho.m_Q2.xPoint = point; } else if (point.Y > p_cho.m_Q3.xPoint.Y) { p_cho.m_Q3.xPoint = point; } } #endregion #region Setting Right Roots //If this is the rightmost point set both roots Y to its Y else if (point.X > xMax) { p_cho.m_Q1.xPoint = point; p_cho.m_Q4.xPoint = point; xMax = point.X; } //If the X point equals the max, set the Y values to the extremes else if (point.X == xMax) { if (point.Y < p_cho.m_Q1.xPoint.Y) { p_cho.m_Q1.xPoint = point; } else if (point.Y > p_cho.m_Q4.xPoint.Y) { p_cho.m_Q4.xPoint = point; } } #endregion #region Setting Top Roots //If this is the topmost point, set both roots X to its X if (point.Y < yMin) { p_cho.m_Q1.yPoint = point; p_cho.m_Q2.yPoint = point; yMin = point.Y; } //If the Y point equals the min, set the X values to the extremes else if (point.Y == yMin) { if (point.X < p_cho.m_Q2.yPoint.X) { p_cho.m_Q2.yPoint = point; } else if (point.X > p_cho.m_Q1.yPoint.X) { p_cho.m_Q1.yPoint = point; } } #endregion #region Setting Bottom Roots //If this is the bottommost point, set both roots X to its X else if (point.Y > yMax) { p_cho.m_Q3.yPoint = point; p_cho.m_Q4.yPoint = point; yMax = point.Y; } //If the Y point equals the max, set the X values to the extremes else if (point.Y == yMax) { if (point.X < p_cho.m_Q3.yPoint.X) { p_cho.m_Q3.yPoint = point; } else if (point.X > p_cho.m_Q4.yPoint.X) { p_cho.m_Q4.yPoint = point; } } #endregion } }