Identification des intersections de routes à l'aide de PostGIS

17

J'essaie d'identifier où les routes se croisent et de faire un point à cette intersection, avec le nombre de routes qui forment l'intersection répertoriée.

entrez la description de l'image ici

Je me demandais s'il y avait un moyen d'utiliser ST_NumPoints pour y parvenir, mais je n'arrive pas à comprendre ce que je devrais faire. Ce que j'ai fait, c'est de créer une table de points où les lignes se croisent en utilisant le code suivant:

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

Si je lance cela sur un échantillon de routes, j'obtiens la grille de points suivante (les routes sont illustrées):

entrez la description de l'image ici

Si j'inspecte l'un des points, je constate qu'il y a plusieurs points empilés les uns sur les autres:

entrez la description de l'image ici

Le GID ici est l'ID de la route, mais je ne comprends pas pourquoi il y a beaucoup de points. Je peux comprendre que 4 points soient comptés pour une intersection routière centrale, mais il y a 12 points énumérés ici. Existe-t-il une meilleure façon d'effectuer ce calcul dans PostGIS?

djq
la source

Réponses:

21

Si vous vous regroupez, vous ne devriez obtenir que des points uniques.

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)
;
obscur
la source
Juste une remarque, le regroupement par géométrie entraîne un regroupement par la bbox de la géométrie, pas la géométrie elle-même. Cela n'a pas d'importance lorsqu'il s'agit de points. Enfin presque. Bboxes a moins de précision que le point lui-même, ce qui en théorie peut conduire à regrouper deux points qui ne sont pas identiques.
Nicklas Avén
Merci @ NicklasAvén. Quelle est la précision de la comparaison Bbox? Je m'attends à ce qu'il soit suffisant pour ce cas d'utilisation.
underdark
1
Merci @underdark. Savez-vous comment je peux compter le nombre de lignes qui se croisent? J'ai essayé quelques combinaisons de COUNT()telles que COUNT(ST_Touches(..))et COUNT(ST_Intersection(..))mais cela ne semble pas fonctionner comme toutes les valeurs 12.
djq
@underdark, oui c'est tout à fait suffisant, c'est pourquoi j'ai écrit "en théorie". La boîte est en float4 et les coordonnées du point sont en double précision. Ainsi, la boîte aura la même apparence pour ST_Point (1.000001,1.0) et ST_Point (1.000002,1.0) (Au moins sur mon système, je viens d'essayer. Il regroupe les points à ensemble). Cette différence entre la boîte et la géométrie réelle a été discutée pendant un certain temps chez dev-list.
Nicklas Avén
Voir la modification suggérée @AlexOs gis.stackexchange.com/a/151277/3195
Martin F
6

C'est un peu plus compliqué que vous ne le pensez. En effet, il n'existe aucun bon moyen d'analyser les relations pour plus de paires. Vous ne pouvez pas mettre trois lignes dans une fonction et demander si toutes se croisent.

Mais, au moins une approche pourrait être de trouver d'abord les croisements, puis de vérifier le nombre de routes qui se touchent à chaque croisement (tout peut être fait dans la même requête).

Si vos routes se connectent parfaitement les unes aux autres et qu'aucune route ne passe par un croisement, vous pouvez faire quelque chose comme ceci (non testé):
édité avec une clause de groupe oublié (toujours non testé):

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;

Si les routes ne sont pas connectées correctement et / ou que certaines routes passent par un croisement, c'est plus compliqué.

HTH

Nicklas

Nicklas Avén
la source
Bonjour @Nicklas, je ne parviens pas à le faire fonctionner. Les deux clauses internes fonctionnent bien; dois-je remplacer le distinct_crosspoints ,roadspar mon nom de table ( roads_test)? J'ai essayé cela, mais j'ai eu une erreur d' geomêtre ambigu.
djq
1
@celenius, Désolé d'avoir oublié la clause de groupe. Je vois aussi que vous n'avez pas besoin de mettre distinct à un niveau supplémentaire. Vous pouvez simplement le mettre directement à l'intersection. Notez que Distinct a le même comportement que group selon la discussion sous la réponse underdarks.
Nicklas Avén
J'ai ajouté le distinct_crosspoints.geom à la réponse de Nicklas pour lancer la requête. Fonctionne maintenant pour moi.
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)
    ;

Si la ligne A (id 1) croise la ligne B (id 2), c'est un point d'intersection dont nous avons besoin. Mais la ligne B coupe également la ligne A au même point. Mais nous n'avons pas besoin de ce point deux fois. Voilà pourquoi j'utilise a.gid < b.gid au lieu dea.gid != b.gid

Alex Os
la source