Сравнение Lat, Long Coordinates

У меня есть список из более чем 15 тысяч координат широты и долготы. Учитывая любые координаты X, Y, какой самый быстрый способ найти самые близкие координаты в списке?

Ответ 1

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

Код для точных алгоритмов для создания диаграммы Voronoi и упорядочения поиска структуры данных слишком велик, чтобы вписаться в это маленькое поле редактирования.:)

@Linor: Это то, что вы сделали бы после создания диаграммы Вороного. Но вместо создания прямоугольной сетки вы можете выбрать разделительные линии, которые точно соответствуют линиям диаграммы Вороного (таким образом, вы получите меньше областей, пересекающих разделительные линии). Если вы рекурсивно разделите свою диаграмму Вороного пополам по лучшей разделительной линии для каждой поддиаграммы, вы можете выполнить поиск по дереву для каждой точки, которую вы хотите найти. Это требует немного работы спереди, но экономит время позже. Каждый поиск будет иметь порядок log N, где N - количество точек. 16 сравнений намного лучше, чем 15 000!

Ответ 2

Я сделал это один раз для веб-сайта. То есть найдите дилера в радиусе 50 миль от вашего почтового индекса. Я использовал большой расчет круга, чтобы найти координаты, которые были в 50 милях к северу, в 50 милях к востоку, в 50 милях к югу и в 50 милях к западу. Это дало мне мин и макс лат и мин и максимум. Затем я сделал запрос на базу данных:

select *
    from dealers
    where latitude  >= minlat
      and latitude  <= maxlat
      and longitude >= minlong
      and longitude <= maxlong

Так как некоторые из этих результатов будут оставаться на расстоянии более 50 миль, я снова использовал формулу большого круга в этом небольшом списке координаты. Затем я распечатал список вместе с расстоянием от цели.

Конечно, если вы хотите найти точки вблизи международной линии дат или полюсов, это не сработает. Но он отлично работает для поисков внутри Северной Америки!

Ответ 3

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

KD-Trees и варианты KD-Trees, похоже, работают очень хорошо, но квадроциклы также будут работать. Качество этих запросов зависит от того, является ли ваш набор из 15 000 точек данных статичным (вы не добавляете множество точек данных в набор ссылок). Mount и Arya работают над Приблизительная Ближайшая Соседняя библиотека проста в использовании и понимании, даже без хорошего заземления в математике. Это также дает вам некоторую гибкость в отношении типов и допусков ваших запросов.

Ответ 4

Скорее зависит от того, сколько раз вы хотите это сделать, и какие ресурсы доступны - если вы выполняете тест один раз, то методы O (log N) хороши. Если вы делаете это тысячу раз на сервере, построение таблицы поиска растровых изображений будет быстрее, либо давая результат напрямую, либо как первый этап. 2 ГБ растрового изображения могут отображать весь мир лат-lon до 32-битного значения при 0,011 градусах (1,2 км на экваторе) и должны вписываться в память. Если вы работаете только в одной стране или можете исключить полюса, вы можете иметь меньшую карту или более высокое разрешение. На 15 000 пунктов у вас, вероятно, гораздо меньше карты. Сначала я оценил ее как первый шаг к тому, чтобы делать латинский поиск в почтовом индексе, что требует более высокого разрешения. В зависимости от требований вы используете отображаемое значение для непосредственного указания результата или для краткого списка кандидатов (что позволит уменьшить карту, но требует большей последующей обработки - вы больше не находитесь в области поиска O (1)).

Ответ 5

Вы не указали, что вы имели в виду быстрее всего. Если вы хотите быстро получить ответ, не написав никакого кода, я бы предоставил фильтр радиуса gpsbabel.

Ответ 6

Основываясь на ваших разъяснениях, я бы использовал геометрическую структуру данных, такую ​​как KD-дерево или R-дерево. MySQL имеет тип данных SPATIAL, который делает это. Другие языки/рамки/базы данных имеют библиотеки для поддержки этого. В принципе, такая структура данных вставляет точки в дереве прямоугольников и ищет дерево с использованием радиуса. Это должно быть достаточно быстро, и я считаю, что это проще, чем строить диаграмму Вороного. Я предполагаю, что есть некоторый порог, выше которого вы предпочли бы добавленную производительность диаграммы Voronoi, чтобы вы были готовы заплатить дополнительную сложность.

Ответ 7

Это можно решить несколькими способами. Я бы сначала применил эту проблему, создав Delaunay сеть, соединяющую ближайшие точки друг с другом. Это можно выполнить с помощью команды v.delaunay в приложении GIS с открытым исходным кодом GRASS. Вы можете выполнить проблему в GRASS, используя один из многочисленных модулей сетевого анализа в GRASS. В качестве альтернативы вы можете использовать свободные пространственные RDBMS PostGIS для выполнения запросов на расстояние. Постоянные запросы PostGIS значительно мощнее, чем в MySQL, поскольку они не ограничены операциями BBOX. Например:

SELECT network_id, ST_Length(geometry) from spatial_table where ST_Length(geometry) < 10;

Поскольку вы используете долготу и широту, вы, вероятно, захотите использовать функции Spheroid-Distance. С пространственным индексом PostGIS очень хорошо масштабируется для больших наборов данных.

Ответ 8

Даже если вы создаете диаграмму voronoi, это все равно означает, что вам нужно сравнить ваши координаты x, y со всеми 15 тысячами созданных областей. Чтобы сделать это проще, первое, что появилось у меня в голове, состояло в том, чтобы создать какую-то сетку над возможными значениями, чтобы вы могли легко разместить координату x/y в одном из полей в сетке, если это то же самое сделанные для списка областей, вы должны быстро сжать возможные кандидаты для сравнения (потому что сетка будет более прямоугольной, возможно, область будет в нескольких положениях сетки).

Ответ 9

Преждевременная оптимизация - это корень всего зла.

15K координаты не так уж много. Почему бы не перебрать по координатам 15K и посмотреть, действительно ли это проблема производительности? Вы могли бы сэкономить много работы и, возможно, никогда не становитесь слишком медленными, чтобы даже заметить.

Ответ 10

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

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

Ответ 11

Спасибо всем за ответы.

@Tom, @Chris Upchurch: координаты довольно близки друг к другу, и они находятся в относительно небольшой области около 800 кв. км. Наверное, я могу предположить, что поверхность плоская. Мне нужно обрабатывать запросы снова и снова, и ответ должен быть достаточно быстрым для большего количества веб-ресурсов.

Ответ 12

Сетка очень простая и очень быстрая. Это в основном просто 2D-массив списков. Каждая запись массива представляет точки, которые попадают внутрь ячейки сетки. Очень легко установить сетку:

for each point p
  get cell that contains p
  add point to that cell list

и это очень легко посмотреть на вещи:

given a query point p
  get cell that contains p
  check points in that cell (and its 8 neighbors), against query point p

Алехо

Ответ 13

Просто чтобы быть contrairian, вы имеете в виду близкое расстояние или (вождение) время? В городской местности я с удовольствием проезжаю 5 миль (5 минут) на шоссе, чем 4 мили (20 минут останавливаются и уходят) в другом направлении.

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