버스 정류장 (포인트)을 네트워크 계층 (OSM 데이터)에 연결해야합니다. 이 버스 정류장은 노선에 직접 놓여 있지 않으며 (스크린 샷 참조) 위치를 옮기지 않아야합니다. PostGIS, pgrouting 및 QGIS를 사용하고 있으며 소스 및 대상 열 등으로 네트워크를 이미 라우팅 할 수 있습니다.
주로 두 가지 일을하고 싶습니다.
- 가장 짧은 경로 분석을 사용하여 버스 정류장 사이의 거리를 가져옵니다.
- 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