Search code examples
c#sortingfloating-pointcoordinatesgrahams-scan

How to sort floating point coordinates with no elimination of coordinates?


I have a list of coordinates that should form a edges of a path which i need to get sorted. I am trying to use Grahams scan and have tried a couple of samples from:

  1. GrhamsScan.cs
  2. ConvexHull.cs
  3. ConvexHull Algo

These codes fails for several test cases that I have and I am not sure whats wrong.

Edit:

These coordinates are supposed to be part of tangent lines. If the coordinates are not in sorted, the tangents go hap hazard instead of a proper path that could be straight or curved as the storm progresses.

I am creating tangents to circles that form a storm's path. An example can be seen here: enter image description here

Edit#02

A correct shape (ignore the semi circle at the end) should look like this if the points forming the tangent lines are in order.

enter image description here

Testcases:

Test case#01

[0]: {X = 11.581625 Y = -110.983437}
[1]: {X = 11.1816254 Y = -108.983437}
[2]: {X = 11.88781 Y = -113.115852}
[3]: {X = 11.587204 Y = -111.015938}
[4]: {X = 12.1884336 Y = -115.215759}
[5]: {X = 11.88781 Y = -113.115845}
[6]: {X = 12.5794077 Y = -116.863365}
[7]: {X = 12.1794081 Y = -115.163368}
[8]: {X = 13.0785418 Y = -118.855026}
[9]: {X = 12.5785418 Y = -116.855026}
[10]: {X = 13.534234 Y = -119.732178}
[11]: {X = 13.034234 Y = -118.732178}

Test case#02

   [0]: {X = 10.4182844 Y = -111.21611}
[1]: {X = 10.0190592 Y = -109.21595}
[2]: {X = 10.712142 Y = -113.283806}
[3]: {X = 10.4127483 Y = -111.183716}
[4]: {X = 11.0115175 Y = -115.383896}
[5]: {X = 10.712141 Y = -113.2838}
[6]: {X = 11.4204569 Y = -117.136063}
[7]: {X = 11.0213022 Y = -115.435867}
[8]: {X = 11.9213 Y = -119.144341}
[9]: {X = 11.4223957 Y = -117.144066}
[10]: {X = 12.4652023 Y = -120.266693}
[11]: {X = 11.9662571 Y = -119.266167}

Testcases#03

   [0]: {X = 10.6 Y = -109.1}
    [1]: {X = 11.0 Y = -111.1}
    [2]: {X = 11.3 Y = -113.2}
    [3]: {X = 11.6 Y = -115.3}
    [4]: {X = 12.0 Y = -117.0}
    [5]: {X = 12.5 Y = -119.0}
    [6]: {X = 13.0 Y = -120.0}

Kindly guide me a resource, algorithm or code where i can find a reliable sorting algorithm for floating point coordinates and does not eliminate points while doing that. Speed is not priority, accuracy is a priority.

I would appreciate all inputs. Thanks


Solution

  • This is what i wrote and it worked for all the cases finally. Let me admit it can be improved for performance and this might be a quick and dirty way but this what i am using at the moment.

    P.S: I also admit that "Convex Hull" or "Graham Scan" was never what i needed and has nothing to do with what was required. So technically it was a fault on my side. I needed to sort points with the closest point first as @Chris had suggested.

    public class ConvexHull6
    {
    
        public class PointDistance
        {
            public double X { get; set; }
            public double Y { get; set; }
            public double distance { get; set; }
            public int index { get; set; }
        }
        public class StormPointsDistance
        {
            public StormPoints stormPoints { get; set; }
            public Double distance { get; set; }
        }
        public static List<PointD> ReOrderPointsByClosestPointFirst(List<PointD> points, bool islower = false)
        {
            var minX = points.Min(p => p.X);
            var maxX = points.Max(p => p.X);
            var minP = points.First(p => p.X == minX);
            var maxP = points.First(p => p.X == maxX);
    
            minP = points.First(p => p.X == minX);
            maxP = points.First(p => p.X == maxX);
    
            var pB = points.ToList();
            var len = pB.Count();
            //Temporary lists to hold data structures and points when performing the points sorting..
            var pDist = new List<PointDistance>();
            var distances = new List<Double>();
            int index = 0;
            //Sorted list to hold final points...
            var sorted = new List<PointD>();
            for (int i = 0; i < len; i++)
            {
                if (i > 0)
                {
                    //Minimum point or "Point of Reference for comparison" is now the last point in the sorted list.
                    minP = sorted[sorted.Count() - 1];
                    //Clear the temporary lists used...
                    pDist.Clear(); distances.Clear();
                }
                for (int j = 0; j < len - i; j++)
                {
                    var distance = Math.Sqrt(Math.Pow(pB[j].X - minP.X, 2) + Math.Pow(pB[j].Y - minP.Y, 2));
                    pDist.Add(new PointDistance() { X = pB[j].X, Y = pB[j].Y, distance = distance, index = index });
                    distances.Add(distance);
                }
                //Order the data structure
                pDist = pDist.OrderBy(m => m.distance).ToList();
                //Convert to points list for use
                pB = pDist.Select(m => new PointD(m.X, m.Y)).ToList();
                //Get the first point and put it in the sorted list
                sorted.Add(pB[0]);
                //Remove the point from the pb list so that it is not considered again
                pB.RemoveAt(0);
    
                index++;
            }
            pDist = pDist.OrderBy(m => m.distance).ToList();
            distances = pDist.Select(m => m.distance).ToList();
    
            //The new code...
            points = sorted.ToList();
    
            //Get the minimum Point again as minP has been overwritten during the loop
            minX = points.Min(p => p.X);
            maxX = points.Max(p => p.X);
            minP = points.First(p => p.X == minX);
            maxP = points.First(p => p.X == maxX);
            //Check if minp does nott match the first point
            if ((minP != points[0] && maxP == points[0]) || (maxP != points[len - 1] && minP == points[len - 1]))
            {
                //Reverse only if the first point of array is not the minimum point
                points.Reverse();
            }
            return points;
        }
    
    }