PostGIS'de çokgen özellikleri arasındaki farkları görselleştirmek için çizgiler nasıl oluşturulur?


15

polygon_bBazı çokgen özellikleri olan bir PostGIS masam var. polygon_aAynı çokgenleri içeren, polygon_bancak küçük değişikliklere sahip bir tablo da vardır . Şimdi çokgen özellikleri arasındaki farkları görselleştirmek için çizgiler oluşturmak istiyorum.

resim açıklamasını buraya girin resim açıklamasını buraya girin resim açıklamasını buraya girin

Bunu sanırım ST_ExteriorRingve ST_Differenceişi yapacağım ama WHERE maddesi oldukça zor görünüyor.

CREATE VIEW line_difference AS SELECT
row_number() over() AS gid,
g.geom::geometry(LineString, yourSRID) AS geom
FROM 
    (SELECT
    (ST_Dump(COALESCE(ST_Difference(ST_ExteriorRing(polygon_a.geom), ST_ExteriorRing(polygon_b.geom))))).geom AS geom
    FROM polygon_a, polygon_b
    WHERE 
    -- ?
    ) AS g;

Biri bana yardım edebilir mi?

DÜZENLEME 1

Gönderdiğim gibi 'tilt' denedim ST_Overlaps(polygon_a.geom, polygon_b.geom) AND NOT ST_Touches(polygon_a.geom, polygon_b.geom)ama sonuç beklendiği gibi değil.

CREATE VIEW line_difference AS SELECT
row_number() over() AS gid,
g.geom::geometry(LineString, your_SRID) AS geom
FROM 
    (SELECT
    (ST_Dump(COALESCE(ST_Difference(ST_ExteriorRing(polygon_a.geom), ST_ExteriorRing(polygon_b.geom))))).geom AS geom
    FROM polygon_a, polygon_b
    WHERE 
    ST_Overlaps(polygon_a.geom, polygon_b.geom) AND NOT ST_Touches(polygon_a.geom, polygon_b.geom))
     AS g;

resim açıklamasını buraya girin

DÜZENLEME 2

workupload.com/file/J0WBvRBb (örnek veri kümesi)


ST_Difference kullanmadan önce çokgenler çok satırlı çevirmeye çalıştım, ancak sonuçlar hala garip.

CREATE VIEW multiline_a AS SELECT
row_number() over() as gid,
ST_Union(ST_ExteriorRIng(polygon_a.geom))::geometry(multilinestring, 4326) AS geom
FROM
polygon_a;

CREATE VIEW multiline_b AS SELECT
row_number() over() as gid,
ST_Union(ST_ExteriorRIng(polygon_b.geom))::geometry(multilinestring, 4326) AS geom
FROM
polygon_b;

CREATE VIEW line_difference AS SELECT
row_number() over() as gid,
g.geom
FROM
    (SELECT
    (ST_Dump(COALESCE(ST_Difference(multiline_a.geom, multiline_b.geom)))).geom::geometry(linestring, 4326) AS geom
    FROM
    multiline_a, multiline_b)
As g;

resim açıklamasını buraya girin


Daha çok bir topoloji sorusuna benziyor. Diğer katman tarafından kapsanmayan segmentleri tanımlamak istiyorsunuz. PostGIS topolojisi ile çok çalışmadım ve size doğrudan bir cevap veremem, ancak buna daha fazla bakmanızı öneririm.
Thomas

İlginç, indirmek için örnek bir veri kümeniz var mı?
huckfinn

Yanıtlar:


10

İşte birkaç yeni numara:

  • EXCEPTher iki tabloda da aynı olan geometrileri kaldırmak için, yalnızca her bir tablo ( A_onlyve B_only) için benzersiz olan geometrilere odaklanabiliriz .
  • ST_Snap bindirme operatörleri için kesin başını sallamak.
  • Farklılıkları göstermek için iki geometri seti arasındaki simetrik farkıST_SymDifference bulmak için kaplama operatörünü kullanın . Güncelleme : bu örnek için aynı sonucu gösterir. Ne aldıklarını görmek için her iki işlevi de deneyebilirsiniz.ST_Difference

Bu beklediğinizi almalıdır:

-- CREATE OR REPLACE VIEW polygon_SymDifference AS
SELECT row_number() OVER () rn, *
FROM (
  SELECT (ST_Dump(ST_SymDifference(ST_Snap(A, B, tol), ST_Snap(B, A, tol)))).*
  FROM (
    SELECT ST_Union(DISTINCT A_only.geom) A, ST_Union(DISTINCT B_only.geom) B, 1e-5 tol
    FROM (
      SELECT ST_Boundary(geom) geom FROM polygon_a
      EXCEPT SELECT ST_Boundary(geom) geom FROM polygon_b
    ) A_only,
    (
      SELECT ST_Boundary(geom) geom FROM polygon_b
      EXCEPT SELECT ST_Boundary(geom) geom FROM polygon_a
    ) B_only
  ) s
) s;

 rn |                                        geom
