Определение пересечения дорог с помощью PostGIS

17

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

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

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

CREATE TABLE test_points as
SELECT      
    ST_Intersection(a.geom, b.geom),
    a.gid
FROM
    roads as a,
    roads as b
WHERE
    ST_Touches(a.geom, b.geom);

Если я запускаю это на примере дорог, я получаю следующую сетку точек (дороги показаны для иллюстрации):

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

Если я осматриваю одну из точек, я вижу, что есть много точек, наложенных друг на друга:

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

GID здесь - это идентификатор дороги, но я не понимаю, почему есть много точек. Я могу понять, что 4 балла подсчитываются за центральное пересечение дорог, но здесь перечислено 12 баллов. Есть ли лучший способ выполнить этот расчет в PostGIS?

djq
источник

Ответы:

21

Если вы группируете, вы должны получать только уникальные очки.

CREATE TABLE test_points as
SELECT      
    ST_Intersection(a.geom, b.geom),
    Count(Distinct a.gid)
FROM
    roads as a,
    roads as b
WHERE
    ST_Touches(a.geom, b.geom)
    AND a.gid != b.gid
GROUP BY
    ST_Intersection(a.geom, b.geom)
;
Подземье
источник
Просто замечание, группировка по геометрии приводит к группированию по bbox геометрии, а не самой геометрии. Это не имеет значения при работе с точками. Ну, почти. Bbox имеет меньшую точность, чем сама точка, что в теории может привести к группированию двух точек, которые не идентичны.
Никлас Авен
Спасибо @ NicklasAvén. Насколько точное сравнение Bbox? Я ожидаю, что этого будет достаточно для этого варианта использования.
Подземье
1
Спасибо @underdark. Вы знаете, как я могу посчитать количество пересекающихся линий? Я пробовал несколько комбинаций, COUNT()таких как COUNT(ST_Touches(..))и, COUNT(ST_Intersection(..))но это, похоже, не работает, как все значения 12.
djq
@underdark, да, это абсолютно достаточно, поэтому я написал «в теории». Поле находится в float4, а координаты точки имеют двойную точность. Таким образом, окно будет выглядеть одинаково для ST_Point (1.000001,1.0) и ST_Point (1.000002,1.0) (по крайней мере, в моей системе, я только что попробовал. Он группирует точки вместе). Это различие между коробкой и реальной геометрией уже давно стало предметом обсуждения в dev-list.
Никлас Авен
Смотрите @AlexOs предлагаемую модификацию gis.stackexchange.com/a/151277/3195
Мартин Ф
6

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

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

Если ваши дороги идеально соединены друг с другом, и нет никаких дорог, проходящих через перекресток, то вы можете сделать что-то вроде этого (не проверено):
отредактировано с забытым предложением группы (все еще не проверено):

SELECT distinct_crosspoints.geom as crossing, array_agg(roads.gid), count(*) FROM
  (SELECT DISTINCT (geom) geom FROM 
    (SELECT ST_Intersection(a.geom, b.geom) geom 
     FROM roads a, roads b 
     WHERE ST_Intersects(a.geom, b.geom)
    ) all_crosspoints
   ) distinct_crosspoints
   ,roads 
 WHERE ST_Intersects(distinct_crosspoints.geom, roads.geom)
 GROUP BY distinct_crosspoints.geom;

Если дороги не соединены надлежащим образом и / или некоторые дороги проходят через перекресток, это более сложно.

НТН

Никлас

Никлас Авен
источник
Привет @ Никлас, я не могу заставить это работать. Два внутренних предложения работают нормально; я должен заменить имя distinct_crosspoints ,roadsмоей таблицы ( roads_test)? Я попробовал это, но потом получил ошибку geomиз-за неоднозначности.
DJQ
1
@celenius, извините, я забыл предложение группы. Я также вижу, что вам не нужно ставить отличительные на дополнительный уровень. Вы можете просто поставить его на перекрестке напрямую. Обратите внимание, что Distinct ведет себя так же, как и группа, в соответствии с обсуждением в разделе «Подземные ответы»
Никлас Авен
Я добавил в ответ Nicklas и так, чтобы отличный ответ У меня сейчас работает.
Фрэнк
1
 CREATE TABLE test_points as
    SELECT      
        ST_Intersection(a.geom, b.geom),
        Count(Distinct a.gid)
    FROM
        roads as a,
        roads as b
    WHERE
        ST_Touches(a.geom, b.geom)
        AND a.gid < b.gid   /* !!! Changed "!=" for "<"  */
    GROUP BY
        ST_Intersection(a.geom, b.geom)
    ;

Если линия A (id 1) пересекает линию B (id 2), это точка пересечения, в которой мы нуждаемся. Но линия B также пересекает линию A в той же точке. Но нам не нужно это дважды. Вот почему я использую a.gid < b.gid вместоa.gid != b.gid

Алекс Ос
источник