PostGIS kullanarak kesişime dayalı ayrı poligonlar


36

Bazılarının birbiriyle kesiştiği bir PostGIS poligon tablosu var. Yapmaya çalıştığım şey bu:

  • Kimliğe göre seçilen çokgen için, kesişen tüm çokgenleri bana verin. Temel olarak,select the_geom from the_table where ST_Intersects(the_geom, (select the_geom from the_table where source_id = '123'))
  • Bu çokgenlerden, kesişimin yeni çokgen olacağı şekilde yeni çokgenler oluşturmam gerekiyor. Yani çokgen A çokgen B ile kesişirse, 3 yeni çokgen alırım: A eksi AB, AB ve B eksi AB.

Herhangi bir fikir?


1
Hmmm, neye ulaştığını görüyorum ama basit bir grafik bana (ve diğerlerine) tam olarak ne istediğini görmede yardımcı olacak harikalar yaratabilir.
Jason,

Cevabımda bazı eklendi.
Adam Matan

Yanıtlar:


29

İlgilendiğiniz her poligon için bir kesişen poligon grubu aldığınızı söylediğiniz için, "poligon yerleşimi" olarak adlandırılan şeyi oluşturmak isteyebilirsiniz.

Bu tam olarak Adam'ın çözümünün yaptığı şey değil. Farkı görmek için, ABC kavşağının bu resmine bakın:

Abc kesişme

Adam'ın çözümünün hem "AB! C" hem de "ABC" alanını kapsayan bir "AB" poligonunun yanı sıra "AC! B" ve "ABC" yi kapsayan bir "AC" poligonu ve " "BC" A "ve" ABC "olan çokgen. Bu nedenle, "AB", "AC" ve "BC" çıkış poligonlarının tümü "ABC" alanıyla örtüşür.

Bir poligon üst üste binme olmayan poligonlar üretir, böylece AB! C bir poligon olur ve ABC bir poligon olur.

PostGIS'de çokgen bir kaplama oluşturmak aslında oldukça basittir.

Temelde üç adım var.

Adım 1, astarı çıkartmaktır [Poligonun dış halkasını kullandığımı, delikleri düzgün bir şekilde tutmak istiyorsanız biraz daha karmaşık hale geldiğini unutmayın]:

SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines

Adım 2, çizgiyi "düğümlemek" tir (her kesişme noktasında bir düğüm üretir). JTS gibi bazı kütüphanelerde bunu yapmak için kullanabileceğiniz "Noder" sınıfları vardır, ancak PostGIS'te ST_Union işlevi sizin için yapar:

SELECT ST_Union(the_geom) AS the_geom FROM (...your lines...) AS noded_lines

Adım 3, ST_Polygonize işlevi tarafından yapılan tüm bu satırlardan gelebilecek tüm örtüşmeyen tüm çokgenleri oluşturmaktır :

SELECT ST_Polygonize(the_geom) AS the_geom FROM (...your noded lines...)

Bu adımların her birinin çıktısını geçici tabloya kaydedebilir veya hepsini tek bir ifadede birleştirebilirsiniz:

CREATE TABLE my_poly_overlay AS
SELECT geom FROM ST_Dump((
    SELECT ST_Polygonize(the_geom) AS the_geom FROM (
        SELECT ST_Union(the_geom) AS the_geom FROM (
            SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines
        ) AS noded_lines
    )
)

ST_Dump kullanıyorum çünkü ST_Polygonize'in çıktısı bir geometri koleksiyonudur ve her sıranın çokgen kaplamasını oluşturan çokgenlerden biri olduğu bir tabloya sahip olmak (genellikle) daha uygundur.


ST_ExteriorRingHerhangi bir delik bıraktığını unutmayın . ST_Boundaryiç halkaları koruyacak, fakat aynı zamanda içlerinde çokgen oluşacaktır.
jpmc26

Çok sayıda çokgen olduğunda dış halkaların birliği çöküyor. Maalesef bu "basit" çözüm yalnızca küçük eşantiyonlar için işe yarıyor.
Pierre Racine

13

Doğru anlarsam, almak istiyorsun (A sol geometri, B sağdır):

A∪B'nin görüntüsü http://img838.imageshack.us/img838/3996/intersectab1.png

Ve özü:

Bir ∖ AB

A ∖ AB'nin görüntüsü http://img830.imageshack.us/img830/273/intersectab2.png

AB

AB'nin görüntüsü http://img828.imageshack.us/img828/7413/intersectab3.png

ve B ∖ AB

B ∖ AB'nin görüntüsü http://img839.imageshack.us/img839/5458/intersectab4.png

Yani - kesişen her çift için üç farklı geometri.

İlk önce, kesişen tüm geometrilerin bir görüntüsünü oluşturalım. Tablo adınızı varsayalım polygons_table, kullanacağız

CREATE OR REPLACE VIEW p_intersections AS    -- Create a view with the 
SELECT t1.the_geom as t1_geom,               -- intersecting geoms. Each pair
       t2.the_geom as t2_geom                -- appears once (t2.id<t2.id)
    FROM polygons_table t1, polygons_table t2  
         WHERE t1.id<t2.id AND t1.the_geom && t2.the_geom 
                           AND intersects t1.the_geom, t2.the_geom;

Şimdi bir görünümü (pratikte, bir salt okunur tablo) sahip her bir çift dolayı sadece bir kez görünür kesişen geoms, saklar çiftleri bu t1.id<t2.idduruma.

- Şimdi gelelim senin kavşakları toplamak A∖AB, ABve B∖ABSQL en kullanarak UNION: Her üç sorgularında

--AB:
SELECT ST_intersection(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION 

--AAB:
SELECT ST_Difference(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION

--BAB:
SELECT ST_Difference(t2.the_geom, t1.the_geom) 
    AS geom 
    FROM p_intersections;

Notlar:

  1. &&Operatör daha önce bir filtre olarak kullanılır intersectsperformansını artırmak için, operatör.
  2. VIEWDevasa bir sorgu yerine bir tane yaratmayı seçtim ; Bu sadece kolaylık sağlamak içindir.
  3. Eğer demekse ABbirlik değil, kavşak, ait olduğu Ave Ben Kullanım ST_Union yerine st_intersection - UNIONuygun yerlere sorguda.
  4. İşareti Seti farkı unicode işaretidir; Veritabanınızı karıştırırsa koddan kaldırın.
  5. Resimler, Wikimedia Commons'ın güzel Set teorisi kategorisinin izniyle .


Güzel açıklama! Sonuçlar scw çözümünde olduğu gibi aynı, ancak daha hızlı olması gerekiyor (A ve B'yi hesaplamak / veya saklamak / ek kavşaklarda değil)
stachu

Teşekkürler! Tabloları değil, sadece SQL VIEW'leri oluşturduğum için fazladan bilgi saklamadığımı düşünüyorum.
Adam Matan

Evet, bu doğru, ama gerekmeyen A ve B ek kesişimini
hesapladın

5
Bu cevaptaki görseller artık çalışmıyor.
Fezter

8

Tarif ettiğiniz şey, Birlik operatörünün ArcGIS'de çalışma şeklidir , ancak GEOS dünyasında Birlik veya Kavşaktan biraz farklıdır. Shapely manual, setlerin GEOS'ta nasıl çalıştığına dair örneklere sahiptir . Bununla birlikte, PostGIS wiki sizin için hile yapması gereken linework'ı kullanarak iyi bir örneğe sahip .

Alternatif olarak, üç şeyi hesaplayabilirsiniz:

  1. ST_Bölüm (geom_a, geom_b)
  2. ST_Difference (geom_a, geom_b)
  3. ST_Difference (geom_b, geom_a)

Bunlar, ikinci kurşun noktanızda bahsettiğiniz üç poligon olmalı.


2
PostGIS wiki örneği iyi
fmark

ST_Intersects kesişirse ya da olmasa boolean döndürür mü? ST_Iersersection'ın işe yarayacağını düşünüyorum.
Jason,

Evet, benim tarafımdaki yazım hatası - orijinal şimdi düzeltildi, teşekkürler Jason!
scw

-2

Gibi bir şey:

New_table DEĞERLERİNE INSERT ((kimliği seçin, st_intersects (the_geom, (old_table olan_geom'u seçin)) = true

EDIT: Çokgenin gerçek kesişimine ihtiyacınız var.

INSERT IN_'ın new_table değerleri ((kimliği seçin, ST_Itrersection (the_geom, (eskiden kimliği seçin: 123 =))

Bunun işe yarayıp yaramadığına bakın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.