Đây là giải pháp đầy đủ của tôi. Nó liên quan đến một loại hack để thực hiện việc phân tách: Tôi lấy điểm trên các dòng (cách, sử dụng thuật ngữ OSM) bằng cách sử dụng ST_ClosestPoint
, và sau đó đệm chúng theo một khoảng cách rất nhỏ để thực hiện việc chia tách thực sự hoạt động. Mặt khác, lỗi không chính xác / làm tròn đã ngăn cản việc chia tách.
Điều này có vấn đề là nó tạo ra hai phần tách trên mỗi dòng trên mỗi điểm (vì bộ đệm). Đối với việc sử dụng của tôi, điều này là tốt, vì sau này tôi đã định tuyến giữa các điểm phân tách gần nhất với các điểm ban đầu, nằm ngoài đường và nó có thể là một trong hai điểm phân tách của giao lộ bộ đệm dòng.
Tôi đã bắt đầu bằng cách tải xuống dữ liệu OSM và đưa nó vào 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
Tách các cách sử dụng bộ đệm:
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;
Tạo cấu trúc liên kết cần thiết để định tuyến với 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');