/// <summary> /// Static function to convert a list of points into a polygon without having a local object instance /// </summary> public static Polygon Get(List<Point2D> data) { Polygon p = new Polygon(); p.Import(data); return p; }
/// <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); }
/// <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> /// Given two polygons, and two tangent which will join together /// This function will create a polygon which merge the two polygons together using the tangents to bridge between them /// </summary> public static Polygon Wire(Polygon polygonA, Polygon polygonB, Vector2D lowerTangent, Vector2D upperTangent) { var wiredPolygon = new List<Point2D>(); //If UpperTangent.Start is equal to LowerTangent.Start, we need to end the loop early Boolean endEarly = PolygonManipulation.Equals(upperTangent.Start, lowerTangent.Start); //Add the start point to the wired polygon wiredPolygon.Add(upperTangent.Start); //Jump across the tangent at set the target at the current vertex var currentVertex = polygonB.GetVertex(upperTangent.Target); //Since we need to traverse each polygon in a different direction, this marks what polygon we are on Boolean leftPolygon = false; //While we aren't back at start do { //Add the current vertex to the wired polygon wiredPolygon.Add(currentVertex.Point); //If we have hit the lower tangent target if (PolygonManipulation.Equals(currentVertex.Point, lowerTangent.Target)) { //Jump across the lower tangent onto the other polygon leftPolygon = true; currentVertex = polygonA.GetVertex(lowerTangent.Start); wiredPolygon.Add(currentVertex.Point); //If we need to end early, break the loop if (endEarly) break; } //While we haven't find a suitable current vertex do { if (leftPolygon) { //Traverse Clockwise if (currentVertex == null || currentVertex.Point == null) currentVertex = polygonA.Tail.Prev; else currentVertex = currentVertex.Prev; } else { //Traverse Counterclockwise if (currentVertex == null || currentVertex.Point == null) currentVertex = polygonB.Tail.Prev; else currentVertex = currentVertex.Prev; } } while (currentVertex == null || currentVertex.Point == null); } while (!PolygonManipulation.Equals(currentVertex.Point, upperTangent.Start)); wiredPolygon = wiredPolygon.Distinct().ToList(); //Since the wired polygon is in clockwise order, we need to reverse it wiredPolygon.Reverse(); return Polygon.Get(wiredPolygon); }