Mais

PostGIS - como eficientemente ST_Union todos os polígonos sobrepostos em uma única tabela

PostGIS - como eficientemente ST_Union todos os polígonos sobrepostos em uma única tabela


Meu objetivo é pegar uma única tabela e reunir todos os polígonos que estão se tocando ou próximos uns dos outros em polígonos únicos

Sou um desenvolvedor C # que está começando a aprender sobre PostGIS. Usando o código abaixo, consegui fazer isso, mas parece ineficiente, e há muito no PostGIS que é novo para mim.

Da minha tentativa inicial (ainda nos comentários), consegui reduzir as iterações usando array_agg com ST_UNION em vez de unir apenas polys por vez.

Acabo com 133 polys do meu 173 original.

sql = "DROP TABLE IF Exists tmpTable; criar tabela tmpTable (ID varchar (50), geometria Geom (Geometria, 4326), Touchin varchar (50)); criar índice idx_tmp em tmpTable usando GIST (Geom);"; CommandText = sql; ExecuteNonQuery (); sql = ""; for (int i = 0; i  0) {CommandText = "selecionar touchin, contar (*) from tmpTable onde touchin não é grupo nulo por touchin ordem por 2 desc limite 1"; // CommandText = "selecionar id, tocar em tmpTable onde touchin não é nulo"; usando (var prdr = ExecuteReader ()) {CommandText = ""; if (prdr.Read ()) {thisId = prdr.GetString (0); // otherID = prdr.GetString (1); CommandText = @ "update tmpTable set geom = st_union (unioned) from (selecione array_agg (geom) como unido de tmpTable onde touchin = '" + thisId + "' ou id = '" + thisId + @ "') como dados onde id = '"+ thisId +"' "; // CommandText = "update tmpTable set geom = st_union (geom, (selecione geom de tmpTable onde ID = '" + otherId + "')) where id = '" + thisId + "'"; }} if (! string.IsNullOrEmpty (CommandText)) {ExecuteNonQuery (); // CommandText = "update tmpTable set geom = null, touchin = null onde ID = '" + otherId + "'"; CommandText = "update tmpTable set geom = null, touchin = null onde touchin = '" + thisId + "'"; ExecuteNonQuery (); } CommandText = "update tmpTable set touchin = (selecione id de tmpTable como t onde st_intersects (st_buffer (geom, 0,0001), (selecione geom de tmpTable como t2 onde t2.ID = tmpTable.ID)) e t.ID <> tmpTable .ID limite 1) "; ExecuteNonQuery (); CommandText = "selecionar contagem (*) de tmpTable onde touchin não é nulo"; tocando = (longo) ExecuteScalar (); }

Aqui está um exemplo do conjunto de dados que estou usando:

INSERT INTO tmpTable SELECT '872538', ST_GeomFromText ('POLYGON ((- 101,455035985 26,8835084441, -101,455035985 26,8924915559, -101,444964015 26,8924915559, -101,455035985 26,8835084441, -101,455035985 26,8924915559, -101,444964015 26,8924915559, -101,442664015' INSERT INTO tmpTable SELECT '872550', ST_GeomFromText ('POLYGON ((- 93.9484752173 46.0755084441, -93.9484752173 46.0844915559, -93.9355247827 46.0844915559, -93.93552447541)' 46.0844915559, -93.9355247827 46.0844915559, -93.93552447841) '46.0844915559, -93.9355247827 46.0844915559, -93.5267552447841) 46.08.458.452.541. INSERT INTO tmpTable SELECT '872552', ST_GeomFromText ('POLYGON ((- 116.060688575 47.8105084441, -116.060688575 47.8194915559, -116.047311425 47.8194915559, -116.047311425 47.8105084441, -116.060688575 47.8194915559, -116.047311425 47.8194915559, -116.047311425 47.81050841) INSERT INTO tmpTable SELECT '872553', ST_GeomFromText ('POLYGON ((- 116.043688832 47.8125084441, -116.043688832 47.8214915559, -116.030311168 47.8214915559, -116.030311168508' 47.841.841.841.841.841.841.841.841.841.841.841.841.841. INSERT INTO tmpTable SELECT '872557', ST_GeomFromText ('POLYGON ((- 80.6380222359 26.5725084441, -80.6380222359 26.5814915559, -80.6279777641 26.5814915559, 26.5725084441, -80.6380222359 26.5814915559, -80.6279777641 26.5814915559, 26.5725084441, -80.6380222359 26.5814915559, -80.6279777641 26.5814915559, -80.6279778.563.563.541.572.541.572.563.541. INSERT INTO tmpTable SELECT '872558', ST_GeomFromText ('POLYGON ((- 80.6520223675 26.5755084441, -80.6520223675 26.5844915559, -80.6419776325 26.5844915559, -80.6419776325 26.544.3650); INSERT INTO tmpTable SELECT '872559', ST_GeomFromText ('POLYGON ((- 80.6400224991 26.5785084441, -80.6400224991 26.5874915559, -80.6299775009 26.5874915559, -80.6400224991 26.5785084441, -80.6400224991 26.5874915559, -80.6299775009 26.587491555999, -80.6400224.541), -80.6400224991 26.5874915559, -80.6299775009 26.5874915559, -80.62507.642.541) INSERT INTO tmpTable SELECT 872560 ', ST_GeomFromText ( 'POLYGON ((- 80,6530226307 26,5815084441, -80,6530226307 26,5904915559, -80,6429773693 26,5904915559, -80,6429773693 26,5815084441, -80,6530226307 26,5815084441))', 4326), '0'; INSERT INTO tmpTable SELECT '872568', ST_GeomFromText ('POLYGON ((- 90.7892258584 30.7365084441, -90.7892258584 30.7454915559, -90.7787741416 30.7454915559, -90.7892258584 30.7365084441, -90.7892258584 30.7454915559, -90.7787741416 30.7454915559, -90.778.77877414416) INSERT INTO tmpTable SELECT '872569', ST_GeomFromText ('POLYGON ((- 90,7832259127 30,7375084441, -90,7832259127 30,7464915559, -90,7727740873 30,7464915559, -90,7832259127 30,73,75084441, -90,7832259127 30,7464915559, -90,7727740873 30,7464915559, -90,7832259127 307375084441, -90,7832259127 30,7464915559, -90,7727740873 30,7464915559, -90,7727740873' 073127508447);

A maneira mais simples seriaST_Uniona mesa inteira:

SELECT ST_Union (geom) FROM tmpTable;

Isso lhe dará um enormeMultiPolygon, que provavelmente não é o que você deseja. Você pode obter os componentes individuais dissolvidos comST_Dump. Então:

SELECT (ST_Dump (geom)). Geom FROM (SELECT ST_Union (geom) AS geom FROM tmpTable) sq;

Isso dá a você um polígono separado para cada conjunto de comovente entradas, mas os grupos de entradas que foram separados por uma curta distância permanecerão como geometrias separadas. Se você tiver acesso ao PostGIS 2.2.0rc1, você pode mesclar geometrias que estão juntas em um únicoGeometryCollectionusando ST_ClusterWithin:

SELECT unnest (ST_ClusterWithin (geom, 0.0001)) AS grp FROM tmpTable;

Se você quiserPolígonosdentro doGeometryCollectionpara ser dissolvido, você pode executarST_UnaryUnionem cadaGeometryCollectionno resultado, como:

SELECT ST_UnaryUnion (grp) FROM (SELECT unnest (ST_ClusterWithin (geom, 0,0001)) AS grp FROM tmpTable) sq;

Assista o vídeo: Lessons on GDB and Interactive Maps No. 2. Getting, installing and configuring PostGIS PostgreSQL.