Come calcolare la rete più piccola che collega tutti i punti usando PostGIS?


13

Ho una serie di script Postgis che genera due tabelle: una di una serie di punti e la seconda una serie di strade che li circondano. Tutti i dati sono nella stessa proiezione ed entrambi gli output sono memorizzati nelle tabelle Postgres 9.2 con Postgis 2.1

È stata creata la topologia pgrouting della rete stradale e la tabella dei punti ha una colonna contenente il segmento stradale più vicino.

Vorrei quindi generare un sottoinsieme della rete stradale che rappresenta la rete più piccola che collega tutti i punti usando qualcosa come un albero di spanning minimo. La rete stradale non è indirizzata e i costi sono semplicemente la lunghezza del percorso.

Posso farlo in QGIS / Grass usando la famiglia di moduli v.net ma idealmente mi piacerebbe mantenere anche questo passaggio finale in SQL.

Ho esaminato la nuova funzione postgis di apspWarshall, ma non riesco a capire come può essere incoraggiato a concentrare la propria energia sulla connessione dei punti e non sull'intera rete.

Questo è lo script breve che ho messo insieme nel tentativo di creare un framework per risolverlo, ma non riesco a vedere dove sia possibile focalizzare la funzione per iniziare con un sottoinsieme dei bordi.

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

Nei singoli percorsi più brevi, la funzione richiede l'inizio e la fine, ma apparentemente non in tutti i punti. Allo stesso modo in Grass, v.net.spanningtree e v.net.steiner si aspettano un insieme di punti e linee come una rete combinata con cui lavorare.

Qualcuno ha un suggerimento su come farlo in PostGIS?


non sono sicuro di aver capito la domanda, ma l' algoritmo docs.pgrouting.org/2.0/en/src/tsp/doc/index.html#pgr-tsp è un algoritmo per i venditori ambulanti ?
simplexio,

1
Grazie. Non ho davvero paura. Il commesso viaggiatore assume un viaggio da a a b a c e così via in modo lineare. Quello che voglio è la rete minima che collega ogni punto in modo efficiente in modo tale che ogni punto possa iniziare un viaggio verso qualsiasi altro punto nella consapevolezza che non ci sono percorsi superflui da perdere. In altre piattaforme, ciò avviene di solito con una funzione Spanning Tree minimo, Steiner Tree ( en.wikipedia.org/wiki/Steiner_tree_problem ) o simili. Se ti piace, TSP è ottimo per la società di logistica, ma voglio pianificare le strade che useranno.
Adrian,

Risposte:


2

Questa risposta non è completa o testata, ma prova qualcosa del genere:

secondo le domande / 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;

penso che questo non sia molto efficiente.


Lo apprezzo davvero - grazie. Questo mi ha dato alcuni nuovi angoli da esplorare a cui non avevo pensato. Questo codice troverà i vicini non connessi più vicini da una tabella di punti. L'ulteriore complicazione che ho è che i punti nel mio caso sono collegati lungo una rete di linestring, ma mi chiedo se posso sostituire la query ST_Distance con una distanza stradale pgRouting, anche se sarebbe significativamente più lenta di una query di punti non rotta.
Adrian,

2

@Adrian, non ho molta familiarità con i risultati di puting, tuttavia la documentazione è molto dettagliata. La mia risposta si basa su una funzione in due passaggi, che sarà molto carente in SQL ma [probabilmente] produce i risultati. Questa soluzione [non testata] NON ottimizzerà quale sia il miglior punto di partenza, ma ridurrà l'intera rete di rotte solo ai bordi che collegano tutte le fermate, quindi instrada in modo efficiente a tutte le fermate.

Passaggio 1 (sottoselezione di un sottoinsieme della rete stradale che collega tutte le fermate) Utilizza la funzione di routing a destinazione multipla (percorso K Dijkstr) per restituire una raccolta di percorsi che (quando il costo <> -1) effettivamente collegano tutti i tuoi fermate.

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

Il problema che ho qui è la sintassi per assemblare un array dalla tabella di arresto, poiché non è stato descritto nella domanda. Tuttavia, supponiamo che la sintassi SQL possa assemblare quell'array e che l'arresto minimo dell'id dovrebbe essere il punto di partenza per tutti i percorsi K verso i rimanenti target target.

Passaggio 2 (selezione finale dei percorsi minimi in base ai percorsi della rete stradale del sottoinsieme di cui sopra che collegano tutte le fermate) Questo è essenzialmente ciò che hai iniziato, ma ti propongo di unire la tua rete stradale al risultato iniziale su id1 (percorso) in modo che solo il sottoinsieme di strade venga utilizzato nell'indirizzamento finale di 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

Quindi, in sintesi ... la query di routing k_dijkstra_path interna riduce la rete stradale totale solo ai percorsi che collegano tutte le fermate, quindi il routing fField_Warshal esterno utilizza solo quegli ID edge per risolvere la query di ottimizzazione del percorso .... forse.


Grazie - questo è molto utile e il mio primo nuovo vantaggio. Lo sto guardando adesso. Sto solo cercando di capire come generare l'id di arresto minimo e l'array. Ho una tabella degli ID richiesti ma 'SELECT min (id) FROM node_table' e 'SELECT ARRAY [id] FROM node_table' producono errori di sintassi quando vengono inseriti nel codice ma funzionano come codice indipendente (la mia scarsa comprensione sono certo)
Adrian,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.