将不在线上的点(公交车站)(LINESTRING)连接到网络吗?


9

我需要将巴士站(点)连接到网络层(OSM数据)。这些公交车站不直接位于线路上(请参见屏幕截图),也不应移动其位置。我使用PostGIS,pgrouting和QGIS,并且网络已经可以通过源列和目标列等进行路由。

在此处输入图片说明

我主要想在事后做两件事:

  1. 使用最短路径分析获得公交车站之间的距离。
  2. 使用OSM网络在距公交车站步行距离处创建等时线。

为了获得准确的值,有必要使路线“开始”和“停止”最接近公交车站。在许多情况下,最接近的现有节点将距离太远而无法获得准确的值。但是,不应有通往公交车站实际位置的路线。在我在图片上的示例中,您可以看到停靠点之间的路线应该是什么样子。

是否有可能将最靠近公交车站的新节点自动插入网络(LINESTRING),或者是否可以在仅针对查询设置的“虚拟点”上开始路由(类似于道路QGIS中的图形插件吗?

Answers:


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中使用点特征分割线串的提示,我将不胜感激,因为在我研究了类似的问题之后,目前似乎还没有一个简单的解决方案。


ST_Split(somethingtocut,刀片)
simplexio 2014年

1
添加注释,因为我根本没有测试过,语法可能是错误的……...从中选择*,st_split(a.lg,a.pg)(从点选择*,lines.g为lg,points.geom为pg联接ST_intersect(p.geom,l.geom)上的行,但拆分返回集合,因此您仍然需要从中删除所有行...
simplexio 2014年

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');

我的第一个想法就是缓冲。但是,如果您可以得到“到最近的距离”,缓冲该数量,在该相交处创建一个点,那么您可以创建一条线,其端点包括原始点和指向该点的“最近”点。
Mox

1

由于我正在从事类似的任务,所以我只想介绍一下我目前使用的方法。这利用了GRASS GIS,但是就我对PostGIS的实验而言,通过在相应位置拆分这些LineString来向现有LineString添加多个新点是相当复杂的-尽管我确信有一个方便的解决方案。

我现在v.net通过选项使用了GRASS GIS 功能connect。只需选择input vector line layerpoints layer。可以选择将点捕捉到直线上的最近点,或者在直线上的最近点和新点之间创建新的连接。

这是一个前后的图像。在右侧,为点图层的每个点添加了路网上的一个节点: 在此处输入图片说明

之后,在PostGIS中,在..._vertices_pgr道路网络之外创建表格后,只需将点分配到最近的顶点即可,以便可以在路由请求中使用它们。对于此任务,您可以使用ST_ClosestPoint@Setraworks在其答案中完成的功能。

这种方法的缺点是:

  • 点和线的连接必须在GRASS GIS中完成
  • 计算出的路线可能包含许多组成部分(取决于新添加的点数)
  • 动态添加新点是不可能的

如果您要在路网中添加定义数量的点(例如在带有公交车站的问题示例中),则此方法效果很好。

如果有人可以使用PostGIS提供一个可行的示例,那么我很乐意阅读!


0

有一篇文章讨论了类似的问题,您可以在以下位置看到该文章:http : //osdir.com/ml/qgis-user-gis/2011-11/msg00220.html


这只是可能解决方案的一部分,因为将点捕捉到线上之后,这些点直接位于线上,但是它们仍然不是网络的一部分。
Setraworks 2014年

如果您期望得到可以满足您所有要求的答案,那么您可能会感到失望。这可能会使您半途而废,然后可以专注于丢失的另一部分。
瑞安·加内特

我认为您是对的Ryan。我已经设法将点捕捉到直线上,所以下一步将是找出如何在postgis中使用点分割线串。感谢您一直以来的帮助!
Setraworks 2014年

很高兴我能帮上忙。有一些工具可以用点将线分开,但是我将继续在PostGIS中寻找一个选项。祝您好运
Ryan Garnett 2014年

@Setraworks,您可能需要查看以下PostGIS选项(ST_Split)postgis.net/docs/ST_Split.html。您可以用点分割线,这是PostGIS的解释:该功能支持按点分割线,按线分割线,按线分割多边形。返回的几何图形始终是一个集合。
瑞安·加内特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.