라인 (LINESTRING)에 있지 않은 포인트 (버스 정류장)를 네트워크에 연결합니까? 두 가지 일을하고 싶습니다. 가장 짧은 경로

버스 정류장 (포인트)을 네트워크 계층 (OSM 데이터)에 연결해야합니다. 이 버스 정류장은 노선에 직접 놓여 있지 않으며 (스크린 샷 참조) 위치를 옮기지 않아야합니다. PostGIS, pgrouting 및 QGIS를 사용하고 있으며 소스 및 대상 열 등으로 네트워크를 이미 라우팅 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

주로 두 가지 일을하고 싶습니다.

  1. 가장 짧은 경로 분석을 사용하여 버스 정류장 사이의 거리를 가져옵니다.
  2. OSM 네트워크를 사용하여 버스 정류장에서 걸어서 갈 수있는 이소 크론 생성.

정확한 값을 얻으려면 버스 정류장에 가장 근접한 라우팅 ‘시작’및 ‘정지’가 필요합니다. 대부분의 경우 가장 가까운 기존 노드가 너무 멀어 정확한 값을 얻을 수 없습니다. 그러나 버스 정류장의 실제 지점 위치로 라우팅해서는 안됩니다. 그림의 예에서 정류장 사이의 경로가 어떻게 보이는지 볼 수 있습니다.

버스 정류장에 가장 가까운 네트워크에 새로운 노드를 자동으로 삽입 할 가능성이 있습니까 (LINESTRING) 또는 쿼리 전용으로 설정된 일종의 ‘더미 포인트’에서 라우팅을 시작할 수 있습니까 (도로와 유사) QGIS의 그래프 플러그인)?



답변

솔루션의 첫 번째 부분은 다음과 같습니다.

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에서 포인트 피처로 선 스트링을 나누는 방법에 대한 힌트를 얻은 사람에게 감사 할 것입니다.


답변

이것이 나의 완전한 해결책입니다. 분할을 수행하기위한 일종의 해킹이 필요합니다. 나는를 사용하여 선상의 점 (방법, 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');


답변

비슷한 작업을하고 있기 때문에 현재 사용중인 접근 방식에 대해서만 이야기하고 싶었습니다. 이것은 GRASS GIS를 사용하지만 PostGIS에 대한 실험이 진행되는 한 해당 위치에서 해당 LineString을 분할하여 기존 LineString에 여러 개의 새로운 점을 추가하는 것은 매우 복잡합니다.

이제 v.net옵션을 사용하여 GRASS GIS 기능을 사용했습니다 connect. input vector line layer그리고를 선택하십시오 points layer. 점을 선에서 가장 가까운 점으로 스냅하거나 선에서 가장 가까운 점과 새 점 사이에 새 연결을 작성하는 옵션이 있습니다.

여기 전후 이미지가 있습니다. 오른쪽에는 포인트 레이어의 각 포인트에 대해 도로 네트워크의 노드가 추가되었습니다.
여기에 이미지 설명을 입력하십시오

이후 PostGIS ..._vertices_pgr에서 도로 네트워크 외부에 테이블 을 생성 한 후 포인트를 가장 가까운 정점에 지정하면 라우팅 요청에 사용할 수 있습니다. 이 작업을 위해 ST_ClosestPoint@Setraworks의 답변에서 수행 한 기능을 사용할 수 있습니다 .

이 접근법의 단점은 다음과 같습니다.

  • GRASS GIS에서 점과 선을 연결해야합니다.
  • 계산 된 경로는 여러 개의 구성 요소로 구성 될 수 있습니다 (새로 추가 된 포인트의 수량에 따라 다름)
  • 새로운 포인트를 동적으로 추가 할 수 없음

이 방법은 버스 정류장에 관한 질문의 예에서와 같이 도로망에 추가 할 정의 된 수의 포인트가있는 경우에 잘 작동합니다.

누구든지 PostGIS를 사용하여 실제 예제를 제공 할 수 있다면 그것에 대해 읽고 싶습니다!


답변

비슷한 문제를 다루는 게시물이 있습니다. 다음 위치에서 해당 게시물을 볼 수 있습니다. http://osdir.com/ml/qgis-user-gis/2011-11/msg00220.html


답변