----+-------------------------------------------------------------------------------------
  1 | LINESTRING(206.234028204842 -92.0360704110685,219.846021625456 -92.5340701703592)
  2 | LINESTRING(18.556700448873 -36.4496098325257,44.44438533894 -40.5104231486146)
  3 | LINESTRING(-131.974995802602 -38.6145334122719,-114.067738329597 -39.0215165366584)
(3 rows)

üç satır


Bu cevabı biraz daha açmak için, ilk adım ST_Boundarysadece dışsaldan ziyade her çokgenin sınırını alır. Örneğin, delikler olsaydı, bunlar sınır tarafından izlenirdi.

EXCEPTMaddesi B parçası olan A geometrileri kaldırmak için kullanılan ve A bir parçası olan B satırları Bu, yalnızca A parçası olan satır sayısını ve sadece B parçası azaltır. Örneğin, A_only almak için:

SELECT ST_Boundary(geom) geom FROM polygon_a
EXCEPT SELECT ST_Boundary(geom) geom FROM polygon_b

İşte 6 satır A_only ve 3 satır B_only: A_only B_only

Daha sonra ST_Union(DISTINCT A_only.geom), çizgileri tek bir geometriye, tipik olarak bir MultiLineString'e birleştirmek için kullanılır.

ST_Snap, düğümleri bir geometriden diğerine yapıştırmak için kullanılır. Örneğin ST_Snap(A, B, tol), A geometrisini alacak ve B geometrisinden daha fazla düğüm ekleyecek veya mesafedeyse B geometrisine taşıyacaktır tol. Muhtemelen bu işlevleri kullanmanın birkaç yolu vardır, ancak fikir her bir geometriden birbirine kesin koordinatlar elde etmektir. Yapışmadan sonraki iki geometri şöyle görünür:

Bir tersledi B tersledi

Farklılıkları göstermek için, ST_SymDifferenceveya seçeneğini kullanmayı seçebilirsiniz ST_Difference. Her ikisi de bu örnek için aynı sonucu göstermektedir.


Güzel cevap. Aracı sorgularınızın sonuçlarını görselleştirmek için ne kullandığınızı merak ettim. Hemen qgis gibi görünmüyordu ve belki de biraz daha hızlı yapan bir şey mi?
RoperMaps

1
JTS Testbuilder'ı geometrileri görüntülemek ve işlemek için kullanıyorum. GEOS ve Shapely ile ilgili bir geometri motorudur, ancak Java tabanlı bir GUI'ye sahiptir.
Mike T

'LINESTRING arasında başıyla onaylanmamış kesişimi' sorunlarını yok saymanın / atlamanın bir yolu var mı? Tüm giriş çokgenleri iyi görünüyor (QGIS geometri denetleyicisi ile kontrol edildi).
eclipsed_by_the_moon

1
'ST_Boundary (geom)' yerine 'ST_Boundary (ST_SnapToGrid (geom, 0.001))' sorunu çözüyor.
eclipsed_by_the_moon

6

Her iki çokgeninizin farklı düğüm kümeleri (yeşil poligon A, kırmızı poligon B bölümleri) nedeniyle biraz zor olduğunu düşünüyorum. Her iki poligonun segmentlerinin karşılaştırılması, poligon B segmentlerinin değiştirileceği hakkında bir ipucu verir.

Çokgen A düğümleri

poli a

"Farklı" segmentlerin düğümleri çokgen B

seg diff

Ne yazık ki bu sadece segment yapısındaki farkı gösterir, ancak umarım bir başlangıç ​​noktasıdır ve şöyle çalışır:

Bir indirme ve unzip işleminden sonra komutları ile Debian Linux Jessie altında PostgrSQL 9.46, PostGIS 2.1 kullanarak veri kümesini içe aktardım.

$ createdb gis-se
$ psql gis-se < /usr/share/postgis-2.1/postgis.sql
$ psql gis-se < /usr/share/postgis-2.1/spatial_ref_sys.sql
$ shp2pgsql -S polygon_a | psql gis-se
$ shp2pgsql -S polygon_b | psql gis-se

Çokgen A segmentlerinin B ve yardımcı verada olmadığını varsayarsak, her iki poligon setinin segmentleri arasındaki farkı oluşturmaya çalışarak, her gruptaki (A veya B) çokgenlere segment üyeliğini ihmal ederim. Didaktik nedenlerden ötürü, SQL öğelerini çeşitli görünümlerde formüle ederim.

Bu GIS-SE yazısına karşılık olarak , her iki poligonu da segment tablolarına ayırıyorum segments_avesegments_b

-- Segments of the polygon A
CREATE VIEW segments_a AS SELECT sp, ep
FROM
   -- extract the endpoints for every 2-point line segment for each linestring
   (SELECT
      ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp,
      ST_PointN(geom, generate_series(2, ST_NPoints(geom)  )) as ep
    FROM
    -- extract the individual linestrings
     (SELECT (ST_Dump(ST_Boundary(geom))).geom
      FROM polygon_a
     ) AS linestrings
    -- be sure that nothing is scrambled
    ORDER BY sp, ep
) AS segments;

