Визначення перехресть доріг за допомогою 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?

Відповіді:


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)
;

Лише зауваження, згрупування за геометрією призводить до групування по коробці геометрії, а не до самої геометрії. Це не має значення при роботі з пунктами. Ну, майже. Bboxes має меншу точність, ніж сама точка, яка теоретично може призвести до групування двох точок разом, які не є тотожними.
Nicklas Avén

Дякую @ NicklasAvén Наскільки точне порівняння Bbox? Я б очікував, що цього буде достатньо для цього випадку використання.
underdark

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) (Принаймні, у моїй системі, я щойно спробував. Він групує точки до точок разом). Ця різниця між коробкою та реальною геометрією вже деякий час є дискусією у списку розробників.
Nicklas Avén

Дивіться запропоновані модифікації @AlexOs gis.stackexchange.com/a/151277/3195
Martin F

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;

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

HTH

Ніклас


Привіт @Nicklas, я не в змозі змусити це запустити. Дві внутрішні пропозиції добре працюють; чи слід замінювати distinct_crosspoints ,roadsім'я таблиці ( roads_test)? Я це спробував, але потім отримав помилку щодо geomнеоднозначності.
djq

1
@celenius, Вибачте, що я забув групову пропозицію. Я також бачу, що вам не потрібно ставити чітко на додатковий рівень. Ви можете просто поставити його на перехрестя безпосередньо. Зауважте, що Distinct має таку саму поведінку, як і група, згідно з обговоренням у відповіді недоліків.
Nicklas Avén

Я додав distct_crosspoints.geom до відповіді 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), це нам потрібна точка перетину. Але лінія В також перетинає лінію А в тій же точці. Але нам ця точка не потрібна двічі. Ось чому я використовую a.gid < b.gid замість цьогоa.gid != b.gid

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.