¿Cómo calcular la red más pequeña que conecta todos los puntos usando PostGIS?

13

Tengo un conjunto de scripts postgis que genera dos tablas: una de un conjunto de puntos y la segunda un conjunto de carreteras que los rodean. Todos los datos están en la misma proyección y ambas salidas se almacenan en tablas postgres 9.2 con postgis 2.1

Se ha creado la topología de la red de carreteras y la tabla de puntos tiene una columna que contiene el segmento de carretera más cercano.

Entonces me gustaría generar un subconjunto de la red de carreteras que represente la red más pequeña que conecta todos los puntos usando algo así como un árbol de expansión mínima. La red de carreteras no está dirigida y los costos son simplemente la longitud de la ruta.

Puedo hacer esto en QGIS / Grass usando la familia de módulos v.net, pero idealmente me gustaría mantener este paso final en SQL también.

He visto la nueva función postgis apspWarshall, pero no sé cómo se puede alentar a centrar su energía en conectar los puntos y no en toda la red.

Este es el script corto que he creado en un intento de crear un marco para resolver esto, pero no puedo ver dónde es posible enfocar la función para comenzar con un subconjunto de los bordes.

SELECT seq, id1 AS node, id2 AS edge, cost, the_geom
FROM   pgr_apspWarshall('SELECT gid AS id, 
                                source, 
                                target, 
                                st_length(the_geom) AS cost 
                         FROM   road_network
                        ',
                        false, false
                       ) AS tree
JOIN   road_network As roads
ON     tree.id2 = roads.gid

En los problemas de ruta más corta de ruta única, la función solicita el inicio y el final, pero aparentemente no en los problemas de todos los puntos. Igualmente en Grass, v.net.spanningtree y v.net.steiner esperan un conjunto de puntos y líneas como una red combinada para trabajar.

¿Alguien tiene alguna sugerencia sobre cómo hacer esto en PostGIS?

Adrian
fuente
No estoy seguro de entender la pregunta, pero ¿ le ayuda el algoritmo docs.pgrouting.org/2.0/en/src/tsp/doc/index.html#pgr-tsp Travelling Sales Person?
simplexio
1
Gracias. Realmente no tengo miedo. El vendedor que viaja asume un viaje de a a b a c y así sucesivamente de forma lineal. Lo que quiero es la red mínima que vincule cada punto de manera eficiente, de modo que cualquier punto pueda comenzar un viaje a cualquier otro punto sabiendo que no hay caminos superfluos para perderse. En otras plataformas, esto generalmente se hace con una función de Árbol de expansión mínimo, Steiner Tree ( en.wikipedia.org/wiki/Steiner_tree_problem ) o similar. Si lo desea, TSP es excelente para la empresa de logística, pero quiero planificar las carreteras que utilizarían.
Adrian

Respuestas:

2

Esta respuesta no está completa o probada, pero intente algo como esto:

Según las preguntas / 39210 :

with index_query as (
SELECT
        ,ST_Distance(i.geom, i.b_geom) AS dist
        ,ST_MakeLine(i.geom, i.b_geom) as geom
FROM(
SELECT
        ,a.geom
        ,b.geom AS b_geom
        ,rank() OVER (PARTITION BY a.id ORDER BY ST_Distance(a.centroid_geom, b.the_geom)) AS pos
FROM points a, points b 
WHERE a.id <> b.id) i
WHERE pos = 1
) select ST_Union(geom) from index_query;

Creo que esto no es muy eficiente.

youseeus
fuente
Realmente aprecio esto, gracias. Esto me ha dado algunos ángulos nuevos para explorar en los que no había pensado. Este código encontrará los vecinos no conectados más cercanos de una tabla de puntos. La complicación adicional que tengo es que los puntos en mi caso están conectados a lo largo de una red de cadenas lineales, pero me pregunto si puedo reemplazar la consulta ST_Distance con una distancia de ruta pgRouting, aunque sería significativamente más lenta que una consulta de puntos sin enrutar.
Adrian
2

@Adrian, no estoy muy familiarizado con los resultados de pgrouting, sin embargo, la documentación es muy detallada. Mi respuesta se basa en una función de dos pasos, que será muy ineficiente en SQL pero [probablemente] produce los resultados. Esta solución [no probada] NO optimizará cuál es el mejor punto de partida, pero reducirá toda la red de rutas a solo los bordes que conectan todas las paradas, luego las rutas de manera eficiente a todas las paradas.

Paso 1 (sub-selección de un subconjunto de red de carreteras que conecta todas las paradas) Utiliza la función de enrutamiento de múltiples destinos (ruta K Dijkstr) para devolver una colección de rutas que (cuando el costo <> -1) realmente conecta todos sus se detiene

SELECT id1 as path, st_astext(st_linemerge(st_union(b.the_geom))) as the_geom
FROM pgr_kdijkstraPath(
SELECT id, source, target, cost FROM edge_table’,
min(all_your_stop_ids), [array_of_all_your_stop_ids], false, false
) a,
edge_table b
WHERE a.id3=b.id
GROUP by id1
ORDER by id1

El problema que tengo aquí es la sintaxis para ensamblar una matriz de su tabla de parada, ya que no se describió realmente en la pregunta. Sin embargo, supongamos que la sintaxis SQL puede ensamblar esa matriz y que la parada mínima de identificación debería ser el punto de partida para todas las rutas K a las paradas objetivo restantes.

Paso 2 (selección final de las rutas mínimas en función de las rutas de red de carreteras del subconjunto anteriores que conectan todas las paradas) Esto es esencialmente con lo que comenzó, pero le propongo que combine su red de carreteras con el resultado inicial en id1 (ruta) para que solo se use el subconjunto de carreteras en la ruta final de Field-Warshal :

SELECT seq, id1 AS node, id2 AS edge, cost, the_geom
FROM   pgr_apspWarshall('SELECT R.gid AS id, 
                                R.source, 
                                R.target, 
                                st_length(R.the_geom) AS cost 
             FROM   road_network AS R JOIN
                   (SELECT id1 as path
                     FROM pgr_kdijkstraPath(
                            ’SELECT id, source, target, cost FROM edge_table’,
                            min(all_your_stop_ids), 
                            [array_of_all_your_stop_ids], false, false
                           ) a,
                     edge_table b
                    WHERE a.id3=b.id
                    GROUP by id1
                    ORDER by id1
                        ',
                        false, false
                  ) AS  Just_K_Paths
         on R.id1 = just_K_paths.id1',       /* this join reduces R down to K paths */
         false, false
        ) AS tree
  JOIN   road_network As roads
  ON     tree.id2 = roads.gid

Entonces, en resumen ... la consulta de enrutamiento interna k_dijkstra_path reduce la red vial total a solo las rutas que conectan todas sus paradas, luego la ruta externa fField_Warshal usa solo esos identificadores de borde para resolver la consulta de optimización de ruta ... tal vez.

JasonInVegas
fuente
Gracias, esto es muy útil y mi primer nuevo plomo. Lo estoy mirando ahora. Solo estoy tratando de averiguar cómo generar la identificación de parada mínima y la matriz. Tengo una tabla de los identificadores requeridos, pero 'SELECCIONAR min (id) DESDE node_table' y 'SELECCIONAR ARRAY [id] FROM node_table' producen errores de sintaxis cuando se insertan en su código pero funcionan como código independiente (mi pobre comprensión es que soy seguro)
Adrian