Comment calculer le plus petit réseau qui relie tous les points à l'aide de PostGIS?

13

J'ai un ensemble de scripts postgis qui génère deux tableaux - l'un d'un ensemble de points et le second un ensemble de routes qui les entourent. Toutes les données sont dans la même projection et les deux sorties sont stockées dans des tableaux postgres 9.2 avec postgis 2.1

La topologie de routage du réseau routier a été créée et la table de points a une colonne contenant le segment de route le plus proche.

Je voudrais alors générer un sous-ensemble du réseau routier qui représente le plus petit réseau qui relie tous les points en utilisant quelque chose comme un arbre couvrant minimum. Le réseau routier n'est pas dirigé et les coûts sont simplement la longueur de l'itinéraire.

Je peux le faire dans QGIS / Grass en utilisant la famille de modules v.net mais, idéalement, je voudrais également conserver cette dernière étape dans SQL.

J'ai regardé la nouvelle fonction postgis apspWarshall, mais je ne sais pas comment l'encourager à concentrer son énergie sur la connexion des points et non sur l'ensemble du réseau.

Ceci est le court script que j'ai mis en place pour tenter de créer un cadre pour résoudre ce problème, mais je ne vois pas où il est possible de concentrer la fonction pour commencer avec un sous-ensemble des bords.

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

Dans les problèmes de chemin le plus court à chemin unique, la fonction demande le début et la fin, mais apparemment pas dans les problèmes tous points. De même, dans Grass, v.net.spanningtree et v.net.steiner attendent un ensemble de points et de lignes en tant que réseau combiné avec lequel travailler.

Quelqu'un a-t-il des suggestions sur la façon de procéder dans PostGIS?

Adrian
la source
Je ne suis pas sûr de comprendre la question, mais est-ce que l' algorithme docs.pgrouting.org/2.0/en/src/tsp/doc/index.html#pgr-tsp Sales Sales Person vous aide?
simplexio
1
Merci. Ce n'est pas vraiment que j'ai peur. Le vendeur itinérant suppose un voyage de a à b à c et ainsi de suite de manière linéaire. Ce que je veux, c'est le réseau minimum qui relie efficacement chaque point de telle sorte que tout point puisse commencer un voyage vers n'importe quel autre point en sachant qu'il n'y a pas de chemins superflus pour se perdre. Dans d'autres plates-formes, cela se fait généralement avec une fonction d'arbre couvrant minimal, Steiner Tree ( en.wikipedia.org/wiki/Steiner_tree_problem ) ou similaire. Si vous le souhaitez, TSP est idéal pour l'entreprise de logistique, mais je veux planifier les routes qu'ils utiliseraient.
Adrian

Réponses:

2

Cette réponse n'est pas complète ou testée, mais essayez quelque chose comme ceci:

selon questions / 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;

je pense que ce n'est pas très efficace.

youseeus
la source
Je l'apprécie vraiment - merci. Cela m'a donné de nouveaux angles à explorer auxquels je n'avais pas pensé. Ce code trouvera les voisins non connectés les plus proches d'une table de points. La complication supplémentaire que j'ai est que les points dans mon cas sont connectés le long d'un réseau de chaînes de lignes, mais je me demande si je peux remplacer la requête ST_Distance par une distance de route pgRouting, bien que ce soit beaucoup plus lent qu'une requête ponctuelle non routée.
Adrian
2

@Adrian, je ne connais pas vraiment les résultats du pgroutage, mais la documentation est très détaillée. Ma réponse est basée sur une fonction en deux étapes, qui sera très inefficace en SQL mais produira [probablement] les résultats. Cette solution [non testée] n'optimisera PAS le meilleur point de départ, mais réduira l'ensemble du réseau d'itinéraire aux seuls tronçons qui relient tous les arrêts, puis acheminera efficacement tous les arrêts.

Étape 1 (sous-sélection d'un sous-ensemble du réseau routier qui relie tous les arrêts) Cette fonction utilise la fonction de routage à destinations multiples (chemin K Dijkstr) pour renvoyer une collection de chemins qui (lorsque le coût <> -1) connectent réellement tous vos s'arrête.

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

Le problème que j'ai ici est la syntaxe pour assembler un tableau à partir de votre table d'arrêt, car elle n'était pas vraiment décrite dans la question. Cependant, supposons que la syntaxe SQL puisse assembler ce tableau et que l'arrêt id minimum doit être le point de départ de tous les K chemins vers les arrêts cibles restants.

Étape 2 (sélection finale des chemins minimaux en fonction des chemins de réseau routier du sous-ensemble ci-dessus qui relient tous les arrêts ) de sorte que seul le sous-ensemble de routes soit utilisé dans le routage final 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

Donc, en résumé ... la requête de routage k_dijkstra_path interne réduit le réseau routier total aux seuls chemins reliant tous vos arrêts, puis le routage fField_Warshal externe utilise uniquement ces identifiants de bord pour résoudre la requête d'optimisation de chemin .... peut-être.

JasonInVegas
la source
Merci - c'est très utile et ma première nouvelle piste. Je regarde ça maintenant. J'essaie juste de savoir comment générer l'id d'arrêt minimum et le tableau. J'ai une table des identifiants requis mais 'SELECT min (id) FROM node_table' et 'SELECT ARRAY [id] FROM node_table' produisent des erreurs de syntaxe lorsqu'ils sont insérés dans votre code mais fonctionnent comme du code autonome (ma mauvaise compréhension je suis sûr)
Adrian