Identyfikacja skrzyżowań drogowych za pomocą PostGIS


17

Próbuję ustalić, gdzie drogi się przecinają, i wskazać punkt na tym skrzyżowaniu, podając liczbę dróg, które tworzą skrzyżowanie.

wprowadź opis zdjęcia tutaj

Zastanawiałem się, czy istnieje jakiś sposób wykorzystania ST_NumPoints, aby to osiągnąć, ale nie do końca wiem, co powinienem zrobić. Zrobiłem to, aby utworzyć tabelę punktów, w których linie przecinają się przy użyciu następującego kodu:

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

Jeśli uruchomię to na próbce dróg, otrzymam następującą siatkę punktów (drogi są pokazane dla ilustracji):

wprowadź opis zdjęcia tutaj

Jeśli sprawdzę jeden z punktów, zauważę, że na sobie ustawionych jest wiele punktów:

wprowadź opis zdjęcia tutaj

GID tutaj jest identyfikatorem drogi, ale nie rozumiem, dlaczego istnieje wiele punktów. Rozumiem, że 4 punkty są liczone za centralne skrzyżowanie dróg, ale jest tutaj 12 punktów. Czy istnieje lepszy sposób na wykonanie tego obliczenia w PostGIS?

Odpowiedzi:


21

Jeśli zgrupujesz, powinieneś zdobyć tylko unikalne punkty.

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

Wystarczy zauważyć, że grupowanie według geometrii powoduje grupowanie według przedziału geometrii, a nie samej geometrii. To nie ma znaczenia, gdy masz do czynienia z punktami. Cóż prawie. Bboksy mają mniejszą precyzję niż sam punkt, co teoretycznie może prowadzić do zgrupowania dwóch punktów, które nie są identyczne.
Nicklas Avén

Dzięki @ NicklasAvén. Jak dokładne jest porównanie Bbox? Spodziewałbym się, że to wystarczy do tego przypadku użycia.
podmrok

1
Dzięki @underdark. Czy wiesz, jak mogę policzyć liczbę przecinających się linii? Wypróbowałem kilka kombinacji COUNT()takich jak COUNT(ST_Touches(..))i, COUNT(ST_Intersection(..))ale wydaje się, że to nie działa, ponieważ wszystkie wartości są 12.
djq

@underdark, tak, to jest absolutnie wystarczające, dlatego napisałem „teoretycznie”. Pole ma wartość float4, a współrzędne punktu mają podwójną precyzję. Tak więc okno będzie wyglądać tak samo dla ST_Point (1.000001,1.0) i ST_Point (1.000002,1.0) (Przynajmniej w moim systemie, właśnie próbowałem. Grupuje punkty do razem). Ta różnica między geometrią pudełkową a rzeczywistą była dyskusją od pewnego czasu na liście deweloperów.
Nicklas Avén

Zobacz @AlexOs sugerowaną modyfikację gis.stackexchange.com/a/151277/3195
Martin F

6

Jest to trochę trudniejsze niż można się spodziewać. Jest tak, ponieważ nie ma dobrego sposobu analizowania relacji dla więcej niż par. Nie możesz wstawić trzech linii do funkcji i zapytać, czy wszystkie się przecinają.

Ale przynajmniej jednym podejściem może być znalezienie skrzyżowań, a następnie sprawdzenie, ile dróg styka się na każdym skrzyżowaniu (wszystko można zrobić w tym samym zapytaniu).

Jeśli twoje drogi idealnie się ze sobą łączą i nie ma żadnych dróg przechodzących przez skrzyżowanie, możesz zrobić coś takiego (nie testowane):
edytowane z zapomnianą klauzulą ​​grupy (wciąż nie testowane):

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;

Jeśli drogi nie są właściwie połączone i / lub niektóre drogi przechodzą przez skrzyżowanie, jest to bardziej skomplikowane.

HTH

Nicklas


Cześć @Nicklas, nie mogę uruchomić tego. Dwie wewnętrzne klauzule działają dobrze; powinienem zamieniać na distinct_crosspoints ,roadsmoją nazwę tabeli ( roads_test)? Próbowałem tego, ale potem wystąpił błąd dotyczący geomniejednoznaczności.
djq

1
@celenius, Przepraszam, że zapomniałem klauzuli grupy. Widzę też, że nie musisz stawiać odrębności na dodatkowym poziomie. Możesz po prostu umieścić go bezpośrednio na skrzyżowaniu. Zauważ, że Distinct ma takie samo zachowanie jak grupa, zgodnie z dyskusją pod odpowiedzią podmroku.
Nicklas Avén

Dodałem odrębny_krosspoints.geom do odpowiedzi Nicklas, aby uruchomić kwerendę. Teraz działa dla mnie.
Frank

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

Jeśli linia A (id 1) przecina linię B (id 2), to potrzebujemy punktu przecięcia. Ale linia B przecina także linię A w tym samym punkcie. Ale nie potrzebujemy tego punktu dwa razy. Dlatego używam a.gid < b.gid zamiasta.gid != b.gid

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.