Menghubungkan titik (halte bus), yang tidak terletak pada jalur (LINESTRING), ke jaringan?

9

Saya perlu menghubungkan halte bus (titik) ke lapisan jaringan (data OSM). Halte bus ini tidak terletak langsung di garis (lihat tangkapan layar) atau lokasinya tidak boleh dipindahkan. Saya menggunakan PostGIS, pgrouting dan QGIS dan jaringan sudah dapat dirutekan dengan sumber dan kolom target dll.

masukkan deskripsi gambar di sini

Terutama saya ingin melakukan dua hal setelahnya:

  1. Mendapatkan jarak antara halte bus menggunakan analisis jalur terpendek.
  2. Membuat isochrones dengan jarak berjalan kaki dari halte menggunakan jaringan OSM.

Untuk mendapatkan nilai yang tepat perlu, bahwa perutean 'dimulai' dan 'berhenti' paling dekat dengan halte bus. Dalam banyak kasus, simpul terdekat yang ada akan terlalu jauh untuk mendapatkan nilai yang tepat. Tetapi seharusnya tidak ada rute ke lokasi titik sebenarnya dari halte bus. Dalam contoh saya pada gambar, Anda dapat melihat seperti apa perutean antara berhenti.

Apakah ada kemungkinan untuk memasukkan node baru secara otomatis ke jaringan (LINESTRING) yang paling dekat dengan halte bus atau apakah mungkin untuk memulai routing pada semacam 'dummy point' yang diatur hanya untuk permintaan (mirip dengan apa jalannya) plugin grafik di QGIS tidak)?

Setraworks
sumber

Jawaban:

5

Bagian pertama dari solusinya adalah ini:

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;

Ini menghentikan busstop ke garis-garis jaringan jalan seperti yang Anda lihat dalam gambar dan bekerja dengan sangat mudah.

masukkan deskripsi gambar di sini

Selanjutnya saya akan mencoba membagi garis di lokasi titik. Setelah memisahkan baris, saya ingin menggunakan pgr_createTopology lagi. Setelah itu, dimungkinkan untuk membuat kueri untuk mengetahui node terdekat dengan busstop, yang kemudian akan menjadi node yang baru saya buat di 'splitpoints'.

Saya akan berterima kasih jika seseorang memiliki petunjuk untuk saya bagaimana membagi linestring dengan fitur titik di postgis, karena setelah saya melihat pertanyaan serupa sepertinya tidak ada solusi yang mudah untuk itu saat ini.

Setraworks
sumber
ST_Split (somethingtocut, blade)
simplexio
1
menambahkan komentar karena saya tidak menguji ini sama sekali, syntac mungkin salah ... ... pilih *, st_split (a.lg, a.pg) dari (pilih *, lines.g sebagai lg, points.geom sebagai pg dari poin gabungkan baris pada ST_intersect (p.geom, l.geom)) sebagai koleksi return yang terpecah sehingga Anda masih perlu mengeluarkan semua baris darinya ...
simplexio
2

Ini solusi lengkap saya. Ini melibatkan semacam peretasan untuk menyelesaikan pemisahan: Saya mendapatkan poin pada garis (cara, menggunakan terminologi OSM) menggunakan ST_ClosestPoint, dan kemudian buffer mereka dengan jarak yang sangat kecil untuk mendapatkan pemisahan agar benar-benar berfungsi. Kalau tidak, kesalahan pembulatan / pembulatan mencegah pemisahan.

Ini memiliki masalah yang menghasilkan dua split pada setiap baris per titik (karena buffering). Untuk penggunaan saya ini baik-baik saja, karena kemudian saya diarahkan antara titik-titik pemisahan terdekat dengan titik-titik asli, yang berada di luar garis, dan itu bisa berupa salah satu dari dua titik pemisahan dari persimpangan garis-penyangga.

Saya mulai dengan mengunduh data OSM dan memasukkannya ke 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

Memisahkan cara menggunakan buffer:

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;

