Punti di collegamento (fermate degli autobus), che non si trovano sulle linee (LINESTRING), alla rete?


9

Devo collegare le fermate degli autobus (punti) a un livello di rete (dati OSM). Queste fermate dell'autobus non si trovano direttamente sulle linee (vedi screenshot) né la loro posizione dovrebbe essere spostata. Uso PostGIS, pgrouting e QGIS e la rete è già instradabile con colonne di origine e destinazione, ecc.

inserisci qui la descrizione dell'immagine

Principalmente voglio fare due cose dopo:

  1. Ottenere le distanze tra le fermate dell'autobus utilizzando l'analisi del percorso più breve.
  2. Creazione di isocronici con distanze percorribili dalla fermata dell'autobus tramite la rete OSM.

Per ottenere valori esatti è necessario che l'instradamento 'inizi' e 'si fermi' più vicino alle fermate degli autobus. In molti casi il nodo esistente più vicino sarà troppo lontano per ottenere valori esatti. Ma non dovrebbe esserci un instradamento verso l'effettiva posizione del punto della fermata dell'autobus. Nel mio esempio sull'immagine puoi vedere come dovrebbe apparire il routing tra le fermate.

Esiste la possibilità di inserire automaticamente nuovi nodi nella rete (LINESTRING) più vicini alle fermate del bus o è possibile iniziare il routing su una sorta di "punto fittizio" impostato solo per la query (simile a quello della strada plug in Graph in QGIS fa)?

Risposte:


5

La prima parte della soluzione è questa:

SELECT a.id, ST_Closestpoint(ST_Collect(b.geom_way), a.geom) AS geom 
FROM point_table a, line_table b
GROUP BY a.id, a.geom;

Ciò aggancia i computer portatili alle linee della rete stradale come puoi vedere nella foto e funziona abbastanza facilmente.

inserisci qui la descrizione dell'immagine

Successivamente proverò a dividere le linee nelle posizioni dei punti. Dopo aver diviso le linee voglio usare di nuovo pgr_createTopology. Dopodiché dovrebbe essere possibile creare una query per scoprire i nodi più vicini ai computer portatili, che saranno i miei nodi appena generati nei "punti di splittaggio".

Le sarei grato se qualcuno avesse un suggerimento per me su come dividere il linestring con le caratteristiche dei punti nei postgis, dal momento che dopo aver esaminato domande simili non sembra essere una soluzione facile al momento.


ST_Split (somethingtocut, blade)
simplexio

1
aggiungendo commento perché non l'ho provato affatto, syntac probabilmente sbagliato ... ... selezionare *, st_split (a.lg, a.pg) da (selezionare *, lines.g come lg, points.geom come pg dai punti unisci le righe su ST_intersect (p.geom, l.geom)) come una raccolta di ritorno divisa, ma devi comunque estrarne tutte le righe ...
simplexio

2

Questa è la mia soluzione completa. Implica una sorta di hack per eseguire la divisione: ottengo i punti sulle linee (modi, per usare la terminologia OSM) ST_ClosestPointe poi li bufferizzo per una distanza molto piccola per far funzionare effettivamente la divisione. In caso contrario, errori di imprecisione / arrotondamento impedivano la divisione.

Questo ha il problema che genera due divisioni su ogni riga per punto (a causa del buffering). Per il mio uso questo andava bene, poiché in seguito ho instradato tra i punti di divisione più vicini ai punti originali, che erano al di fuori della linea, e potrebbe essere uno dei due punti di divisione dell'intersezione del buffer di linea.

Ho iniziato scaricando i dati OSM e impattandoli in Postgres:

CITY="MY_CITY"
BBOX="-46.6003,-23.7362,-46.4806,-23.5965"
wget --progress=dot:mega -O "$CITY.osm" "http://www.overpass-api.de/api/xapi?*[bbox=${BBOX}][@meta]"

# create database
createdb my_database
# add extensions
psql -d my_database -c "CREATE EXTENSION postgis;"
psql -d my_database -c "CREATE EXTENSION pgrouting;"

# import osm data to postgres database
osm2pgrouting \
    -f MY_CITY.osm \
    -d my_database \
    -U user

# load points into db
shp2pgsql -I -s 4326 points_to_split_ways.shp public.points_to_split_ways | psql -d my_database

Dividere i modi usando un buffer:

WITH pts_ways AS (
  -- get nearest way for each point we want to split the ways by
  SELECT s.gid AS pt_id, ws.gid AS way_gid, s.geom AS pt_geom, ws.the_geom AS way_geom FROM points_to_split_ways s
  CROSS JOIN LATERAL
  (
    SELECT w.gid, w.the_geom
    FROM ways w
    ORDER BY s.geom <-> w.the_geom LIMIT 1
  ) AS ws
), pts_on_ways AS (
  -- "move" these points to be on top of the ways
  SELECT pt_id, way_gid, ST_ClosestPoint(way_geom, pt_geom) as geom
  FROM pts_ways
), ways_without_pts AS (
  -- get the ways that don't have any points on them
  SELECT the_geom as the_geom, gid as way_gid FROM ways
  WHERE gid NOT IN (SELECT way_gid FROM pts_ways)
)
SELECT
  way_gid as old_id,
  -- we need to build a new unique ID, because split ways will share the old ID
  row_number() over(order by way_gid) as gid,
  -- this is the split way geometry
  the_geom
