Straßenkreuzungen mit PostGIS identifizieren

17

Ich versuche zu identifizieren, wo sich Straßen kreuzen, und einen Punkt an dieser Kreuzung zu machen, wobei die Anzahl der Straßen, die die Kreuzung bilden, aufgelistet wird.

Bildbeschreibung hier eingeben

Ich habe mich gefragt, ob es eine Möglichkeit gibt, ST_NumPoints zu verwenden, um dies zu erreichen, aber ich kann nicht genau herausfinden, was ich tun soll. Ich habe eine Punktetabelle erstellt, in der sich die Linien mit dem folgenden Code schneiden:

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

Wenn ich dies auf einem Beispiel von Straßen laufen lasse, erhalte ich das folgende Punktraster (die Straßen werden zur Veranschaulichung gezeigt):

Bildbeschreibung hier eingeben

Wenn ich einen der Punkte inspiziere, sehe ich, dass viele Punkte übereinander gestapelt sind:

Bildbeschreibung hier eingeben

Die GID ist hier der Straßenausweis, aber ich verstehe nicht, warum es so viele Punkte gibt. Ich kann verstehen, dass 4 Punkte für eine zentrale Straßenkreuzung gezählt werden, aber hier sind 12 Punkte aufgeführt. Gibt es eine bessere Möglichkeit, diese Berechnung in PostGIS durchzuführen?

djq
quelle

Antworten:

21

Wenn Sie gruppieren, sollten Sie nur eindeutige Punkte erhalten.

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)
;
Underdunkel
quelle
Nur eine Notiz, Gruppierung nach Geometrie, führt zu Gruppierung nach dem b-Feld der Geometrie, nicht der Geometrie selbst. Das spielt keine Rolle, wenn es um Punkte geht. Naja fast. Bboxes hat eine geringere Genauigkeit als der Punkt selbst, was theoretisch dazu führen kann, dass zwei nicht identische Punkte zusammengefasst werden.
Nicklas Avén
Danke @ NicklasAvén. Wie genau ist der Bbox-Vergleich? Ich würde erwarten, dass es für diesen Anwendungsfall ausreicht.
Underdunkel
1
Danke @underdark. Wissen Sie, wie ich die Anzahl der sich schneidenden Linien zählen kann? Ich habe versucht, ein paar Kombinationen COUNT()wie COUNT(ST_Touches(..))und, COUNT(ST_Intersection(..))aber dies scheint nicht zu funktionieren, wie alle Werte sind 12.
djq
@underdark, ja es ist absolut genug, deshalb habe ich "theoretisch" geschrieben. Die Box befindet sich in float4 und die Koordinaten des Punktes sind doppelt genau. So sieht die Box für ST_Point (1.000001,1.0) und ST_Point (1.000002,1.0) gleich aus (Zumindest bei meinem System habe ich es gerade versucht. Es gruppiert die zu Punkten zusammen). Dieser Unterschied zwischen Box und realer Geometrie ist bei dev-list schon seit einiger Zeit umstritten.
Nicklas Avén
Siehe @AlexOs Änderungsvorschlag gis.stackexchange.com/a/151277/3195
Martin F
6

Das ist ein bisschen kniffliger als Sie vielleicht erwarten. Das liegt daran, dass es keine gute Möglichkeit gibt, Beziehungen für mehr als Paare zu analysieren. Sie können nicht drei Zeilen in eine Funktion einfügen und fragen, ob sich alle überschneiden.

Mindestens ein Ansatz könnte jedoch darin bestehen, zuerst die Kreuzungen zu finden und dann zu überprüfen, wie viele Straßen sich an jeder Kreuzung berühren (dies kann alles in derselben Abfrage erfolgen).

Wenn Ihre Straßen perfekt miteinander verbunden sind und es keine Straßen gibt, die an einer Kreuzung vorbeiführen, können Sie Folgendes tun (nicht getestet):
Mit vergessener Gruppenklausel bearbeitet (immer noch nicht getestet):

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;

Wenn die Straßen nicht richtig verbunden sind und / oder einige Straßen an einer Kreuzung vorbeifahren, ist dies komplizierter.

HTH

Nicklas

Nicklas Avén
quelle
Hallo @Nicklas, ich bin nicht in der Lage, dies zum Laufen zu bringen. Die zwei inneren Klauseln funktionieren gut; soll ich das distinct_crosspoints ,roadsdurch meinen Tabellennamen ( roads_test) ersetzen ? Das habe ich versucht, aber dann ist mir der Fehler unterlaufen, dass geomich mehrdeutig bin.
djq
1
@celenius, Entschuldigung, ich hatte die Gruppenklausel vergessen. Ich sehe auch, dass Sie nicht auf einer zusätzlichen Ebene unterscheiden müssen. Sie können es einfach direkt auf die Kreuzung setzen. Beachten Sie, dass Distinct das gleiche Verhalten wie group by hat, wie in der Diskussion unter underdarks answer beschrieben.
Nicklas Avén
Ich habe die distinct_crosspoints.geom zur Nicklas-Antwort hinzugefügt, um die Abfrage zum Laufen zu bringen. Funktioniert jetzt für mich.
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)
    ;

Wenn die Linie A (ID 1) die Linie B (ID 2) kreuzt, ist dies ein Schnittpunkt, den wir benötigen. Die Linie B kreuzt jedoch auch die Linie A an derselben Stelle. Diesen Punkt brauchen wir aber nicht zweimal. Deshalb benutze ich a.gid < b.gid statta.gid != b.gid

Alex Os
quelle