Identificación de intersecciones viales con PostGIS

17

Estoy tratando de identificar dónde se cruzan las carreteras entre sí, y hacer un punto en esta intersección, con el número de carreteras que forman la intersección enumerada.

ingrese la descripción de la imagen aquí

Me preguntaba si había alguna forma de usar ST_NumPoints para lograr esto, pero no puedo entender qué debería hacer. Lo que he hecho es crear una tabla de puntos donde las líneas se cruzan usando el siguiente código:

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 ejecuto esto en una muestra de carreteras, obtengo la siguiente cuadrícula de puntos (las carreteras se muestran a modo de ilustración):

ingrese la descripción de la imagen aquí

Si inspecciono uno de los puntos, veo que hay muchos puntos apilados uno encima del otro:

ingrese la descripción de la imagen aquí

El GID aquí es la identificación de la carretera, pero no entiendo por qué hay muchos puntos. Puedo entender que se cuentan 4 puntos para una intersección de carretera central, pero hay 12 puntos enumerados aquí. ¿Hay una mejor manera de realizar este cálculo en PostGIS?

djq
fuente

Respuestas:

21

Si agrupa, solo debería obtener puntos únicos.

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)
;
bajo oscuro
fuente
Solo un aviso, la agrupación por geometría da como resultado la agrupación por el bbox de la geometría, no la geometría en sí. Eso no importa cuando se trata de puntos. Bueno, casi. Bboxes tiene menos precisión que el punto en sí mismo, lo que en teoría puede llevar a agrupar dos puntos que no son idénticos.
Nicklas Avén
Gracias @ NicklasAvén. ¿Qué tan precisa es la comparación de Bbox? Espero que sea suficiente para este caso de uso.
oscuro
1
Gracias @underdark. ¿Sabes cómo puedo contar la cantidad de líneas que se cruzan? He intentado algunas combinaciones de COUNT()tales como COUNT(ST_Touches(..))y, COUNT(ST_Intersection(..))pero esto no parece funcionar como lo son todos los valores 12.
DJ
@underdark, sí, es absolutamente suficiente, por eso escribí "en teoría". El cuadro está en float4 y las coordenadas del punto están en doble precisión. Por lo tanto, el cuadro se verá igual para ST_Point (1.000001,1.0) y ST_Point (1.000002,1.0) (Al menos en mi sistema, acabo de intentarlo. Agrupa los puntos a). Esta diferencia entre la caja y la geometría real ha sido una discusión durante algún tiempo en la lista de desarrolladores.
Nicklas Avén
Consulte la modificación sugerida de @AlexOs gis.stackexchange.com/a/151277/3195
Martin F
6

Esto es un poco más complicado de lo que cabría esperar. Esto se debe a que no hay una buena manera de analizar las relaciones para más que pares. No puede poner tres líneas en una función y preguntar si todas se cruzan.

Pero, al menos un enfoque podría ser encontrar primero los cruces, luego verificar cuántos caminos se tocan en cada cruce (todo se puede hacer en la misma consulta).

Si sus caminos se conectan perfectamente entre sí y no hay caminos que pasen por un cruce, entonces podría hacer algo como esto (no probado):
editado con una cláusula de grupo olvidado (aún no probado):

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 las carreteras no están conectadas correctamente y / o algunas carreteras pasan por un cruce, es más complicado.

HTH

Nicklas

Nicklas Avén
fuente
Hola @Nicklas, no puedo hacer que esto se ejecute. Las dos cláusulas internas funcionan bien; ¿Debo reemplazar el distinct_crosspoints ,roadsnombre de mi tabla ( roads_test)? Lo intenté pero luego recibí un error acerca de geomser ambiguo.
djq
1
@celenius, siento haber olvidado la cláusula del grupo. También veo que no es necesario poner distintivo en un nivel adicional. Puedes ponerlo directamente en la intersección. Tenga en cuenta que Distinct tiene el mismo comportamiento que group by según la discusión en underdarks answer.
Nicklas Avén
Agregué distinct_crosspoints.geom a la respuesta de Nicklas para ejecutar la consulta. Ahora funciona para mi.
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 línea A (id 1) cruza la línea B (id 2) es un punto de intersección que necesitamos. Pero la línea B también cruza la línea A en el mismo punto. Pero no necesitamos este punto dos veces. Es por eso que estoy usando en a.gid < b.gid lugar dea.gid != b.gid

Alex Os
fuente