FROM (
  SELECT 
    way_gid,
    -- split the ways and dump into indiviudal segments
    (ST_Dump(ST_Split(line_geom, pt_geom))).geom AS the_geom
  FROM (
    (SELECT the_geom as line_geom, gid FROM ways) AS lines
    LEFT JOIN
    -- HACK: use a buffer to fix imprecisions / rounding errors
    -- this will generate one extra splitting per point (each buffer will intersect each way twice)
    -- but it's ok for our purposes
    -- also, collect them grouped by the way to handle cases where there are multiple points on the same way
    (SELECT ST_Collect(ST_Buffer(geom, 0.000001)) as pt_geom, way_gid FROM pts_on_ways GROUP BY way_gid) AS pts
    ON lines.gid = pts.way_gid
  ) AS tmp1
  -- union the ways without points, otherwise you'd get only the ones that were split
  UNION ALL
  SELECT way_gid, the_geom FROM ways_without_pts
) AS tmp2;

Crea la topologia necessaria per il routing con pgrouting:

SELECT UpdateGeometrySRID('ways_split','the_geom', 4326);
SELECT find_srid('public','ways_split','the_geom');
ALTER TABLE ways_split ADD COLUMN "source" integer;
ALTER TABLE ways_split ADD COLUMN "target" integer;
ALTER TABLE ways_split ADD PRIMARY KEY (gid);
ALTER TABLE ways_split ADD CONSTRAINT ways_source_fkey FOREIGN KEY (source) REFERENCES ways_split_vertices_pgr (id) MATCH FULL;
ALTER TABLE ways_split ADD CONSTRAINT ways_target_fkey FOREIGN KEY (target) REFERENCES ways_split_vertices_pgr (id) MATCH FULL;
SELECT pgr_createTopology('ways_split', 0.00001, 'the_geom', 'gid', clean := TRUE);
SELECT pgr_analyzeGraph('ways_split', 0.000001, the_geom := 'the_geom', id := 'gid');

Anche il mio primo pensiero è stato buffer. Ma se riesci a ottenere una 'distanza dal più vicino', tamponare tale importo, creare un punto in quell'intersezione ... allora potresti creare una linea con i punti finali costituiti dal punto originale e il punto 'più vicino' ad esso.
Mox,

1

Dal momento che sto lavorando su un'attività simile, volevo solo parlare dell'approccio che sto usando attualmente. Questo fa uso di GRASS GIS, ma per quanto riguarda i miei esperimenti con PostGIS, è abbastanza complicato aggiungere più nuovi punti ai LineString esistenti suddividendo tali LineString nelle rispettive posizioni, anche se sono sicuro che ci sia una soluzione conveniente.

Ora ho fatto uso della v.netfunzione GRIS GIS usando l'opzione connect. Basta scegliere input vector line layere points layer. C'è la possibilità di agganciare i punti al punto più vicino sulle linee o di creare nuove connessioni tra il punto più vicino sulle linee e il nuovo punto.

Ecco un'immagine prima e dopo. Sul lato destro, per ogni punto del livello punti è stato aggiunto un nodo sulla rete stradale: inserisci qui la descrizione dell'immagine

Successivamente in PostGIS, dopo aver creato la ..._vertices_pgrtabella fuori dalla rete stradale, basta assegnare i punti al vertice più vicino in modo da poterli utilizzare nelle richieste di instradamento. Per questa attività è possibile utilizzare la ST_ClosestPointfunzione svolta da @Setraworks nella sua risposta.

Gli svantaggi di questo approccio sono:

  • il collegamento dei punti con le linee deve essere eseguito in GRASS GIS
  • i percorsi calcolati potrebbero essere costituiti da molti componenti (a seconda della quantità di punti appena aggiunti)
  • aggiunta dinamica di nuovi punti non possibile

Questo approccio funziona bene se hai un numero definito di punti da aggiungere alla rete stradale (come nell'esempio della domanda con le fermate degli autobus).

Se qualcuno può fornire un esempio funzionante con PostGIS, mi piacerebbe leggerlo!


0

C'è un post che discute un problema simile, puoi vedere quel post nel seguente percorso: http://osdir.com/ml/qgis-user-gis/2011-11/msg00220.html


Questa è solo una parte di una possibile soluzione, perché dopo aver agganciato i punti alle linee, i punti si trovano direttamente sulle linee, ma non fanno ancora parte della rete.
Setraworks,

Se ti aspetti di ottenere una risposta che ti fornisca tutte le tue esigenze, potresti rimanere deluso. Questo potrebbe farti arrivare a metà strada, quindi puoi concentrarti sull'altra parte che ti manca.
Ryan Garnett,

Penso che tu abbia ragione Ryan. Sono già riuscito a agganciare i punti alle linee, quindi il passo successivo sarà scoprire come dividere i linestring con i punti in postgis. Grazie per il tuo aiuto finora!
Setraworks

Sono contento di poterti aiutare. Esistono strumenti che suddividono una linea con un punto, ma continuerò a cercare un'opzione in PostGIS. Buona fortuna
Ryan Garnett

@Setraworks potresti dare un'occhiata alla seguente opzione PostGIS (ST_Split) postgis.net/docs/ST_Split.html . Puoi dividere una linea con un punto, ecco la spiegazione di PostGIS: la funzione supporta la divisione di una riga per punto, una riga per riga, un poligono per riga. La geometria restituita è sempre una raccolta.
Ryan Garnett,
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.