Получить ближайшую геометрию в пространстве, используя пространственный индекс - PullRequest
1 голос
/ 15 октября 2011

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

Я пробовал несколько способов, но у меня всегда была проблема с границей пространственного индекса .

Как это:

ВЫБРАТЬ *, Расстояние (GeomFromText ('POINT (19.02658 47.51574)'), mo_utak_polyline.Geometry) как расстояние ОТ mo_utak_polyline ГДЕ ВХОД (ВЫБРАТЬ pkid ОТ idx_mo_utak_polyline_Geometry <40 макс. 47.52824) И расстояние <= 0.0025) ЗАКАЗАТЬ по расстоянию </p>

Или это:

SELECT *, Пересекается (GeomFromText ('POINT (19.02658 47.51574)'), megyehatar_region.Geometry) как пересекается с megyehatar_region ГДЕ ВХОДЯЩИЙ (ВЫБИРАЙТЕ pkid ИЗ idx_megyehatar_region_Gemin.51565 x 408> 406> 406> 406> 406> 406> 0,05> 405> x65> x080> x0.865 x 408 x 680 x 680 x 568 x 568 x 568 x 568 x080 x 403 x080865 x065865 x658 x65865 x160x1602656656656000 макс. Геометрия: *1012* SELECT *, пересекается (GeomFromText ('POINT (19.02658 47.51574)'), megyehatar_region.Geometry) как пересекается с (выберите SELECT 52.51574) И пересекается = 1

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

Какой, по вашему мнению, лучший способ сделать это?

Как изменить эту часть запроса

ВЫБРАТЬ pkid ОТ idx_mo_utak_polyline_Geometry ГДЕ xmin> 19.01408 И xmax <19.03908 И ymin> 47.50324 И ymax <47.52824) </p>

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

Заранее спасибо!

Ответы [ 4 ]

0 голосов
/ 07 февраля 2017

В SpatiaLite версии 4.4 или выше теперь есть индекс KNN (K-Nearest Neighbours), который работает довольно хорошо. Недавно я написал запрос, который для каждой из примерно 500 точек искал ближайшую линейную строку из 5 миллионов записей строк. Используя более новый метод VirtualSpatialIndex, упомянутый KaeptnHaddock, запрос выполнялся в течение примерно 3 минут. С новым индексом KNN запрос занял менее 20 секунд. Вот мой запрос KNN:

select k.* from knn k, points p
WHERE f_table_name = 'linestrings' 
AND ref_geometry = p.geometry
AND max_items = 1;
0 голосов
/ 04 сентября 2013

Сделайте первый запрос к индексу, чем вы можете сделать пересекает и, что еще лучше, расстояние == 0 догеометрии, которые вы получили из индексированного запроса:

Координаты вашей точки - X, Y

    SELECT * FROM table 
        WHERE pk_uid IN (SELECT pkid FROM idx_table_geometry 
                         WHERE xmin < X AND ymin < Y AND xmax > X AND ymax > Y) 
              AND distance( makepoint(X,Y), geometry ) == 0
0 голосов
/ 28 июля 2015

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

Я не уверен, насколько хорошо структурирован этот код и как быстро он будет вычисляться для большого набора данных (мойтест-набор небольшой).

Я очень заинтересован в получении обратной связи, если вы видите улучшение в этом запросе (мой sql очень ржавый - это было давно ...)

select * 
from pointlayer as p
left join linelayer as l on
    Distance(p.geometry, l.geometry) in (
       select MIN(Distance(p.geometry, geometry)) 
       from linelayer
       where pk in (
           select rowid
           from SpatialIndex
           where f_table_name = 'linelayer'
           and search_frame = BuildCircleMbr(X(b.geometry), Y(b.geometry),25))
)
0 голосов
/ 13 февраля 2012

Как насчет следующего:

SELECT count(*) FROM idx_mo_utak_polyline_Geometry WHERE 
MBRContains(BuildMBR('19.01408','47.50324' , '19.03908', '47.52824'), BuildMBR(xmin,ymin , xmax, ymax)) OR
MBRIntersects(BuildMBR('19.01408','47.50324' , '19.03908', '47.52824'), BuildMBR(xmin,ymin , xmax, ymax)) 
...