Membangun poligon di atas area yang dapat dijangkau


10

Saat ini saya bekerja di bidang isochrones dan algoritma yang mendasarinya. Apa yang sekarang menyebabkan masalah bukanlah perhitungan jika isochrone itu sendiri, tetapi visualisasi hasilnya.
Hasil algoritma isochrone saya adalah titik dan ujung. Sebenarnya saya punya solusi yang berfungsi, tetapi untuk 3873 edge dan 1529 node sepertinya butuh waktu lama (sekitar 2,0 detik pada laptop Lenovo T440s saya yang berisi CPU Core i7 2015 dan SSD yang cukup cepat). Alih-alih detik saya ingin sesuatu yang lebih seperti msec :-).

Mungkin seseorang dapat membantu saya mengurangi waktu perhitungan yang dibutuhkan untuk membangun poligon yang memvisualisasikan area yang dapat dijangkau.

Tapi tunggu ... hal pertama yang pertama!
Berikut adalah visualisasi tepi yang saya adalah hasil perhitungan isochrone saya: Hasil perhitungan Isochrone (kerangka yang ada dari linestrings) Tepi ini disimpan dalam tabel database PostGIS dan merupakan linestrings sederhana.

Apa yang ingin saya perlihatkan kepada pengguna terlihat seperti ini: masukkan deskripsi gambar di sini Perhatikan area yang terputus di bagian paling selatan dan paling timur gambar. Ini harus digambar sebagai area terpisah (jadi tidak boleh ada penggabungan di sini :-))

Saat ini saya menggunakan permintaan ini:

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_MakePolygon(ST_ExteriorRing(ST_GeometryN(segments, generate_series(1, ST_NumGeometries(segments))))) AS polygons FROM (
        SELECT ST_Union(ST_Buffer("GEOMETRY", 20, 'quad_segs=2')) AS segments FROM my_edges AS a
    ) AS b
) AS c

Saya sudah melakukan beberapa percobaan dan saya juga membaca banyak dokumentasi, tetapi saya tidak dapat menemukan solusi yang lebih baik.
Di mata saya masalah besar adalah penggunaan ST_Union (seperti yang dinyatakan dalam dokumen fungsi ini bisa lambat). Hal yang sangat menarik adalah bahwa menggantinya dengan ST_Collect tampaknya memperlambat perhitungan ST_Buffer sehingga semua-dalam-semua permintaan berikut bahkan lebih lama, meskipun tidak mengisi area di antara tepi (hanya membuat buffer di sekitar garis ):

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_Buffer(ST_Collect(ST_LineMerge("GEOMETRY")), 20, 'quad_segs=2') AS polygons FROM my_edges AS a
) AS b

Ini membutuhkan sekitar 3,8 detik di sistem saya (jadi hampir dua kali lipat waktu). Kesimpulan pertama saya dari tolok ukur kecil ini adalah bahwa ST_Buffer tiba-tiba lambat ketika menyangkut MultiLineStrings (bahkan lebih lambat daripada saat membuat buffer untuk setiap baris dan menggabungkan buffer - yang menurut saya aneh)

Saya juga mencoba menggunakan alpha-bentuk (menggunakan implementasi dari pgRouting), tetapi karena tidak ada nilai alpha untuk mengatur (dan sebenarnya saya tidak akan benar-benar sekarang ke nilai yang mengatur nilai seperti itu) Saya hanya mendapatkan satu poligon hebat ( jadi saya akan kehilangan daerah di bagian paling selatan dan timur sebagai wilayah terpisah yang bukan yang saya inginkan).
ST_Polygonize (yang merupakan hal pertama yang muncul di pikiran saya) tidak menghasilkan hasil yang dapat digunakan, tapi mungkin saya melewatkan sesuatu di sini ...

Apakah ada cara yang lebih baik untuk membuat area yang diperlihatkan di PostGIS? Mungkin juga dengan menggunakan kode java (jts) atau kode javascript sisi klien (jsts)? Sebenarnya saya bisa hidup dengan kehilangan beberapa detail selama area yang ditunjukkan dalam hasil saya tetap terpisah dan perhitungannya menjadi (jauh) lebih cepat.


Tidak bisakah Anda menggunakan ST_Exteriorring (ST_Dump (ST_Union (ST_Buffer (geom, ....))). Anda mungkin perlu menguji untuk Linestrings yang kadang-kadang dihasilkan dari ST_Union setelah buffer, tetapi itu mudah dengan ST_GeometryType (geom). Sejauh menggunakan Java atau jsts, Anda bisa, tetapi tidak mungkin lebih cepat, mengingat bahwa sebagian besar fungsi Postgis (GEOS) adalah C / C ++ port JTS di tempat pertama
John Powell

Anda benar, ini berfungsi, tetapi sebenarnya itu tidak lebih cepat (membutuhkan ~ 3.1secs, saat menggunakan GeometryN membutuhkan 2secs). Inilah yang saya gunakan: SELECT ST_AsGeoJson (ST_Transform (ST_Exteriorring ((ST_Dump (ST_Union (ST_Buffer ("GEOMETRY", 20)))). Geom), 4326)) DARI my_edges;
Nikolaus Krismer

@ john-barça: Oh .. Saya mengacaukan quad_segs = 2 bagian dalam ST_Buffer ketika mencoba pendekatan Anda ... dengan itu ubah queries even (keduanya sekitar 2secs). Namun, ini masih sangat lambat (di mata saya), apakah ada cara lain untuk mencobanya?
Nikolaus Krismer

Masalah menarik .... apakah Anda ingin membagikan beberapa data pengujian?
dbaston

Jika ini membantu, saya senang berbagi beberapa data. Semua hal yang saya lakukan di sini adalah open-source, jadi ini seharusnya tidak menjadi masalah besar. Hal pertama yang perlu diperhatikan: Aplikasi web untuk pengujian terletak di dbis-isochrone.uibk.ac.at:8080/testing . Informasi lebih lanjut tentang hal-hal yang saya kerjakan dapat ditemukan di dbis-isochrone.uibk.ac.at . Di bagian "tautan" situs web ada beberapa referensi lebih lanjut (termasuk beberapa data uji)
Nikolaus Krismer

Jawaban:


5

Menyingkirkan serialisasi GeoJSON, yang berikut ini memakan waktu sekitar 6,3 detik pada laptop saya:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(geom, 20, 2)))).geom))
FROM bz_edges

