c# - через - построить матрицу весов и найти кратчайшие расстояния между всеми парами вершин заданного графа
Каков самый быстрый способ найти кратчайшее декартовое расстояние между двумя полигонами (9)
У меня есть 1 красный многоугольник и 50 случайно размещенных синих полигонов - они расположены в географическом 2D пространстве . Каков самый быстрый / быстрый алгоритм для нахождения кратчайшего расстояния между красным многоугольником и его ближайшим синим полигоном?
Имейте в виду, что это не простой случай, когда точки, составляющие вершины многоугольника, являются значениями для проверки расстояния, поскольку они могут не обязательно быть ближайшими точками.
Поэтому в конце - ответ должен вернуть ближайший синий полигон к единственному красному.
Это сложнее, чем кажется!
Вы можете начать с сравнения расстояния между ограничивающими прямоугольниками. Тестирование расстояния между прямоугольниками проще, чем проверка расстояния между многоугольниками, и вы можете немедленно устранить любые многоугольники, которые больше, чем ближайший_ид + его_диагональный (возможно, вы можете уточнить это еще больше). Затем вы можете проверить оставшиеся полигоны, чтобы найти ближайший многоугольник.
Существуют алгоритмы поиска близости многоугольника - я уверен, что в Википедии есть хороший обзор. Если я правильно помню, те, которые допускают только выпуклые многоугольники, существенно быстрее.
Наивный подход заключается в том, чтобы найти расстояние между красными и 50 синими объектами - так что вы смотрите на 50 трехмерных расчетов Пифагора + сортировку, чтобы найти ответ. Однако это действительно помогло бы найти расстояние между центральными точками.
Если вам нужны произвольные полигоны, возможно, самое лучшее - это решение для трассировки лучей, которое излучает лучи с поверхности красного многоугольника относительно нормали и сообщает, когда попадает другой полигон.
Гибрид может работать - мы могли бы найти расстояние от центральных точек, предполагая, что у нас есть некоторое представление об относительном размере синих многоугольников, мы можем отбирать набор результатов ближе всего к ним, а затем использовать raytracing, чтобы сузить действительно ближайший многоугольник (ы).
Я сомневаюсь, что есть лучшее решение, чем вычисление расстояния между красным и каждым синим и сортировка по длине.
Что касается сортировки, обычно QuickSort трудно превзойти по производительности (оптимизированный, который отсекает рекурсию, если размер меньше 7 пунктов и переключается на что-то вроде InsertionSort, может быть, ShellSort).
Таким образом, я думаю, вопрос заключается в том, как быстро вычислить расстояние между двумя полигонами, ведь вам нужно сделать это вычисление 50 раз.
Следующий подход будет работать и для 3D, но, вероятно, не самый быстрый:
Вопрос в том, готовы ли вы торговать с точностью до скорости? Например, вы можете упаковать все полигоны в ограничивающие прямоугольники, где стороны ящиков параллельны осям системы координат. 3D-игры используют этот подход довольно часто. Для этого вам нужно найти максимальное и минимальное значения для каждой координаты (x, y, z) для построения виртуального ограничивающего прямоугольника. Вычисление расстояний этих ограничивающих прямоугольников - вот довольно тривиальная задача.
Вот пример изображения более сложных ограничивающих прямоугольников, которые не параллельны осям системы координат:
Однако это делает расчет расстояний менее тривиальным. Он используется для обнаружения столкновений, так как вам не нужно знать расстояние для этого, вам нужно только знать, находится ли один край одного ограничивающего прямоугольника внутри другого ограничивающего прямоугольника.
На следующем рисунке показан выровненный по осям ограничивающий прямоугольник:
OOB более точны, AABB быстрее. Возможно, вы хотели бы прочитать эту статью:
Это всегда предполагает, что вы готовы торговать точностью для скорости. Если точность важнее скорости, вам может потребоваться более совершенная техника.
Возможно, вы захотите взглянуть на Вороного Каллинга. Бумага и видео здесь:
Для многоугольных форм с разумным количеством граничных точек, например, в ГИС или приложении для игр, было бы легче выполнить серию тестов.
Для каждой вершины в красном многоугольнике вычислите расстояние до каждой вершины в синих многоугольниках и найдите ближайший (подскажите, сравните расстояние ^ 2, чтобы вам не понадобилось sqrt ()) Найдите ближайший, затем проверьте вершину с каждой стороны найденной красной и синей вершины, чтобы решить, какие сегменты линии ближе всего, а затем найти ближайший подход между двумя сегментами линии.
Как упоминалось выше, использование ограничивающих областей (ящиков, кругов) может позволить вам отказаться от некоторых полигонально-многоугольных взаимодействий. Для этого существует несколько стратегий, например
- Выберите любой синий полигон и найдите расстояние от красного. Теперь выберите любой другой полигон. Если минимальное расстояние между ограничивающими областями больше, чем уже найденное расстояние, вы можете игнорировать этот многоугольник. Продолжить для всех полигонов.
- Найдите минимальное расстояние между центрами и красным многоугольником. Сортируйте расстояния и сначала рассмотрите наименьшее расстояние. Вычислите фактическое минимальное расстояние и продолжайте просматривать отсортированный список до тех пор, пока максимальное расстояние между многоугольниками не будет больше минимального расстояния, найденного до сих пор.
Ваш выбор кругов / выровненных по оси блоков или ориентированных ящиков может оказать большое влияние на производительность алгоритма, в зависимости от фактического расположения входных многоугольников.
Надо убежать на похороны через секунду, но если вы разбиваете свои полигоны на выпуклые подполисы, вы можете сделать некоторые оптимизации. Вы можете выполнять двоичные поиски на каждом поли, чтобы найти ближайшую вершину, а затем я считаю, что ближайшей точкой должна быть либо эта вершина, либо соседний край. Это означает, что вы должны иметь возможность сделать это в log(log m * n) где m - среднее число вершин на поли, а n - количество полисов. Это своего рода хастинг, так что это может быть неправильно. При желании вы получите более подробную информацию.
Возможно, вы сможете уменьшить проблему, а затем выполнить интенсивный поиск на небольшом наборе.
Сначала обработайте каждый полигон, найдя:
- Центр полигона
- Максимальный радиус полигона (т. Е. Точка на краю / поверхности / вершине многоугольника, наиболее удаленного от заданного центра)
Теперь вы можете собрать, скажем, 5-10 ближайших полигонов к красному (найдите центр расстояния до центра, вычтите радиус, отсортируйте список и возьмите верхнюю часть 5), а затем выполните гораздо более исчерпывающую процедуру.