Segment tablosu çokgen A:

SELECT 
  st_astext(sp) AS sp, 
  st_astext(ep) AS ep 
FROM segments_a 
LIMIT 3;
                    sp                     |                 ep
-------------------------------------------+--------------------------------------------
POINT(-292.268907321861 95.0342877387557)  | POINT(-287.118411917425 99.4165242769195)
POINT(-287.118411917425 99.4165242769195)  | POINT(-264.62129248575 93.2470010145007)
POINT(-277.459563916327 -44.5629543976138) | POINT(-292.268907321861 95.03428773875

Poligon B'ye aynı prosedür uygulandı.

-- Segments of the polygon B
CREATE VIEW segments_b AS SELECT sp, ep
FROM
   -- extract the endpoints for every 2-point line segment for each linestring
   (SELECT
      ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp,
      ST_PointN(geom, generate_series(2, ST_NPoints(geom)  )) as ep
    FROM
    -- extract the individual linestrings
     (SELECT (ST_Dump(ST_Boundary(geom))).geom
      FROM polygon_b
     ) AS linestrings
    -- be sure that nothing is scrambled
    ORDER BY sp, ep
) AS segments;

Segment tablosu çokgen B

SELECT
  st_astext(sp) AS sp, 
  st_astext(ep) AS ep 
FROM segments_b 
LIMIT 3;
                    sp                     |                    ep
-------------------------------------------+-------------------------------------------
POINT(-292.268907321861 95.0342877387557)  | POINT(-287.118411917425 99.4165242769195)
POINT(-287.118411917425 99.4165242769195)  | POINT(-264.62129248575 93.2470010145007)
POINT(-277.459563916327 -44.5629543976138) | POINT(-292.268907321861 95.0342877387557)
...                        

Adlı bir fark tablosu görünümü oluşturabilirim segments_diff_{a,b}. Fark, A ve B segment kümesinde sıralı başlangıç ​​veya bitiş noktalarının oluşmamasıyla verilir.

CREATE VIEW segments_diff_a AS
SELECT st_makeline(b.sp, b.ep) as geom
FROM segments_b as b
LEFT JOIN segments_a as a ON (a.sp=b.sp and a.ep = b.ep)
-- filter segments without corresponding stuff in polygon A
WHERE a.sp IS NULL;

segs fark b

Ve tamamlayıcı şeyler:

CREATE VIEW segments_diff_b AS
SELECT st_makeline(a.sp, a.ep) as geom
FROM segments_a as a
LEFT JOIN segments_b as b ON (a.sp=b.sp and a.ep = b.ep)
-- filter segments without corresponding stuff in polygon B
WHERE b.sp IS NULL;

segs fark a

Sonuç: Kırmızı okla işaretlediğiniz küçük küçük segmentler için uygun bir sonuç elde etmek için, her iki poligonun da düğüm yapısına sahip olması ve düğüm seviyesinde bir kesişim aşaması olması gerekir (B'de çokgen A'nın tepe noktalarının eklenmesi). Kavşak şu şekilde yapılabilir:

CREATE VIEW segments_bi AS 
SELECT distinct sp, ep
FROM (
 SELECT
      ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp,
      ST_PointN(geom, generate_series(2, ST_NPoints(geom)  )) as ep
 FROM (
   SELECT st_difference(b.seg, a.seg) as geom FROM 
      segments_diff_a as a, segments_diff_b as b 
      WHERE st_intersects(a.seg, b.seg)
    ) as cut
  ) as segments
  WHERE sp IS NOT NULL AND ep IS NOT NULL
ORDER BY sp, ep;

Ama garip sonuçlarla ...

sürümü kes


Çabaların için teşekkürler. Sonuçlar garip. Sadece merak ediyorum ST_HausdorffDistance () soruyu cevaplamak için yardımcı olabilir mi: gis.stackexchange.com/questions/180593/…
Ay Denizi

Hm, st_haudorffdistance, size istenen segmentlere değil (kırmızı oklar) gösteren bir benzerlik ölçümü sağlar.
huckfinn

Bu sadece bir fikir, ST_HausdorffDistance her iki tablonun geometrilerini karşılaştırmak için kullanılabilir. Çokgenler mekansal olarak eşit olmasaydı çizgiler oluşturuyorum. Bunu nasıl yapacağımı bilmiyorum.
Ay Denizi

Bu bir hassasiyet ve topoloji meselesi gibi görünüyor ( gis.stackexchange.com/a/182838/26213 ve webhelp.esri.com/arcgisdesktop/9.2/… )
huckfinn

1

Örneğe bakıldığında, değişiklik, değiştirilen yeni tablodaki özelliklerin her zaman eski tablodaki örtüşen özellikler olacağı anlamına gelir. Bu nedenle,

ST_Overlaps (geoma, geomb) VE! ST_Touches (geoma, geomb)

Dokunuşlardaki olumsuzluk, yalnızca kenarlıkları aynı köşe noktalarını paylaşıyorsa özelliklerin de çakışmasıdır.

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.