Получите многоугольники, близкие к широте и долготе в MySQL

Кто-нибудь знает способ получить все полигоны в базе данных MySQL на заданном расстоянии от точки? Фактическое расстояние не так важно, поскольку оно рассчитывается для каждого найденного многоугольника позже, но было бы огромной оптимизацией просто выполнить этот расчет для многоугольников, которые находятся «близко».

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

Какие-либо предложения?


person Gren    schedule 14.12.2009    source источник


Ответы (3)


Медленная версия (без пространственных индексов):

SELECT  *
FROM    mytable
WHERE   MBRIntersects(mypolygon, LineString(Point(@X - @distance, @Y - @distance), Point(@X + @distance, @Y + @distance))

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

Затем создайте SPATIAL INDEX в поле, содержащем координаты вершин, и просто выполните этот запрос:

SELECT  DISTINCT polygon_id
FROM    vertices
WHERE   MBRContains(vertex, LineString(Point(@X - @distance, @Y - @distance), Point(@X + @distance, @Y + @distance))

Все будет намного проще, если вы сохраните в базе данных UTM координаты, а не широту и долготу.

person Quassnoi    schedule 14.12.2009
comment
Огромное спасибо! Для тех, у кого похожие проблемы: в итоге я использовал MBR круга, нарисованного вокруг интересующей точки, и получил все полигоны, чьи MBR пересекали MBR окружностей. - person Gren; 21.12.2009
comment
Вы можете сказать мне, что означает distance? В милях, км или метрах? - person Shaishav Jogani; 27.07.2017
comment
@ShaishavJogani: @distance - это переменная, которая содержит расстояние, в пределах которого вы ищите. Это могут быть мили, километры, метры или любые другие единицы измерения расстояния при условии, что вы храните координаты в тех же единицах. - person Quassnoi; 27.07.2017

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

Первая идея, которая приходит мне в голову, - использовать сетку, назначить каждую точку квадрату и выбрать квадрат, в котором находится точка, и те, что вокруг него. Если мы говорим о бесконечных сетках, тогда используйте хеш-значение квадрата, это даст вам больше очков, чем необходимо (там, где у вас есть коллизии), но все равно уменьшит количество на кучу. Конечно, это не сразу применимо к полигонам, это просто мозговой штурм. Возможный подход, который может привести к слишком большому количеству коллизий, заключался бы в том, чтобы объединить все хешированные значения по ИЛИ и выбрать все записи, в которых хэши с AND с этим значением не равны нулю (не уверен, возможно ли это в MySQL), вы можете использовать большой количество бит хотя.

Проблема с этим подходом заключается в том, что если мы говорим о сферических координатах (широта, как правило, long), это сингулярности, поскольку «квадраты» сетки сужаются по мере приближения к полюсам. Самый простой способ - не ставить точки близко к полюсам ... :)

person falstro    schedule 14.12.2009

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

person KernelJ    schedule 14.12.2009