Penso che sia un po 'complicato, a causa delle diverse serie di nodi di entrambi i poligoni (poligono verde A, segmenti rossi diversi di polione B). Il confronto dei segmenti di entrambi i poligoni fornisce un indizio su quali segmenti del poligono B verranno modificati.
Poligono dei nodi A
Nodi del "diverso" segmento poligono B
Sfortunatamente questo mostra solo la differenza nella struttura del segmento, ma spero che sia un punto di partenza e funzioni così:
Dopo un processo di download e decompressione ho importato il set di dati usando PostgrSQL 9.46, PostGIS 2.1 sotto Debian Linux Jessie con i comandi.
$ 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
Supponendo che i segmenti del poligono A non siano in B e vice vera, provo a costruire la differenza tra i segmenti di entrambi i set di poligoni, trascurando l'appartenenza al segmento ai poligoni in ciascun gruppo (A o B). Per motivi didattici, ho formulato il materiale SQL in diverse viste.
Corrispondente a questo post GIS-SE , scompongo entrambi i poligoni in tabelle di segmenti segments_a
esegments_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;
Il poligono della tabella dei segmenti 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
La stessa procedura è stata applicata al poligono B.
-- 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;
Il poligono della tabella dei segmenti 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)
...
Posso creare una vista tabella differenze denominata segments_diff_{a,b}
. La differenza è data dalla non occorrenza dei punti di inizio o fine ordinati negli insiemi di segmenti A e 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;
E le cose complementari:
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;
Conclusione: per ottenere un risultato corretto per i piccoli segmenti contrassegnati con la freccia rossa, entrambi i poligoni devono avere la stessa struttura del nodo e un passaggio di intersezione a livello di nodo (inserimento dei vertici del poligono A in B). L'intersezione potrebbe essere effettuata da:
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;
Ma con strani risultati ...