Ich denke, es ist ein bisschen knifflig, weil die beiden Polygone unterschiedliche Knotensätze haben (grünes Polygon A, rote unterschiedliche Segmente von Polyon B). Der Vergleich der Segmente beider Polygone gibt einen Hinweis darauf, welche Segmente von Polygon B modifiziert werden.
Knotenpolygon A
Knoten des "unterschiedlichen" Segmentpolygons B
Leider zeigt dies nur den Unterschied in der Segmentstruktur, aber ich hoffe, es ist ein Ausgangspunkt und es funktioniert so:
Nach einem Download- und Entpackvorgang habe ich den Datensatz mit PostgrSQL 9.46, PostGIS 2.1 unter Debian Linux Jessie mit den Befehlen importiert.
$ 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
Unter der Annahme, dass die Segmente von Polygon A nicht in B und umgekehrt sind, versuche ich, den Unterschied zwischen den Segmenten beider Polygonsätze zu bilden, wobei ich die Segmentzugehörigkeit zu den Polygonen in jeder Gruppe (A oder B) vernachlässige. Aus didaktischen Gründen formuliere ich das SQL-Zeug in mehreren Ansichten.
Entsprechend diesem GIS-SE-Beitrag zerlege ich die beiden Polygone in Segmenttabellen segments_a
undsegments_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;
Das Segmenttabellenpolygon 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
Das gleiche Verfahren wurde auf Polygon B angewendet.
-- 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;
Das Segmenttabellenpolygon 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)
...
Ich kann eine Differenztabellenansicht namens erstellen segments_diff_{a,b}
. Die Differenz ergibt sich aus dem Nichtauftreten sortierter Start- oder Endpunkte in der Segmentmenge A und B.
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;
Und das Komplementäre:
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;
Fazit: Um ein korrektes Ergebnis für die kleinen Segmente zu erhalten, die Sie mit dem roten Pfeil markiert haben, müssen beide Polygone die gleiche Knotenstruktur aufweisen und ein Schnittschritt auf Knotenebene (Einfügen von Eckpunkten von Polygon A in B) ist erforderlich. Die Überschneidung könnte erfolgen durch:
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;
Aber mit seltsamen Ergebnissen ...