/// <summary>
        /// Checks if the gradient of ab = cd
        /// </summary>
        public static Boolean GradientEquals(Point2D a, Point2D b, Point2D c, Point2D d)
        {
            float run1 = b.X - a.X;
            float run2 = d.X - c.X;
            float rise1 = b.Y - a.Y;
            float rise2 = d.Y - c.Y;

            if (run1 == 0)
                if (run2 == 0)
                    return true;
                else
                    return false;

            if (run2 == 0)
                return false;

            if (rise1 == 0)
                if (rise2 == 0)
                    return true;
                else
                    return false;

            if (rise2 == 0)
                return false;

            return rise1/run1 == rise2/run2;
        }
 /// <summary>
 /// Gets the next point in the list - usually counter clockwise direction
 /// </summary>
 public static Point2D GetNextPoint(List<Point2D> polygon, Point2D currentPoint)
 {
     var index = PolygonManipulation.IndexOf(polygon, currentPoint);
     if (index == polygon.Count - 1)
         return polygon[0];
     else
         return polygon[index+1];
 }
 /// <summary>
 /// Whether a list of points contains a certain point
 /// </summary>
 public static Boolean Contains(List<Point2D> points, Point2D point)
 {
     for (int i = 0; i < points.Count; i++)
     {
         if (points[i].X == point.X && points[i].Y == point.Y)
             return true;
     }
     return false;
 }
        /// <summary>
        /// Constructor used when a list of polygons and the start and end coordinates are
        /// passed
        /// </summary>
        public Map(IEnumerable<List<Point2D>> polygons, Point2D start, Point2D end)
            : this()
        {
            foreach (var polygon in polygons)
            {
                //Add the polygon to the map with its unique sprite
                Polygons.Add(polygon);
            }

            //Set the start and end coordinates
            Start = start;
            End = end;
        }
        /// <summary>
        /// Given a convex hull and a start point and end point which are points on the convex hull
        /// Traverses the convex hull both clockwise and counterwise and returns the list of points with the minimum length
        /// </summary>
        public static List<Point2D> GetMinimumPolygonChain(List<Point2D> convexHull, Point2D start, Point2D end)
        {
            var circularHull = convexHull;// OrganiseClockwise(convexHull);

            var clockwiseChain = new List<Point2D>();
            var counterClockwiseChain = new List<Point2D>();

            //Clockwise chain
            //Start at the start index
            Int32 currentIndex = circularHull.IndexOf(start);

            //While the end isn't reached
            while (!PolygonManipulation.Equals(circularHull[currentIndex], end) || circularHull.Count == clockwiseChain.Count)
            {
                //Add the point to the polygon chain
                clockwiseChain.Add(circularHull[currentIndex]);

                //Go to next point
                if (currentIndex < circularHull.Count - 1)
                    currentIndex++;
                else
                    currentIndex = 0;
            }

            //Add the end
            clockwiseChain.Add(end);

            //Counterclockwise chain
            //Start at the start index
            currentIndex = circularHull.IndexOf(start);

            //While the end isn't reached
            while (!PolygonManipulation.Equals(circularHull[currentIndex], end) || circularHull.Count == counterClockwiseChain.Count)
            {
                //Add the point to the polygon chain
                counterClockwiseChain.Add(circularHull[currentIndex]);

                //Go to prev point
                if (currentIndex > 0)
                    currentIndex--;
                else
                    currentIndex = circularHull.Count - 1;
            }

            //Add the end
            counterClockwiseChain.Add(end);

            //Return the shortest chain
            return GetPolygonChainDistance(counterClockwiseChain) > GetPolygonChainDistance(clockwiseChain) ? clockwiseChain : counterClockwiseChain;
        }
        /// <summary>
        /// Gets the point on a polygon which is closest to a given point
        /// </summary>
        public static Point2D GetClosestPoint(List<Point2D> polygon, Point2D from)
        {
            float minDistance = float.MaxValue;
            Point2D closestPoint = null;

            foreach (var point in polygon)
            {
                var distance = ConvexHull.GetDistance(point, from);
                if (distance < minDistance && !PolygonManipulation.Equals(from, point))
                {
                    minDistance = distance;
                    closestPoint = point;
                }
            }

            return closestPoint;
        }
        /// <summary>
        /// Determines is pq is the lower tangent of the polygon
        /// Pseudocode from https://facwiki.cs.byu.edu/cs312ringger/index.php/Project_2
        /// (Geometry for Common Tangents)
        /// </summary>
        public static Boolean IsLowerTangent(List<Point2D> polygon, Point2D p, Point2D q)
        {
            //Calculate the gradient taking precautions againist division by zero
            double m;
            Int32 sum = p.X - q.X;
            if (sum == 0)
                //Not double.Max because we don't want to overflow
                m = 9999999;
            else
                m = ((double)p.Y - (double)q.Y) / (double)sum;

            //Calculate the y intercept
            double b = -1 * m * (double)p.X + (double)p.Y;

            //Check if each point in the polygon is a lower tangent
            foreach (var point in polygon)
            {
                if (!PolygonManipulation.Equals(point, p) && !PolygonManipulation.Equals(point, q))
                    if ((m * (double)point.X + b - (double)point.Y) > 0)
                        return false;
            }
            return true;
        }
        /// <summary>
        /// Finds the quickest path avoiding the polygons given a start and end point
        /// Excludes start and end from the path
        /// Need to check for collisions with other polygons
        /// </summary>
        private IEnumerable<Point2D> FindQuickestPathMultiplePolygons(Point2D start, Point2D end)
        {
            //Maps a path to the polygon it avoids
            var paths = new Dictionary<List<Point2D>, List<Point2D>>();

            foreach (var polygon in Polygons)
            {
                //Calcualte convex hull with start and end point and polygon
                var newPolygon = new List<Point2D>();
                newPolygon.Add(start);
                newPolygon.AddRange(polygon);
                newPolygon.Add(end);

                var convexHull = ConvexHull.Solve(newPolygon);

                if (convexHull.Contains(start) && convexHull.Contains(end))
                {
                    var path = ConvexHull.GetMinimumPolygonChain(convexHull, start, end);
                    paths.Add(path, polygon);
                }
            }

            //Get all paths with more than two points
            var correctPaths = paths.Keys.Where(p => p.Count >= 2).ToList();

            if (correctPaths.Count == 0)
                //All paths go straight from the start to end
                //Therefore no obstacles are in the way
                return (new Point2D[] { start, end }).ToList();

            if (correctPaths.Count == 1)
                //Only one path has an obstacle in the way
                //So only one obstacle is between start and end
                return correctPaths.First();

            //Merge all the paths which are blocked by polygons together
            return MergePaths(correctPaths);
        }
 /// <summary>
 /// Gets the squared distance between two points
 /// </summary>
 public static float GetDistanceSquared(Point2D a, Point2DF b)
 {
     return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y);
 }
 /// <summary>
 /// Gets the Manhattan distance between two points
 /// </summary>
 public static float GetDistance(Point2D a, Point2DF b)
 {
     return (float)Math.Sqrt(GetDistanceSquared(a, b));
 }
 /// <summary>
 /// Whether three points make a right turn
 /// </summary>
 private static Boolean NoRightTurn(Point2D a, Point2D b, Point2D c)
 {
     return CrossProduct(a, b, c) <= 0;
 }
 /// <summary>
 /// Calculates the cross product of 3 2d points
 /// </summary>
 public static Int32 CrossProduct(Point2D a, Point2D b, Point2D c)
 {
     return (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y)*(c.X - a.X);
 }
        /// <summary>
        /// Generates a random polygon
        /// </summary>
        public static List<Point2D> GenerateRandomPolygon(Int32 maxPointNumber, Int32 maxX, Int32 maxY, Int32 offsetX = 0, Int32 offsetY = 0)
        {
            //Create points
            List<Point2D> pointList = new List<Point2D>();
            for (int p = 0; p < maxPointNumber; p++)
            {
                Point2D newPoint = new Point2D(random.Next(maxX) + offsetX, random.Next(maxY) + offsetY);

                if (!PolygonManipulation.Contains(pointList, newPoint))
                    pointList.Add(newPoint);
            }
            pointList = pointList.Distinct().ToList();

            return pointList;
        }
        /// <summary>
        /// Polygon count must be between 1 and 4
        /// </summary>
        public static Map GenerateMultipleObstacleMap(Int32 polygonNumber, Int32 maxPointNumber, Int32 maxX, Int32 maxY)
        {
            if (polygonNumber == 1)
                return GenerateSingleObstacleMap(maxPointNumber, maxX, maxY);

            if (polygonNumber > 4)
                polygonNumber = 4;

            List<List<Point2D>> polygons = new List<List<Point2D>>();
            Point2D start = null;
            Point2D mid = null;
            Point2D end = null;

            //Spread the polygons out based in the number
            if (polygonNumber == 2)
            {
                //Arrange side by side
                /* ##### #####
                 * #   # #   #
                 * ##### #####
                */
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, 2, 2));
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, maxX + 3, 2));
                Int32 maxHeight = GetMaximumHeight(polygons);
                start = new Point2D(0, random.Next(maxHeight));
                mid = new Point2D(maxX + 2 + random.Next(1), random.Next(maxHeight));
                end = new Point2D(2 * maxX + 3, random.Next(maxHeight));
            }
            else if (polygonNumber == 3)
            {
                //Arrange in tri-shape
                /*   #####
                 *   #   #
                 *   #####
                 *
                 * ##### #####
                 * #   # #   #
                 * ##### #####
                */
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, maxX / 2 + 2, 2));
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, 2, maxY + 3));
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, maxX + 3, maxY + 3));
                Int32 maxHeight = GetMaximumHeight(polygons);
                start = new Point2D(0, random.Next(maxHeight));
                mid = new Point2D(maxX + 2 + random.Next(1), random.Next(maxHeight / 2) + maxHeight / 2 + 2);
                end = new Point2D(2 * maxX + 3, random.Next(maxHeight));
            }
            else if (polygonNumber == 4)
            {
                //Arrange in sqaure
                /* ##### #####
                 * #   # #   #
                 * ##### #####
                 *
                 * ##### #####
                 * #   # #   #
                 * ##### #####
                */
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, 2, 2));
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, maxX + 3, 2));
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, 2, maxY + 3));
                polygons.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, maxX + 3, maxY + 3));
                Int32 maxHeight = GetMaximumHeight(polygons);
                start = new Point2D(0, random.Next(maxHeight));
                mid = new Point2D(maxX + 2 + random.Next(1), random.Next(maxHeight));
                end = new Point2D(2 * maxX + 3, random.Next(maxHeight));
            }

            return new Map(polygons, start, end) { Mid = mid };
        }
        /// <summary>
        /// Returns a map which is a single obstacle test
        /// </summary>
        public static Map GenerateSingleObstacleMap(Int32 maxPointNumber, Int32 maxX, Int32 maxY)
        {
            //Generate the map

            var polygon = new List<List<Point2D>>();
            polygon.Add(GenerateRandomPolygon(maxPointNumber, maxX, maxY, 2, 2));

            //Insert polygon into generated Map
            Int32 polygonWidth = polygon.First().Max(p => p.X);
            Int32 polygonHeight = polygon.First().Max(p => p.Y);
            Int32 mapWidth = polygonWidth + 2;
            Int32 mapHeight = polygonHeight + 2;

            Point2D start = new Point2D(random.Next(2), Convert.ToInt32((random.Next(mapHeight) - 0.5 * mapHeight) + (float)mapHeight / 2));
            Point2D end = new Point2D(mapWidth - random.Next(2), mapHeight - start.Y);
            return new Map(polygon, start, end);
        }
 /// <summary>
 /// Finds the quickest path avoiding the polygon given a start and end point
 /// Excludes start and end from the path
 /// </summary>
 private IEnumerable<Point2D> FindQuickestPathSinglePolygon(Point2D start, Point2D end)
 {
     return FindQuickestPathSpecifiedPolygon(Polygons.First(), start, end);
 }
 /// <summary>
 /// Checks whether two given points are equal
 /// </summary>
 public static Boolean Equals(Point2D a, Point2D b)
 {
     return (a.X == b.X) && (a.Y == b.Y);
 }
        private static IEnumerable<Point2D> FindQuickestPathSpecifiedPolygon(IEnumerable<Point2D> polygon, Point2D start, Point2D end)
        {
            //Calcualte convex hull with start and end point and polygon
            var newPolygon = new List<Point2D>();
            newPolygon.Add(start);
            newPolygon.AddRange(polygon);
            newPolygon.Add(end);

            newPolygon = ConvexHull.GetMinimumPolygonChain(ConvexHull.Solve(newPolygon), start, end);

            //If we haven't found a path yet or this path is the shortest
            newPolygon.Remove(start);
            newPolygon.Remove(end);
            return newPolygon;
        }
 /// <summary>
 /// Gets a point previous in the list - usually clockwise direction
 /// </summary>
 public static Point2D GetPreviousPoint(List<Point2D> polygon, Point2D currentPoint)
 {
     var index = PolygonManipulation.IndexOf(polygon, currentPoint);
     if (index == 0)
         return polygon[polygon.Count - 1];
     else
         return polygon[index-1];
 }
 /// <summary>
 /// Calculates the gradient between two points
 /// </summary>
 private static float CalculateGradient(Point2D a, Point2D b)
 {
     float rise = (float)b.Y - (float)a.Y;
     float run = (float)b.X - (float)a.X;
     if (run == 0)
         return 999999;
     else if (rise == 0)
         //Have to return an abnormal value here, else if m1.run = 0 and m2.rise = 0
         //Apparentally the gradients are equal
         return 888888;
     else
         return rise / run;
 }
 /// <summary>
 /// Value equivalent of .IndexOf
 /// </summary>
 public static Int32 IndexOf(List<Point2D> polygon, Point2D p)
 {
     for (int i = 0; i < polygon.Count; i++)
     {
         if (polygon[i].X == p.X && polygon[i].Y == p.Y)
             return i;
     }
     return -1;
 }