Melihat data di OpenJUMP, saya perhatikan sedikit detail di segmen jalan, relatif terhadap tingkat detail yang diinginkan dalam output. Tampaknya bahkan penyederhanaan on-the-fly dari baris-baris ini dapat menghasilkan percepatan besar di PostGIS:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(ST_Simplify(geom, 10), 20, 2)))).geom))
FROM bz_edges

yang membawa segalanya ke 2,3 detik. Saya pikir saya mungkin bisa melakukan lebih baik dengan menyimpan geometri umum dalam kolom terpisah, daripada menghitungnya dengan cepat, tetapi itu sebenarnya tidak memberikan manfaat tambahan.

Tergantung pada seberapa banyak kode yang ingin Anda tulis, Anda hampir dapat dipastikan melakukan yang lebih baik di Jawa, jika tidak ada yang lain karena Anda dapat memanfaatkan banyak inti. (Untuk apa nilainya, JTS melakukan operasi di atas dalam 2,8 detik). Salah satu pendekatan mungkin untuk memperluas CascadedPolygonUnionuntuk membuat beberapa operasi serikat terjadi secara paralel. (pembaruan - di sini adalah ParallelCascadedPolygonUnion )

Saya perhatikan dalam data sampel bahwa ujung-ujungnya disimpan dengan referensi ke titik awal dan akhir, yaitu, Anda memiliki grafik yang dibuat sebelumnya. Saya menduga Anda dapat menghasilkan poligon ini jauh lebih cepat jika Anda bekerja dari grafik daripada menggunakan operasi geometri generik. Misalnya, saya pikir Anda dapat melakukannya seperti ini:

  1. mengidentifikasi komponen yang terhubung dari grafik
  2. untuk setiap komponen yang terhubung, cari simpul dengan koordinat X minimum (dijamin berada di luar komponen)
  3. jelajahi tepi-tepi komponen, selalu belok kiri (atau kanan) bila memungkinkan. Ini akan memberi Anda cincin eksterior setiap komponen.
  4. poligonkan cincin eksterior dan penyangga dengan tepat.

Terima kasih ... penyederhanaan adalah peningkatan yang hebat dan bahkan "sederhana". Butuh waktu yang dibutuhkan di laptop saya ke 1.5sec. Itu bukan tempat yang saya inginkan, tetapi sedikit lebih baik.
Nikolaus Krismer

Mengenai solusi yang Anda sarankan (poin 1-4). Kedengarannya juga sangat sederhana dan patut dicoba. Saya memikirkan sesuatu yang serupa, tetapi saya terjebak di point1 (sangat awal :-)). Bagaimana seseorang mengidentifikasi komponen yang terhubung (satu-satunya hal yang dapat saya pikirkan adalah permintaan rekursif yang mungkin juga sangat lambat).
Nikolaus Krismer

@NikolausKrismer Saya menggunakan JGraphT dan alat tenun untuk tugas-tugas seperti ini. Jika Anda menulis metode grafik sendiri sebagai gantinya (bukan ide yang buruk untuk kinerja terbaik), pencarian mendalam-pertama akan menemukan Anda komponen. (Anda dapat menemukannya di PostGIS 2.2 yang akan datang dengan ST_ClusterIntersectingtetapi saya pikir Anda akan menginginkan segala jenis pemrosesan grafik terjadi di luar basis data, jadi ini mungkin tidak berguna).
dbaston

ini adalah beberapa petunjuk bagus. Saya melihat JGraphT dan ini pasti bisa membantu menyelesaikan masalah saya. Namun, saya juga melihat Postgis 2.2 dan fungsi ST_ClusterIntersecting -> dibutuhkan sekitar 200-250msec untuk mengidentifikasi berbagai kluster dalam kasus di atas. Tidak apa-apa bagi saya (JGraphT tentu bisa lebih baik). Sekarang saya harus berurusan dengan membuat exteriorRing (ST_ExteriorRing gagal, karena ST_MakePolygon mengatakan tautan saya bukan shell)
Nikolaus Krismer

Saya melihat dua komplikasi: (a) Anda tidak hanya perlu cincin eksterior, tetapi juga setiap segmen yang memanjang keluar dari cincin itu, dan (b) sepertinya garis Anda tidak benar-benar berpotongan di beberapa persimpangan. Anda harus memperbaiki (b) jika Anda akan mencoba membuat geometri dari hasil jalan grafik.
dbaston
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.