Creo que es un poco complicado, debido a los diferentes conjuntos de nodos de sus dos polígonos (polígono verde A, segmentos rojos diferentes del polón B). Al comparar los segmentos de ambos polígonos se obtiene una pista sobre qué segmentos del polígono B se modificarán.
Nodos polígono A
Nodos de los segmentos "diferentes" polígono B
Desafortunadamente, esto muestra solo la diferencia en la estructura del segmento, pero espero que sea un punto de partida y funcione así:
Después de un proceso de descarga y descompresión, importé el conjunto de datos usando PostgrSQL 9.46, PostGIS 2.1 en Debian Linux Jessie con los comandos.
$ 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
Suponiendo que los segmentos del polígono A no están en B y viceversa, trato de construir la diferencia entre los segmentos de ambos conjuntos de polígonos, descuidando la pertenencia del segmento a los polígonos en cada grupo (A o B). Por razones didácticas, formulo el material SQL en varias vistas.
En correspondencia con esta publicación GIS-SE , descompongo los dos polígonos en tablas de segmentossegments_a
ysegments_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;
La tabla de segmentos del polígono 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
El mismo procedimiento se aplicó al polígono 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;
La tabla de segmentos polígono 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)
...
Puedo construir una vista de tabla de diferencias llamada segments_diff_{a,b}
. La diferencia está dada por la no ocurrencia de puntos de inicio o fin ordenados en el conjunto de segmentos A y 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;
Y las cosas complementarias:
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;
Conclusión: Para obtener un resultado adecuado para los pequeños segmentos pequeños que marcó con la flecha roja, ambos polígonos deben tener la misma estructura de nodo y un paso de intersección a nivel de nodo (se requiere insertar vértices del polígono A en B). La intersección podría hacerse por:
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;
Pero con resultados extraños ...