/// <summary> /// This method uses a different method to the Monotone Chain convex hull /// Instead of storing the vertices of the polygon in lists /// The vertices are stored as doubly linked lists /// </summary> private static Polygon RecursiveSolve(Polygon points, bool stepThrough = false) { //If there are few enough points to warrant the Graham Scan algorithm if (points.Count() <= MinimumSize) { return Polygon.Get(ConvexHull.Solve(points.Convert())); } //Sort the points by x value and then by y value var sortedPoints = PolygonManipulation.SortLexographically(points.Convert()); //Split points into two sets var a = new List<Point2D>(); var b = new List<Point2D>(); a.AddRange(sortedPoints.Take(sortedPoints.Count()/2)); b.AddRange(sortedPoints.Skip(sortedPoints.Count()/2).Take(sortedPoints.Count() - sortedPoints.Count()/2)); //Compute the convex hulls of a and b recursively var polyA = RecursiveSolve(Polygon.Get(a), stepThrough); var polyB = RecursiveSolve(Polygon.Get(b), stepThrough); //Merge the convex hulls together return Merge(polyA, polyB, stepThrough); }
/// <summary> /// Merges two convex hulls into one convex hull /// Finds upper and lower tangents and removes the points in between /// </summary> private static Polygon Merge(Polygon polygonA, Polygon polygonB, Boolean stepThrough) { //Since a lot of functions require polygons of type List<Point2D> //Convert them here to save time converting lots later on var newPolygonA = PolygonManipulation.SortLexographically(polygonA.Convert()); var newPolygonB = PolygonManipulation.SortLexographically(polygonB.Convert()); //Get the rightmost point of polygon A and the leftmost point of polygon B var tangentPointA = GetRightmostPoint(newPolygonA); var tangentPointB = GetLeftmostPoint(newPolygonB); //Find lower tangent //While Tangent = tangentPointA -> tangentPointB is not a lower tangent to both A and B while (!(IsLowerTangent(newPolygonA, tangentPointA, tangentPointB) && IsLowerTangent(newPolygonB, tangentPointB,tangentPointA))) { //While Tangent = tangentPointA -> tangentPointB is not a lower tangent to A while (!IsLowerTangent(newPolygonA, tangentPointA,tangentPointB)) { //Move counter clockwise tangentPointA = PolygonManipulation.GetNextPoint(newPolygonA, tangentPointA); } //While Tangent = tangentPointA -> tangentPointB is not a lower tangent to B while (!IsLowerTangent(newPolygonB, tangentPointB,tangentPointA)) { //Move clockwise tangentPointB = PolygonManipulation.GetPreviousPoint(newPolygonB, tangentPointB); } } //Get the lower tangent Vector2D lowerTangent = new Vector2D(tangentPointA, tangentPointB); //Reset the tangent points tangentPointA = GetRightmostPoint(newPolygonA); tangentPointB = GetLeftmostPoint(newPolygonB); //While Tangent = tangentPointA -> tangentPointB is not an upper tangent to both A and B while (!IsUpperTangent(newPolygonA, tangentPointA, tangentPointB) || !(IsUpperTangent(newPolygonB, tangentPointB, tangentPointA))) { //While Tangent = tangentPointA -> tangentPointB is not an upper tangent to A while (!IsUpperTangent(newPolygonA, tangentPointA, tangentPointB)) { //Move counter clockwise tangentPointA = PolygonManipulation.GetPreviousPoint(newPolygonA, tangentPointA); } //While Tangent = tangentPointA -> tangentPointB is not an upper tangent to B while (!IsUpperTangent(newPolygonB, tangentPointB, tangentPointA)) { //Move clockwise tangentPointB = PolygonManipulation.GetNextPoint(newPolygonB, tangentPointB); } } //Get the upper tangent Vector2D upperTangent = new Vector2D(tangentPointA, tangentPointB); //Draw tangents if in step through mode if (stepThrough) { //Convert the polygons into a format for drawing var listPolygonA = polygonA.Convert(); var listPolygonB = polygonB.Convert(); //If the polygons have more than two points, fill them in if (listPolygonA.Count > 2) { GraphicalUserInterface.DrawPolygon(listPolygonA, true, XOffset, YOffset, new System.Drawing.SolidBrush(System.Drawing.Color.Coral)); GraphicalUserInterface.DrawPolygon(polygonB.Convert(), true, XOffset, YOffset); } GraphicalUserInterface.DrawPolygon(listPolygonA, false, XOffset, YOffset, new System.Drawing.SolidBrush(System.Drawing.Color.Coral)); GraphicalUserInterface.DrawPolygon(polygonB.Convert(), false, XOffset, YOffset); GraphicalUserInterface.GraphicsObject.DrawLine(new System.Drawing.Pen(System.Drawing.Color.Blue) { Width = 4 }, lowerTangent.Start.Convert(XOffset, YOffset, GraphicalUserInterface.SizeMultiplier), lowerTangent.Target.Convert(XOffset, YOffset, GraphicalUserInterface.SizeMultiplier)); GraphicalUserInterface.GraphicsObject.DrawLine(new System.Drawing.Pen(System.Drawing.Color.Black) { Width = 4 }, upperTangent.Start.Convert(XOffset, YOffset, GraphicalUserInterface.SizeMultiplier), upperTangent.Target.Convert(XOffset, YOffset, GraphicalUserInterface.SizeMultiplier)); //Wait for the user to enter a key into the console to continue Console.ReadKey(); } //Wire together the polygons by tangent return Wire(polygonA, polygonB, lowerTangent, upperTangent); }