Как отсортировать координаты с плавающей запятой без исключения координат?

У меня есть список координат, которые должны образовывать края пути, которые мне нужно отсортировать. Я пытаюсь использовать сканирование Грэма и пробовал несколько образцов из:

  1. GrhamsScan.cs
  2. ConvexHull.cs
  3. Алгоритм ConvexHull

Эти коды не работают для нескольких тестовых случаев, которые у меня есть, и я не уверен, что не так.

Редактировать:

Эти координаты должны быть частью касательных линий. Если координаты не отсортированы, касательные идут случайно вместо правильного пути, который может быть прямым или изогнутым по мере развития шторма.

Я создаю касательные к кругам, образующим путь бури. Пример можно увидеть здесь: введите здесь описание изображения

Редактировать#02

Правильная форма (не обращайте внимания на полукруг в конце) должна выглядеть так, если точки, образующие касательные линии, расположены правильно.

введите здесь описание изображения

Тестовые случаи:

Тестовый пример № 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}

Тестовый пример № 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}

Тестовые случаи#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}

Пожалуйста, укажите мне ресурс, алгоритм или код, где я могу найти надежный алгоритм сортировки для координат с плавающей запятой и не устранять точки при этом. Скорость не в приоритете, точность в приоритете.

Буду признателен за все материалы. Спасибо


person Steve Johnson    schedule 13.01.2015    source источник
comment
Не могли бы вы показать нам график того, как выглядят эти данные? Кроме того, форма выпуклая?   -  person Chris    schedule 13.01.2015
comment
Добавлен скриншот и некоторые важные детали.   -  person Steve Johnson    schedule 13.01.2015
comment
В каждом наборе данных есть одна или две дорожки?   -  person Chris    schedule 13.01.2015
comment
Каждый из приведенных выше наборов данных (тесткейсов) представляет собой отдельную дорожку. Если вы рассматриваете круги, движущиеся слева направо, то верхние касательные к тем кругам, представленным тестовыми наборами № 1, нижние касательные к тем кругам, представленным тестовыми наборами № 2, и координаты центра кругов, представленных тестовыми наборами № 3   -  person Steve Johnson    schedule 13.01.2015
comment
В этом случае, предполагая, что дорожки не зацикливаются сами на себе, я бы предположил, что просто переход от точки к точке, выбирая ближайшую, добьется цели.   -  person Chris    schedule 13.01.2015
comment
Я действительно не думал об этом, лолз. Я должен был сначала попробовать. Спасибо за отзыв!   -  person Steve Johnson    schedule 13.01.2015
comment
Я не понимаю, какое отношение проблема, которую вы решаете, имеет к выпуклым оболочкам.   -  person tmyklebu    schedule 14.01.2015
comment
Я просто хотел отсортировать координаты, и это было то, что я нашел, когда пытался погуглить. Если точки не отсортированы, касательные, в свою очередь, выглядят так, как показано на первой диаграмме. Если есть какой-либо алгоритм, который может помочь мне отсортировать точки в правильном порядке, чтобы сформированный путь был правильным.   -  person Steve Johnson    schedule 14.01.2015
comment
Куда пропала эта третья координата по имени время, которая могла бы значительно помочь вам разобраться с двумя другими?   -  person aka.nice    schedule 14.01.2015
comment
Это хорошее предложение, я только что попробовал это и создал третью структуру данных со свойством Created datetime, установленным на DateTime.Now. Но процедура создания точек, вероятно, добавляет точки таким образом, что Дата создания больше не остается подходящим кандидатом для сортировки точек. :( Работа над пользовательской сортировкой, как предложил @Chris.   -  person Steve Johnson    schedule 14.01.2015


Ответы (2)


К сожалению, вы потеряли градации времени, которые когда-то существовали в метеорологических данных, и точки приходят к вам не по порядку
Итак, вы хотите реконструировать путь из набора точек. Как только это будет сделано, этот ответ учитывает, что создание оболочки не должно быть проблемой.

Если у вас есть N очков, есть N! возможные заказы.

Среди этих порядков вам нужно будет выбрать тот, который максимизирует вероятность представления траектории шторма.

Наивным критерием может быть минимизация длины пути. Более продвинутый может принять во внимание, что скорость шторма не может измениться мгновенно, поэтому более или менее штрафуйте ускорение. Или производная от ускорения... Но для этого может потребоваться дополнительная гипотеза о регулярности дискретизации по времени.

Во всех случаях вам придется внедрить модель того, как должна выглядеть траектория шторма, и связать какую-то оценку (вероятность) с различными гипотезами (возможными траекториями).

Если ваш набор точек действительно крошечный, вы не собираетесь перебирать всю комбинаторику. Вместо этого вы восстановите траекторию, начиная с одной произвольной точки. Затем вы попытаетесь расширить траекторию с одной или с другой стороны, итеративно добавляя точку. Вы выберете априори сокращенный набор наиболее вероятных кандидатов (например, ближайшую точку к последним точкам реконструированной траектории на данный момент или ближайшую к экстраполяции уже реконструированной траектории с гипотезой постоянной скорости или постоянного ускорения...).

Тривиальный алгоритм будет выбирать наиболее вероятного кандидата локально на каждом шаге.

Более серьезный алгоритм будет реконструировать несколько возможных траекторий параллельно, а наименее вероятные исключать по некоторым вероятностным правилам отбора.

Я вижу эту категорию проблем, тесно связанных с отслеживанием целей с помощью RADAR, поэтому вы могли бы ознакомиться с такой литературой и, в частности, заинтересоваться вероятностью байесовского ансамбля. Надеюсь, ты любишь математику.

person aka.nice    schedule 13.01.2015

Это то, что я написал, и это сработало для всех случаев, наконец. Позвольте мне признать, что его можно улучшить для повышения производительности, и это может быть быстрый и грязный способ, но это то, что я использую в данный момент.

P.S: Я также признаю, что «Выпуклый корпус» или «Сканирование Грэма» никогда не были тем, что мне было нужно, и не имеют ничего общего с тем, что требовалось. Так что технически это была ошибка на моей стороне. Мне нужно было сначала отсортировать точки с ближайшей точкой, как предложил @Chris.

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;
    }

}
person Steve Johnson    schedule 26.01.2015