Buat topologi yang diperlukan untuk perutean dengan 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
sumber
Pikiran pertama saya adalah penyangga juga. Tetapi jika Anda bisa mendapatkan 'jarak ke terdekat', buffer jumlah itu, buat titik di persimpangan itu ... maka Anda bisa membuat garis dengan titik akhir yang terdiri dari titik asli Anda dan titik 'terdekat' ke sana.
Mox
1

Karena saya mengerjakan tugas yang sama, saya hanya ingin memberi tahu tentang pendekatan yang saya gunakan saat ini. Ini menggunakan GRASS GIS, tetapi sejauh percobaan saya dengan PostGIS berjalan, cukup rumit untuk menambahkan beberapa poin baru ke LineStrings yang ada dengan membagi LineStrings tersebut di lokasi masing-masing - walaupun saya yakin ada solusi yang mudah.

Saya sekarang memanfaatkan fungsi GRASS GIS v.netmenggunakan opsi connect. Cukup pilih input vector line layerdan points layer. Ada opsi untuk mengambil titik ke titik terdekat pada garis, atau untuk membuat koneksi baru antara titik terdekat pada garis dan titik baru.

Berikut ini adalah gambar sebelum dan sesudah. Di sisi kanan, untuk setiap titik lapisan poin ditambahkan node di roadnetwork: masukkan deskripsi gambar di sini

Setelah itu di PostGIS, setelah membuat ..._vertices_pgrtabel Anda dari roadnetwork, tetapkan saja poin Anda ke simpul terdekat sehingga Anda dapat menggunakannya dalam permintaan perutean Anda. Untuk tugas ini Anda dapat menggunakan ST_ClosestPointfungsi seperti yang dilakukan oleh @Setraworks dalam jawabannya.

Kerugian dari pendekatan ini adalah:

  • menghubungkan titik dengan garis harus dilakukan dalam GRASS GIS
  • rute yang dihitung mungkin terdiri dari banyak komponen (tergantung pada jumlah poin yang baru ditambahkan)
  • penambahan dinamis dari poin baru tidak dimungkinkan

Pendekatan ini berfungsi dengan baik jika Anda memiliki jumlah poin yang pasti untuk ditambahkan ke roadnetwork (seperti dalam contoh pertanyaan dengan halte bus).

Jika ada yang bisa memberikan contoh kerja menggunakan PostGIS saya akan senang membaca tentang itu!

SchoGeo
sumber
0

Ada posting yang membahas masalah serupa, Anda dapat melihat posting itu di lokasi berikut: http://osdir.com/ml/qgis-user-gis/2011-11/msg00220.html

Ryan Garnett
sumber
Ini hanya bagian dari solusi yang mungkin, karena setelah menjepret titik ke garis, titik-titik tersebut terletak langsung pada garis, tetapi mereka masih bukan bagian dari jaringan.
Setraworks
Jika Anda mengharapkan untuk mendapatkan jawaban yang menyediakan semua kebutuhan Anda, Anda mungkin kecewa. Ini mungkin membuat Anda setengah jalan, maka Anda dapat fokus pada bagian lain yang hilang.
Ryan Garnett
Saya pikir Anda benar, Ryan. Saya sudah berhasil mengambil poin ke garis, jadi langkah selanjutnya adalah mencari cara untuk membagi linestrings dengan poin di postgis. Terima kasih atas bantuan Anda sejauh ini!
Setraworks
Senang bisa membantu. Ada alat yang akan membagi garis dengan sebuah titik, tetapi saya akan terus mencari opsi di PostGIS. Semoga beruntung
Ryan Garnett
@Setraworks Anda mungkin ingin melihat opsi PostGIS berikut (ST_Split) postgis.net/docs/ST_Split.html . Anda dapat membagi satu baris dengan satu titik, berikut ini penjelasan dari PostGIS: Fungsi ini mendukung pemisahan garis demi titik, garis demi garis, poligon demi baris. Geometri yang dikembalikan selalu merupakan koleksi.
Ryan Garnett