Saya menggunakan PL/R
fungsi dan PostGIS
untuk menghasilkan poligon voronoi di sekitar serangkaian poin. Fungsi yang saya gunakan didefinisikan di sini . Ketika saya menggunakan fungsi ini pada dataset tertentu saya mendapatkan pesan kesalahan berikut:
Error : ERROR: R interpreter expression evaluation error
DETAIL: Error in pg.spi.exec(sprintf("SELECT %3$s AS id,
st_intersection('SRID='||st_srid(%2$s)||';%4$s'::text,'%5$s')
AS polygon FROM %1$s WHERE st_intersects(%2$s::text,'SRID='||st_srid(%2$s)||';%4$s');",
:error in SQL statement : Error performing intersection: TopologyException: found non-noded
intersection between LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465
264611, 594406 286813) at 568465.05533706467 264610.82749605528
CONTEXT: In R support function pg.spi.exec In PL/R function r_voronoi
Dari memeriksa bagian ini dari pesan kesalahan:
Error performing intersection: TopologyException: found non-noded intersection between
LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465 264611, 594406 286813)
at 568465.05533706467 264610.82749605528
Seperti inilah masalah yang tercantum di atas:
Saya awalnya berpikir bahwa pesan ini mungkin disebabkan oleh adanya titik-titik yang identik, dan mencoba menyelesaikannya dengan menggunakan st_translate()
fungsi, yang digunakan dengan cara berikut:
ST_Translate(geom, random()*20, random()*20) as geom
Ini memang memperbaiki masalah, tetapi kekhawatiran saya adalah bahwa saya sekarang menerjemahkan semua poin hingga ~ 20m ke arah x / y. Saya juga tidak tahu berapa jumlah terjemahan yang sesuai. Misalnya, dalam dataset ini melalui coba-coba a 20m * random number
adalah ok, tapi bagaimana saya bisa tahu apakah ini perlu lebih besar?
Berdasarkan gambar di atas saya pikir masalahnya adalah bahwa titik tersebut bersinggungan dengan garis sementara algoritma mencoba untuk memotong titik dengan poligon. Saya tidak yakin apa yang harus saya lakukan untuk memastikan bahwa intinya ada dalam poligon, daripada berpotongan dengan garis. Kesalahan terjadi pada baris ini:
"SELECT
%3$s AS id,
st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'') AS polygon
FROM
%1$s
WHERE
st_intersects(%2$s::text,''SRID=''||st_srid(%2$s)||'';%4$s'');"
Saya telah membaca pertanyaan sebelumnya, Apa itu "persimpangan non-mengangguk"? untuk mencoba lebih memahami masalah ini, dan akan sangat menghargai saran tentang cara terbaik untuk menyelesaikannya.
WHERE ST_IsValid(p.geom)
untuk memfilter poin pada awalnya.Jawaban:
Dalam pengalaman saya, masalah ini hampir selalu disebabkan oleh:
Pendekatan "nudge" dari
ST_Buffer
solusi memungkinkan Anda lolos dengan # 2, tetapi apa pun yang dapat Anda lakukan untuk menyelesaikan penyebab mendasar ini, seperti menjepitkan geometri Anda ke kisi 1e-6, akan membuat hidup Anda lebih mudah. Geometri buffer biasanya baik untuk perhitungan menengah seperti area tumpang tindih, tetapi Anda harus berhati-hati mempertahankannya karena mereka dapat membuat masalah Anda yang dekat tapi tidak terlalu buruk dalam jangka panjang.Kemampuan penanganan pengecualian PostgreSQL memungkinkan Anda menulis fungsi wrapper untuk menangani kasus-kasus khusus ini, buffering hanya bila diperlukan. Ini contoh untuk
ST_Intersection
; Saya menggunakan fungsi serupa untukST_Difference
. Anda harus memutuskan apakah buffering dan potensi pengembalian poligon kosong dapat diterima dalam situasi Anda.Manfaat lain dengan pendekatan ini adalah Anda dapat menentukan geometri yang sebenarnya menyebabkan masalah Anda; cukup tambahkan beberapa
RAISE NOTICE
pernyataan diEXCEPTION
blok untuk menghasilkan WKT atau sesuatu yang lain yang akan membantu Anda melacak masalahnya.sumber
Melalui banyak trial and error akhirnya saya menyadari bahwa hasil
non-noded intersection
dari masalah persimpangan diri. Saya menemukan utas yang disarankan menggunakanST_buffer(geom, 0)
dapat digunakan untuk memperbaiki masalah (meskipun itu membuatnya jauh lebih lambat secara keseluruhan). Saya kemudian mencoba menggunakanST_MakeValid()
dan ketika diterapkan langsung ke geometri sebelum fungsi lainnya. Ini sepertinya memperbaiki masalah dengan kuat.Saya telah menandai ini sebagai jawaban karena tampaknya merupakan satu-satunya pendekatan yang memperbaiki masalah saya.
sumber
Saya mengalami masalah yang sama (Postgres 9.1.4, PostGIS 2.1.1), dan satu-satunya hal yang berhasil bagi saya adalah membungkus geometri dengan buffer yang sangat kecil.
ST_MakeValid
tidak bekerja untuk saya, juga tidak kombinasiST_Node
danST_Dump
. Buffer tampaknya tidak mengakibatkan penurunan kinerja, tetapi jika saya membuatnya lebih kecil saya masih menerima kesalahan persimpangan non-mengangguk.Jelek, tapi berhasil.
Memperbarui:
Strategi ST_Buffer tampaknya bekerja dengan baik, tapi saya mengalami masalah di mana ia menghasilkan kesalahan saat casting geometri ke geografi. Sebagai contoh, jika suatu titik awalnya di -90.0, dan buffered oleh 0,0000001, sekarang di -90,0000001, yang merupakan geografi yang tidak valid.
Ini berarti bahwa meskipun
ST_IsValid(geom)
sudaht
,ST_Area(geom::geography)
dikembalikanNaN
untuk banyak fitur.Untuk menghindari masalah persimpangan non-mengangguk, sambil mempertahankan geografi yang valid, saya akhirnya menggunakan
ST_SnapToGrid
seperti itusumber
Dalam postgis, ST_Node harus memutus serangkaian garis di persimpangan, yang seharusnya menyelesaikan masalah persimpangan tanpa mengangguk. Membungkus ini dalam ST_Dump menghasilkan array komposit dari garis yang terputus.
Sedikit terkait, ada presentasi PostGIS yang luar biasa: Kiat untuk Pengguna Kuat yang dengan jelas menguraikan masalah dan solusi semacam ini.
sumber
ST_Node
danST_Dump
? Saya membayangkan saya perlu menggunakannya di dekat bagian fungsi ini, tetapi saya tidak yakin:st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'')
inst_node
sini - dapatkah saya menggunakannya sebelumnyast_intersection
?Dalam pengalaman saya, saya memecahkan
non-noded intersection
kesalahan saya dengan menggunakan fungsi St_SnapToGrid yang memecahkan masalah memiliki presisi tinggi dalam koordinat titik puncak poligon.sumber