PostGIS ST_Interection of poligon dapat mengembalikan garis

9

Saat memotong poligon dari satu tabel dengan poligon di yang lain, ST_Intersection dapat mengembalikan serangkaian hasil yang dapat ditangani dengan ST_Dump. Beberapa geometri yang dikembalikan tidak harus ST_Polygon tetapi juga ST_LineString (mungkin juga sebuah titik). Jadi saat menjalankan kueri

INSERT INTO c (geom)
  (SELECT (ST_Dump(ST_Intersection(a.geom,b.geom))).geom
  FROM a INNER JOIN b ON ST_Intersects(a.geom, b.geom));

ketika mencoba mengisi tabel "c" dengan poligon terpotong, ia gagal dengan ERROR: Tipe geometri (LineString) tidak cocok dengan tipe kolom (Poligon)

Saya melakukan pernyataan SELECT bersarang lain sehingga hanya geometri poligon yang datang, seperti:

INSERT INTO c (geom)
  (SELECT geom FROM
    (SELECT (ST_Dump(ST_Intersection(a.geom,b.geom))).geom
    FROM a INNER JOIN b ON ST_Intersects(a.geom, b.geom))) AS cl
    WHERE ST_GeometryType(cl.geom)='ST_Polygon');

Karena ini agak rumit saya bertanya-tanya apakah ada solusi yang lebih elegan untuk menjatuhkan geometri yang tidak valid?

Robert Špendl
sumber
BTW, saya meletakkan <! - bahasa: lang-sql -> sebelum blok kode tetapi masih tidak ada highligting. Ada petunjuk untuk pemula?
Robert Špendl
Untuk memformat kode, cukup sisipkan, pilih dan gunakan tombol Contoh Kode di {}atas jendela pengeditan Pertanyaan.
PolyGeo
Hm, saya melakukan itu, kode itu ditandai sebagai "kode", tetapi kata kunci masih belum berwarna.
Robert Špendl
Saya biasanya tidak mencoba untuk mempriseifikasi kode SQL di sini, tetapi saya baru saja menemukan posting Meta yang terlihat berguna di meta.stackexchange.com/questions/90521/… - apakah Anda meninggalkan "garis kosong antara komentar dan kode"?
PolyGeo
Perpotongan dua geometri dapat menghasilkan semua jenis geometri, jadi saya pikir solusi Anda saat ini adalah yang paling langsung.
Mike T

Jawaban:

9

Ini mungkin tempat yang bagus untuk menggunakan fungsi SQL-language. Berikut ini yang cepat yang dapat digunakan untuk situasi ini:

CREATE OR REPLACE FUNCTION PolygonalIntersection(a geometry, b geometry)
RETURNS geometry AS $$
SELECT ST_Collect(geom)
FROM 
(SELECT (ST_Dump(ST_Intersection(a, b))).geom 
UNION ALL
-- union in an empty polygon so we get an 
-- empty geometry instead of NULL if there
-- is are no polygons in the intersection
SELECT ST_GeomFromText('POLYGON EMPTY')) SQ
WHERE ST_GeometryType(geom) = 'ST_Polygon';
$$ LANGUAGE SQL;

Ini akan mempertahankan komponen poligonal dari persimpangan, tetapi membuang semua yang lainnya. Itu selalu mengembalikan MultiPolygon, bahkan jika Anda memiliki satu atau tidak ada komponen.

WITH 
      square   as (SELECT ST_GeomFromText('POLYGON ((0 0, 0  1,  1  1,  1  0, 0 0))') AS geom),
biggersquare   as (SELECT ST_GeomFromText('POLYGON ((0 0, 0 10, 10 10, 10  0, 0 0))') AS geom),
adjacentsquare as (SELECT ST_GeomFromText('POLYGON ((0 0, 1  0,  1 -1, -1 -1, 0 0))') AS geom)   

SELECT ST_AsText(PolygonalIntersection(square.geom, biggersquare.geom))
  FROM square, biggersquare;
--"MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)))"

SELECT ST_AsText(PolygonalIntersection(square.geom, adjacentsquare.geom))
  FROM square, adjacentsquare;
--"MULTIPOLYGON(EMPTY)"
dbaston
sumber
3

Jawaban yang sangat bagus dari @dbaston. Namun, mengembalikan geometri kosong bukan nol dapat menyebabkan masalah karena geometri kosong yang dikembalikan tidak memiliki srid. St_Intersection mungkin mengembalikan MultiPolygon juga. Fungsi yang diperbarui ini sangat berguna bagi saya:

CREATE OR REPLACE FUNCTION PolygonalIntersection(a geometry, b geometry)
RETURNS geometry AS $$
SELECT ST_Collect(geom)
FROM 
(SELECT (ST_Dump(ST_Intersection(a, b))).geom 
) SQ
WHERE ST_GeometryType(geom) = 'ST_Polygon' OR ST_GeometryType(geom) = 'ST_MultiPolygon';
$$ LANGUAGE SQL;
thoomasbro
sumber