Puntos de conexión (paradas de autobús), que no se encuentran en las líneas (LINESTRING), a la red?

9

Necesito conectar paradas de autobús (puntos) a una capa de red (datos OSM). Estas paradas de autobús no se encuentran directamente en las líneas (ver captura de pantalla) ni se debe mover su ubicación. Uso PostGIS, pgrouting y QGIS y la red ya es enrutable con columnas de origen y destino, etc.

ingrese la descripción de la imagen aquí

Principalmente quiero hacer dos cosas después:

  1. Obtener las distancias entre las paradas de autobús utilizando el análisis de ruta más corta.
  2. Creación de isócronas a poca distancia de la parada de autobús utilizando la red OSM.

Para obtener valores exactos, es necesario que la ruta "comience" y "pare" más cerca de las paradas de autobús. En muchos casos, el nodo existente más cercano estará demasiado lejos para obtener valores exactos. Pero no debe haber una ruta a la ubicación del punto real de la parada de autobús. En mi ejemplo en la imagen, puede ver cómo debería ser la ruta entre paradas.

¿Existe la posibilidad de insertar nuevos nodos automáticamente en la red (LINESTRING) que están más cerca de las paradas de autobús o es posible comenzar el enrutamiento en una especie de 'punto ficticio' que se establece solo para la consulta (similar a lo que ocurre en la carretera plugin gráfico en QGIS hace)?

Setraworks
fuente

Respuestas:

5

La primera parte de la solución es esta:

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;

Esto ajusta las paradas de autobús a las líneas de la red de carreteras como se puede ver en la imagen y funciona bastante fácil.

ingrese la descripción de la imagen aquí

A continuación, intentaré dividir las líneas en las ubicaciones de los puntos. Después de dividir las líneas, quiero usar pgr_createTopology nuevamente. Después de eso, debería ser posible crear una consulta para encontrar los nodos más cercanos a las paradas de bus, que serán mis nodos recién generados en los 'puntos de división'.

Estaría agradecido si alguien tuviera una pista para mí sobre cómo dividir cadenas lineales con entidades de puntos en postgis, ya que después de mirar preguntas similares no parece haber una solución fácil para eso en este momento.

Setraworks
fuente
ST_Split (algo cortado, cuchilla)
simplexio
1
agregando comentarios porque no probé esto en absoluto, la sintaxis probablemente sea incorrecta ... ... seleccione *, st_split (a.lg, a.pg) de (select *, lines.g como lg, points.geom como pg de puntos unir líneas en ST_intersect (p.geom, l.geom)) como una colección de devolución dividida, por lo que aún necesita obtener todas las líneas ...
simplexio
2

Esta es mi solución completa. Implica una especie de truco para hacer la división: obtengo los puntos en las líneas (formas, para usar la terminología OSM) usando ST_ClosestPoint, y luego los amortiguo a una distancia muy pequeña para que la división realmente funcione. De lo contrario, los errores de imprecisión / redondeo impedían la división.

Esto tiene el problema de que genera dos divisiones en cada línea por punto (debido al almacenamiento en búfer). Para mi uso, esto estaba bien, ya que más tarde me dirigí entre los puntos de división más cercanos a los puntos originales, que estaban fuera de la línea, y podría ser cualquiera de los dos puntos de división de la intersección del búfer de línea.

Comencé descargando datos de OSM e incorporándolos a 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

Dividiendo las formas 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;

Cree la topología necesaria para el enrutamiento 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');
bplmp
fuente
Mi primer pensamiento fue el amortiguador también. Pero si puede obtener una 'distancia al más cercano', amortiguar esa cantidad, crear un punto en esa intersección ... entonces podría crear una línea con los puntos finales consistentes en su punto original y el punto 'más cercano'.
Mox
1

Como estoy trabajando en una tarea similar, solo quería contarles sobre el enfoque que estoy usando actualmente. Esto hace uso de GRASS GIS, pero en lo que respecta a mis experimentos con PostGIS, es bastante complicado agregar múltiples puntos nuevos a LineStrings existentes al dividir esos LineStrings en las ubicaciones respectivas, aunque estoy seguro de que hay una solución conveniente.

Ahora hice uso de la v.netfunción GRASS GIS usando la opción connect. Solo elige input vector line layery points layer. Existe la opción de ajustar los puntos al punto más cercano en las líneas o crear nuevas conexiones entre el punto más cercano en las líneas y el nuevo punto.

Aquí hay una imagen de antes y después. En el lado derecho, para cada punto de la capa de puntos se agregó un nodo en la red vial: ingrese la descripción de la imagen aquí

Luego, en PostGIS, después de crear su ..._vertices_pgrtabla fuera de la red de carreteras, simplemente asigne sus puntos al vértice más cercano para que pueda usarlos en sus solicitudes de enrutamiento. Para esta tarea, puede hacer uso de la ST_ClosestPointfunción como lo hizo @Setraworks en su respuesta.

Las desventajas de este enfoque son:

  • La conexión de puntos con líneas debe hacerse en GRASS GIS
  • las rutas que se calculan pueden consistir en muchos componentes (dependiendo de la cantidad de puntos recién agregados)
  • adición dinámica de nuevos puntos no es posible

Este enfoque funciona bien si tiene un número definido de puntos para agregar a la red vial (como en el ejemplo de la pregunta con paradas de autobús).

¡Si alguien puede proporcionar un ejemplo de trabajo usando PostGIS, me encantaría leer sobre eso!

SchoGeo
fuente
0

Hay una publicación que analiza un problema similar, puede ver esa publicación en la siguiente ubicación: http://osdir.com/ml/qgis-user-gis/2011-11/msg00220.html

Ryan Garnett
fuente
Esto es solo una parte de una posible solución, porque después de ajustar los puntos a las líneas, los puntos se encuentran directamente en las líneas, pero aún no forman parte de la red.
Setraworks
Si espera obtener una respuesta que le brinde todos sus requisitos, puede sentirse decepcionado. Esto puede llevarte a la mitad, luego puedes concentrarte en la otra parte que te falta.
Ryan Garnett
Creo que tienes razón Ryan. Ya logré ajustar los puntos a las líneas, por lo que el siguiente paso será descubrir cómo dividir cadenas lineales con puntos en postgis. ¡Gracias por su ayuda hasta ahora!
Setraworks
Me alegro de poder ayudar. Hay herramientas que dividirán una línea con un punto, pero seguiré buscando una opción en PostGIS. Buena suerte
Ryan Garnett
@Setraworks, puede consultar la siguiente opción de PostGIS (ST_Split) postgis.net/docs/ST_Split.html . Puede dividir una línea con un punto, aquí está la explicación de PostGIS: la función admite la división de una línea por punto, una línea por línea, un polígono por línea. La geometría devuelta es siempre una colección.
Ryan Garnett