Точки (автобусные остановки), которые не лежат на линиях (LINESTRING), к сети?

9

Мне нужно подключить автобусные остановки (точки) к сетевому уровню (данные OSM). Эти автобусные остановки не лежат прямо на линиях (см. Скриншот), и их местоположение не должно быть перемещено. Я использую PostGIS, pgrouting и QGIS, и сеть уже маршрутизируется с исходными и целевыми столбцами и т. Д.

введите описание изображения здесь

В основном я хочу сделать две вещи потом:

  1. Получение расстояния между автобусными остановками с использованием анализа кратчайшего пути.
  2. Создание изохрон с пешим расстоянием от автобусной остановки с использованием сети OSM.

Для получения точных значений необходимо, чтобы маршрут «начинался» и «останавливался» ближе всего к автобусным остановкам. Во многих случаях ближайший существующий узел будет слишком далеко, чтобы получить точные значения. Но не должно быть маршрутов к фактическому месту расположения автобусной остановки. В моем примере на рисунке вы можете видеть, как должна выглядеть маршрутизация между остановками.

Есть ли возможность автоматически вставлять в сеть новые узлы (LINESTRING), которые находятся ближе всего к автобусным остановкам, или есть возможность начать маршрутизацию на своего рода «фиктивной точке», которая устанавливается только для запроса (аналогично тому, что для дороги плагин графика в QGIS делает)?

Setraworks
источник

Ответы:

5

Первая часть решения такова:

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;

Это позволяет привязать опоры к линиям дорожной сети, как вы можете видеть на картинке, и работает довольно легко.

введите описание изображения здесь

Далее я попытаюсь разбить линии в местах расположения точек. После разделения строк я хочу снова использовать pgr_createTopology. После этого должна быть возможность создать запрос для определения ближайших узлов к рабочим площадкам, которые будут моими недавно сгенерированными узлами в «точках разделения».

Я был бы признателен, если бы кто-нибудь дал мне подсказку, как разделить линейную строку с точечными элементами в postgis, поскольку после того, как я посмотрел на подобные вопросы, кажется, что на данный момент не существует простого решения для этого.

Setraworks
источник
ST_Split (что-то вырезано, лезвие)
симплексио
1
добавление комментария, потому что я не проверял это вообще, syntac, вероятно, неправильно ... ... выберите *, st_split (a.lg, a.pg) из (выберите *, lines.g как lg, points.geom как pg из точек объединить строки в ST_intersect (p.geom, l.geom)) как разделенную коллекцию возвратов, так что вам все равно нужно извлечь из нее все строки ...
simplexio
2

Это мое полное решение. Это требует своего рода взлома для выполнения разделения: я получаю точки на линиях (способы использования терминологии OSM) ST_ClosestPoint, а затем буферизую их на очень маленьком расстоянии, чтобы разделение действительно заработало. В противном случае неточности / ошибки округления препятствовали расщеплению.

Проблема заключается в том, что он генерирует два разбиения в каждой строке на точку (из-за буферизации). Для моего использования это было хорошо, так как позже я перенаправил между точками разделения, ближайшими к исходным точкам, которые были вне линии, и это могла быть любая из двух точек разделения пересечения буфера линии.

Я начал с загрузки данных OSM и добавления их в 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

Разделение путей с использованием буфера:

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;

Создайте топологию, необходимую для маршрутизации с помощью 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
источник
Моей первой мыслью был и буфер. Но если вы можете получить «расстояние до ближайшего», буферизировать эту сумму, создать точку на этом пересечении ... тогда вы можете создать линию с конечными точками, состоящими из вашей исходной точки и «ближайшей» точки к ней.
Мокс
1

Поскольку я работаю над аналогичной задачей, я просто хотел рассказать о подходе, который я использую в настоящее время. При этом используется GRASS GIS, но, поскольку мои эксперименты с PostGIS пошли, довольно сложно добавить несколько новых точек в существующие LineStrings, разделив эти LineStrings в соответствующих местах - хотя я уверен, что есть удобное решение.

Теперь я использовал v.netфункцию GRASS GIS, используя опцию connect. Просто выберите input vector line layerи points layer. Существует возможность либо привязать точки к ближайшей точке на линиях, либо создать новые соединения между ближайшей точкой на линиях и новой точкой.

Вот изображение до и после. С правой стороны, для каждой точки слоя точек был добавлен узел в дорожной сети: введите описание изображения здесь

После этого в PostGIS, после создания ..._vertices_pgrтаблицы вне дорожной сети, просто назначьте свои точки ближайшей вершине, чтобы вы могли использовать их в своих запросах маршрутизации. Для этой задачи вы можете использовать ST_ClosestPointфункцию, которую сделал @Setraworks в своем ответе.

Недостатками этого подхода являются:

  • соединение точек с линиями должно быть сделано в GRASS GIS
  • рассчитанные маршруты могут состоять из множества компонентов (в зависимости от количества вновь добавленных точек)
  • динамическое добавление новых точек невозможно

Этот подход хорошо работает, если у вас есть определенное количество точек, которые нужно добавить в дорожную сеть (как в примере с автобусными остановками).

Если кто-нибудь может привести рабочий пример с использованием PostGIS, я бы хотел прочитать об этом!

SchoGeo
источник
0

Существует сообщение, в котором обсуждается аналогичная проблема. Вы можете увидеть это сообщение по следующему адресу: http://osdir.com/ml/qgis-user-gis/2011-11/msg00220.html.

Райан Гарнетт
источник
Это только часть возможного решения, потому что после привязки точек к линиям точки лежат непосредственно на линиях, но они все еще не являются частью сети.
Setraworks
Если вы ожидаете получить ответ, содержащий все ваши требования, вы можете быть разочарованы. Это может сделать вас на полпути, тогда вы можете сосредоточиться на другой части, которую вам не хватает.
Райан Гарнетт
Я думаю, что ты прав, Райан. Мне уже удалось привязать точки к линиям, поэтому следующим шагом будет выяснить, как разделить линии строк по точкам в postgis. Спасибо за вашу помощь до сих пор!
Setraworks
Рад, что смог помочь. Существуют инструменты, которые разбивают линию на точку, но я продолжу искать вариант в PostGIS. Удачи
Райан Гарнетт
@Setraworks. Возможно, вы захотите взглянуть на следующий параметр PostGIS (ST_Split) postgis.net/docs/ST_Split.html . Вы можете разбить линию на точку, вот объяснение из PostGIS: функция поддерживает разбиение на строку, на строку, на многоугольник за линией. Возвращенная геометрия всегда является коллекцией.
Райан Гарнетт