Bagaimana cara mereplikasi ArcGIS Intersect di PostGIS

8

Saya mencoba meniru proses ArcGIS ini di PostGIS: http://blogs.esri.com/esri/arcgis/2012/11/13/spaghetti_and_meatballs/ . Ini menjelaskan cara memecah titik-titik yang disangga menjadi poligon berdasarkan persimpangan mereka, menghitung jumlah lapisan, dan menghubungkannya dengan poligon untuk mengklasifikasikannya. Saya menggunakannya untuk membuat peta kerapatan titik kasar dengan vektor, dan hasilnya ternyata bagus untuk kumpulan data saya di ArcGIS. Namun, saya berjuang untuk membuat sesuatu yang bisa diterapkan di PostGIS di mana saya membutuhkannya untuk menghasilkan lapisan kepadatan titik dinamis untuk peta web.

Di ArcGIS, saya hanya menjalankan alat Intersect pada layer poin buffered saya untuk membuat bentuk yang saya butuhkan.

Di PostGIS, saya menjalankan kueri ini:

CREATE TABLE buffer_table AS SELECT a.gid AS gid, ST_Buffer(a.geo,.003) AS geo FROM public.pointTable a;

CREATE TABLE intersections AS SELECT a.gid AS gid_a, b.gid AS gid_b, ST_Intersection(a.geo,b.geo) AS geo FROM public.pointTable a, public.pointTable b WHERE ST_Intersects(a.geo, b.geo) AND a.gid < b.gid;

DELETE FROM intersections WHERE id_a = id_b;

Outputnya terlihat cukup identik dengan output ArcGIS, kecuali bahwa itu tidak memecah poligon ke tingkat yang sama yang diperlukan untuk peta kepadatan yang berarti. Berikut screenshot dari apa yang saya maksud:

ArcGIS PostGIS

ArcGIS di sebelah kiri, dan PostGIS di sebelah kanan. Agak sulit diceritakan, tetapi gambar ArcGIS menunjukkan poligon 'interior' yang dibuat di mana ketiga buffer berpotongan. Output PostGIS, di sisi lain, tidak membuat poligon interior dan malah membuat komponennya tetap utuh. Ini membuat tidak mungkin untuk memberikan klasifikasi untuk area interior hanya dengan 3 lapisan di atas satu sama lain dibandingkan dengan hanya 1 untuk bagian luar.

Adakah yang tahu fungsi PostGIS untuk memecah poligon ke bawah sejauh yang saya butuhkan? Atau, apakah ada yang tahu cara yang lebih baik untuk menghasilkan peta kerapatan titik dengan vektor di PostGIS?

mengais
sumber

Jawaban:

9

Anda dapat melakukan ini semua dalam satu langkah dengan merantai CTE bersama-sama, tetapi saya melakukannya dalam beberapa langkah sehingga saya bisa melihat hasil dalam QGIS saat saya berkembang.

Pertama, buat banyak titik acak untuk dikerjakan, menggunakan distribusi gaussian sehingga kita mendapatkan lebih banyak tumpang tindih di tengah.

create table pts as with 
    rands as (
        select generate_series as id, random() as u1, random() as u2 
        from generate_series(1,100))
select
      id,
      st_setsrid(st_makepoint(
            50 * sqrt(-2 * ln(u1)) * cos(2*pi()*u2), 
            50 * sqrt(-2 * ln(u1)) * sin(2*pi()*u2)),4326) as geom
from rands;

Sekarang buffer poin ke dalam lingkaran sehingga kami mendapatkan beberapa tumpang tindih.

create table circles as
    select id, st_buffer(geom, 10) as geom from pts;

Sekarang, ekstrak hanya batas-batas dari lingkaran. Jika Anda memiliki poligon berlubang, Anda harus menggunakan ST_DumpRings () dan mendapatkan lebih banyak kemewahan di sini. Saya punya poligon sederhana jadi saya curang. Setelah Anda memiliki batasan, persatukan mereka dengan diri mereka sendiri (sebenarnya setiap pekerjaan kecil yang kebetulan akan dilakukan) untuk memaksa mereka untuk mengangguk dan diduplikasi. (Ini sihir.)

create table boundaries as
    select st_union(st_exteriorring(geom)) as geom from circles;

Sekarang bangun kembali area menggunakan garis mengangguk. Ini adalah area yang rusak, dengan hanya satu poligon per area. Setelah poligonisasi, buang poligon individual dari output multipoligon.

