PostGIS - cách hiệu quả ST_Union tất cả các đa giác chồng chéo trong một bảng duy nhất


13

Mục tiêu của tôi là lấy một bảng duy nhất và sắp xếp tất cả các đa giác chạm hoặc gần nhau thành các đa giác đơn

Tôi là nhà phát triển C # đang bắt đầu tìm hiểu về PostGIS. Sử dụng mã dưới đây, tôi đã có thể thực hiện được điều này, nhưng có vẻ như không hiệu quả, và có nhiều điều đối với PostGIS mới đối với tôi.

Từ nỗ lực ban đầu của tôi (vẫn trong các bình luận), tôi đã có thể giảm các lần lặp bằng cách sử dụng mảng_agg với ST_UNION thay vì liên kết chỉ các polys tại một thời điểm.

Tôi kết thúc với 133 polys từ nguồn gốc của tôi 173.

sql = "DROP TABLE IF Exists tmpTable; create table tmpTable ( ID varchar(50), Geom  geometry(Geometry,4326), Touchin varchar(50) ); create index idx_tmp on tmpTable using GIST(Geom); ";
                CommandText = sql;
                ExecuteNonQuery();

                sql = "";
                for (int i = 0; i < infos.Count(); i++)
                {
                    sql += "INSERT INTO tmpTable SELECT '" + infos[i].ID + "', ST_GeomFromText('" + infos[i].wkt + "', 4326), '0';";
                }
                CommandText = sql;
                ExecuteNonQuery();

                CommandText = "update tmpTable set touchin = (select id from tmpTable as t where st_intersects(st_buffer(geom, 0.0001), (select geom from tmpTable as t2 where t2.ID = tmpTable.ID ) ) and t.ID <> tmpTable.ID limit 1)";
                ExecuteNonQuery();

                CommandText = "select count(*) from tmpTable where touchin is not null";
                long touching = (long)ExecuteScalar();
                string thisId = "";
                // string otherId = "";
                while (touching > 0)
                {
                    CommandText = "select touchin, count(*)  from tmpTable where touchin is not null group by touchin order by 2 desc limit 1";
                    //CommandText = "select id, touchin from tmpTable where touchin is not null";
                    using (var prdr = ExecuteReader())
                    {
                        CommandText = "";
                        if (prdr.Read())
                        {
                            thisId = prdr.GetString(0);
                             // otherID = prdr.GetString(1);
                            CommandText = @"update tmpTable set geom = st_union(unioned) 
                                from (select array_agg(geom) as unioned from tmpTable where touchin = '" + thisId + "' or id = '" + thisId + @"') as data
                                where id = '" + thisId + "'";
                             // CommandText = "update tmpTable set geom = st_union(geom, (select geom from tmpTable where ID = '" + otherId + "')) where id = '" + thisId + "'";
                        }
                    }

                    if (!string.IsNullOrEmpty(CommandText))
                    {
                        ExecuteNonQuery();
                        //CommandText = "update tmpTable set geom = null, touchin = null where ID = '" + otherId + "'";
                        CommandText = "update tmpTable set geom = null, touchin = null where touchin = '" + thisId + "'";
                        ExecuteNonQuery();                            
                    }

                    CommandText = "update tmpTable set touchin = (select id from tmpTable as t where st_intersects(st_buffer(geom, 0.0001), (select geom from tmpTable as t2 where t2.ID = tmpTable.ID ) ) and t.ID <> tmpTable.ID limit 1)";
                    ExecuteNonQuery();

                    CommandText = "select count(*) from tmpTable where touchin is not null";
                    touching = (long)ExecuteScalar();
                }

Đây là mẫu của bộ dữ liệu tôi đang sử dụng:

INSERT INTO tmpTable SELECT '872538', ST_GeomFromText('POLYGON((-101.455035985 26.8835084441,-101.455035985 26.8924915559,-101.444964015 26.8924915559,-101.444964015 26.8835084441,-101.455035985 26.8835084441))', 4326), '0';
INSERT INTO tmpTable SELECT '872550', ST_GeomFromText('POLYGON((-93.9484752173 46.0755084441,-93.9484752173 46.0844915559,-93.9355247827 46.0844915559,-93.9355247827 46.0755084441,-93.9484752173 46.0755084441))', 4326), '0';
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.8105084441))', 4326), '0';
INSERT INTO tmpTable SELECT '872553', ST_GeomFromText('POLYGON((-116.043688832 47.8125084441,-116.043688832 47.8214915559,-116.030311168 47.8214915559,-116.030311168 47.8125084441,-116.043688832 47.8125084441))', 4326), '0';
INSERT INTO tmpTable SELECT '872557', ST_GeomFromText('POLYGON((-80.6380222359 26.5725084441,-80.6380222359 26.5814915559,-80.6279777641 26.5814915559,-80.6279777641 26.5725084441,-80.6380222359 26.5725084441))', 4326), '0';
INSERT INTO tmpTable SELECT '872558', ST_GeomFromText('POLYGON((-80.6520223675 26.5755084441,-80.6520223675 26.5844915559,-80.6419776325 26.5844915559,-80.6419776325 26.5755084441,-80.6520223675 26.5755084441))', 4326), '0';
INSERT INTO tmpTable SELECT '872559', ST_GeomFromText('POLYGON((-80.6400224991 26.5785084441,-80.6400224991 26.5874915559,-80.6299775009 26.5874915559,-80.6299775009 26.5785084441,-80.6400224991 26.5785084441))', 4326), '0';
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.7787741416 30.7365084441,-90.7892258584 30.7365084441))', 4326), '0';
INSERT INTO tmpTable SELECT '872569', ST_GeomFromText('POLYGON((-90.7832259127 30.7375084441,-90.7832259127 30.7464915559,-90.7727740873 30.7464915559,-90.7727740873 30.7375084441,-90.7832259127 30.7375084441))', 4326), '0';

Là dữ liệu thực tế cần thiết trong câu hỏi của bạn?
Paul

@Paul - không chắc nó có hữu ích hay không.
Carol AndorMarten Liebster

Câu trả lời:


20

Cách đơn giản nhất sẽ là ST_Uniontoàn bộ bảng:

SELECT ST_Union(geom) FROM tmpTable;

Điều này sẽ cung cấp cho bạn một lượng lớn MultiPolygon, có thể không phải là những gì bạn muốn. Bạn có thể nhận được các thành phần hòa tan cá nhân với ST_Dump. Vì thế:

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

Điều này cung cấp cho bạn một đa giác riêng cho từng nhóm đầu vào chạm , nhưng các nhóm đầu vào được phân tách bằng một khoảng cách ngắn sẽ vẫn là hình học riêng biệt. Nếu bạn có quyền truy cập vào PostGIS 2.2.0rc1 , bạn có thể hợp nhất các hình học gần nhau thành một GeometryCollectionbằng cách sử dụng ST_ClusterWithin :

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

Nếu bạn muốn Polygonstrong GeometryCollectiongiải thể, bạn có thể chạy ST_UnaryUniontrên mỗi GeometryCollectiontrong kết quả, như:

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

Điều đó chắc chắn nhanh hơn nhiều, nhưng 2 điều: (1) Tôi có thể bảo vệ trường ID trong kết quả không? Nó không quan trọng cái nào, nhưng tôi cần lấy kết quả và lấy dữ liệu khác từ nó. (2) Có cách nào để thêm ST_Buffer trở lại không?
Carol AndorMarten Liebster

1
(1) Không dễ dàng, nhưng một cách đơn giản để lấy lại các thuộc tính là kết nối không gian các đa giác kết quả của bạn với một điểm bên trong của đa giác đầu vào của bạn. (2) Đã thêm một số giải thích để xử lý hình học gần nhưng không chạm vào.
dbaston

Cảm ơn sự giúp đỡ - Hiện tại tôi không có 2.2, vì vậy tôi sẽ phải xem lại điều này khi tôi nâng cấp lên. Cho đến nay, việc loại trừ bộ đệm không phải là một bộ ngắt thỏa thuận.
Carol AndorMarten Liebster

Tôi đồng ý đây là đơn giản nhất. Tôi tự hỏi liệu có cách nào để thực hiện một truy vấn đệ quy tìm thấy các địa chất cảm động không, nhưng tôi đã từ bỏ nó - postgresql.org/docs/civerse/static/queries-with.html
chrismarx

1
@chrismarx, hãy xem gis.stackexchange.com/a/94228/18189 để biết một số ý tưởng về giải pháp đệ quy.
dbaston
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.