create sequence polyseq;

create table polys as
    select 
        nextval('polyseq') as id, 
        (st_dump(st_polygonize(geom))).geom as geom 
    from boundaries;

Sekarang, tambahkan tempat untuk jumlah poligon dan isi dengan bergabung dengan centroid dari poligon cut-up kecil ke lingkaran asli, dan merangkum untuk setiap potongan kecil. Untuk set data yang lebih besar indeks pada tabel lingkaran setidaknya akan diperlukan untuk membuat hal-hal tidak terlalu lambat.

create index circles_gix on circles using gist (geom);

alter table polys add column count integer default 0;

update polys set count = p.count 
from (
    select count(*) as count, 
           p.id as id 
    from polys p 
    join circles c 
    on st_contains(c.geom, st_pointonsurface(p.geom)) 
    group by p.id
) as p
where p.id = polys.id;

Itu saja, Anda sekarang tidak memiliki poligon yang tumpang tindih, tetapi setiap poligon yang dihasilkan memiliki hitungan di atasnya yang mengatakan berapa banyak tumpang tindih yang diperhitungkan.

Paul Ramsey
sumber
Itu sangat mengesankan. Saya akhirnya menggunakan sedikit metode curang yang bekerja dan dengan dataset khusus saya (mungkin kurang intensif sumber daya juga, yang penting untuk proyek saya yang melibatkan pemetaan web). Saya akan memposting solusi saya sebagai metode alternatif untuk menghasilkan peta panas, tetapi ini adalah jawaban yang benar untuk pertanyaan yang saya ajukan.
scavok
2

Metode yang akhirnya saya gunakan adalah membuat kisi jala di bidang yang saya minati dengan "resolusi" yang cukup tinggi untuk ditata dan mencerminkan data ke tingkat yang wajar. Anda dapat membaca tentang fungsi jala di sini: Cara membuat kisi poligon reguler di PostGIS?

CREATE TABLE fishnet AS
SELECT * FROM ST_CreateFishnet(800,850,.0005,.0005,-104.9190,38.7588);

Ini menciptakan jala ikan dengan 800 baris, 850 kolom, yang panjang dan panjangnya 0,0005 radian (menggunakan proyeksi WGS84 dalam lat / panjang dan tingkat geografis yang cukup kecil sehingga distorsi dapat diabaikan - yaitu mereka semua terdistorsi lebih atau kurang sama ), dan kemudian koordinat untuk kiri bawah grid.

UPDATE fishnet SET geom = ST_SetSRID(geom,4326);
CREATE INDEX fishnet_geom ON fishnet USING gist (geom);
ANALYZE fishnet;

Karena ini menciptakan sejumlah besar poligon yang akan menjalankan kueri, saya membuat indeks dan memperbarui statistik. Ini mengurangi kueri khas saya dari 50+ detik menjadi 4-5 detik.

SELECT ST_Union(a.geom), a.count
FROM (SELECT count(*) as count, fishnet.geom as geom
    FROM fishnet, incidents
    WHERE ST_DWithin(incidents.geo,fishnet.geom,.002) AND (incidents.incidenttype = 'Burglary')
    GROUP BY fishnet.geom) a
WHERE a.count >= 3
GROUP BY a.count;

Subquery di sini menghitung jumlah insiden dalam 0,002 radian (sekitar 220 meter) dari setiap poligon kisi jaring, dan mengelompokkannya menurut kisi jaring. Ini secara efektif menghitung jumlah lingkaran yang tumpang tindih dengan resolusi kisi.

Kueri luar yang saya gunakan untuk Menyatukan nilai hitungan setiap poligon, dan membatasi hitungan ke 3 atau lebih besar. Meskipun serikat pekerja tidak sepenuhnya diperlukan dan merupakan bagian paling intensif sumber daya dari kueri, ini penting untuk pemetaan web karena ini secara efektif mengubah puluhan ribu poligon kisi, yang tidak berfungsi dengan baik saat melayani langsung ke pembuka layar, menjadi Multipolygons dari berbagai nilai hitung yang ada (biasanya beberapa lusin untuk data saya).

Membatasi nilai hitungan adalah kemampuan penting untuk memanaskan peta sehingga tidak terlalu banyak menggambarkan data sehingga tidak dapat menafsirkannya - ini juga memiliki utilitas tambahan untuk mempercepat kueri secara signifikan.

Hasil akhir: peta

mengais
sumber