如何拆分具有重叠多边形的多边形并计算 PostgreSQL 中的重叠?
How to split polygons with overlapping polygons AND count overlaps in PostgreSQL?
我正在尝试在包含 1000 个重叠多边形(多部分,一些有孔)的单个 table 上创建一个 SQL 查询(PosgreSQL + PostGIS)那将:
.将多边形切割成不重叠的部分,并且对于每一部分
.计算重叠发生的次数。
我用谷歌搜索找到了几个例子,但 none 显示了完整的答案。例如,这是一个切割多边形(基于: PostGIS equivalent of ArcMap Union )但如果多边形有孔则不能正确切割。而且我不知道如何添加计算重叠的列:
WITH forest AS (
SELECT *
FROM (VALUES
(1,ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0) ,(1 1, 1 3, 3 3, 3 1, 1 1))',0))
,(2,ST_GeomFromText('POLYGON((10 0,20 0,20 10,10 10,10 0))',0))
,(3,ST_GeomFromText('POLYGON((2 2,4 2,4 4,2 4,2 2))',0)) /* hole in first */
,(4,ST_GeomFromText('POLYGON((8 5,12 5,12 9,8 9,8 5))',0)) /* overlapping */
,(5,ST_GeomFromText('POLYGON((12 2,14 2,14 4,12 4,12 2))',0)) /* hole in second */
) forest(id, geom)
)
SELECT
(dump).path[1] id,
(dump).geom
FROM
(
-- c) Polygonize the unioned rings (returns a GEOMETRYCOLLECTION)
-- Dump them to return individual geometries
SELECT
ST_Dump(ST_Polygonize(geom)) dump
FROM
(
-- b) Union all rings in one big geometry
SELECT
ST_Union(geom) geom
FROM
(
-- a) First get the exterior ring from all geoms
SELECT
ST_ExteriorRing(geom) geom
FROM
forest
) a
) b
) c
输入:
结果:
此处引用的答案需要自定义扩展:https://gis.stackexchange.com/questions/300800/get-single-part-polygon-by-their-intersection-in-postgis 虽然包括正确的重叠计数和处理孔,但结果也包含重叠的多边形。
WITH geomtable AS (
SELECT 1 id, ST_GeomFromText('POLYGON((0 1, 3 2, 3 0, 0 1), (1.5 1.333, 2 1.333, 2 0.666, 1.5 0.666, 1.5 1.333))') geom
UNION ALL
SELECT 2 id, ST_GeomFromText('POLYGON((1 1, 3.8 2, 4 0, 1 1))') geom
UNION ALL
SELECT 3 id, ST_GeomFromText('POLYGON((2 1, 4.6 2, 5 0, 2 1))') geom
UNION ALL
SELECT 4 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))') geom
UNION ALL
SELECT 5 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))') geom
UNION ALL
SELECT 6 id, ST_GeomFromText('POLYGON((1.75 1, 1 2, 2 2, 1.75 1))') geom
), parts AS (
SELECT a.id, unnest(ST_SplitAgg(a.geom, b.geom, 0.00001)) geom
FROM geomtable a,
geomtable b
WHERE ST_Equals(a.geom, b.geom) OR
ST_Contains(a.geom, b.geom) OR
ST_Contains(b.geom, a.geom) OR
ST_Overlaps(a.geom, b.geom)
GROUP BY a.id, ST_AsEWKB(a.geom)
)
SELECT count(*) nb, ST_Union(geom) geom
FROM parts
GROUP BY ST_Centroid(geom)
结果:
我希望有一种方法可以通过一些调整使其适用于所有类型的多边形...
所以,我再次回答我自己的问题...
这是我想出来的,希望它能帮助其他遇到类似问题的人:
。此代码适用于带孔的多边形(至少对于我测试的情况);
。有两部分:第一部分将多个重叠的多边形分割成单独的部分,第二部分检查(对于每个部分中的一个点)它与多少输入多边形相交;
。此代码将处理 'a few' 重叠的多边形,但未在大型表上进行测试 - 如果输入数据被正确索引,则可以提高性能。
WITH forest AS (
SELECT *
FROM (VALUES
(1,ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(1 1, 1 3, 3 3, 3 1, 1 1))',0))
,(2,ST_GeomFromText('POLYGON((10 0,20 0,20 10,10 10,10 0))',0))
,(3,ST_GeomFromText('POLYGON((2 2,4 2,4 4,2 4,2 2))',0)) /* hole in first */
,(4,ST_GeomFromText('POLYGON((8 5,12 5,12 9,8 9,8 5))',0)) /* overlapping */
,(5,ST_GeomFromText('POLYGON((12 2,14 2,14 4,12 4,12 2))',0)) /* hole in second */
) forest(id, geom)
), parts AS(
SELECT path[1] id, geom FROM ST_Dump((
SELECT ST_Polygonize(the_geom) AS the_geom FROM (
SELECT ST_Union(the_geom) AS the_geom FROM (
SELECT ST_Boundary(geom) AS the_geom FROM forest) AS lines
) AS noded_lines
)
))
SELECT a.geom, count(*) nb
FROM parts a , forest b
WHERE ST_Within(ST_PointOnSurface(a.geom),b.geom)
GROUP BY a.id, a.geom
我正在尝试在包含 1000 个重叠多边形(多部分,一些有孔)的单个 table 上创建一个 SQL 查询(PosgreSQL + PostGIS)那将: .将多边形切割成不重叠的部分,并且对于每一部分 .计算重叠发生的次数。
我用谷歌搜索找到了几个例子,但 none 显示了完整的答案。例如,这是一个切割多边形(基于: PostGIS equivalent of ArcMap Union )但如果多边形有孔则不能正确切割。而且我不知道如何添加计算重叠的列:
WITH forest AS (
SELECT *
FROM (VALUES
(1,ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0) ,(1 1, 1 3, 3 3, 3 1, 1 1))',0))
,(2,ST_GeomFromText('POLYGON((10 0,20 0,20 10,10 10,10 0))',0))
,(3,ST_GeomFromText('POLYGON((2 2,4 2,4 4,2 4,2 2))',0)) /* hole in first */
,(4,ST_GeomFromText('POLYGON((8 5,12 5,12 9,8 9,8 5))',0)) /* overlapping */
,(5,ST_GeomFromText('POLYGON((12 2,14 2,14 4,12 4,12 2))',0)) /* hole in second */
) forest(id, geom)
)
SELECT
(dump).path[1] id,
(dump).geom
FROM
(
-- c) Polygonize the unioned rings (returns a GEOMETRYCOLLECTION)
-- Dump them to return individual geometries
SELECT
ST_Dump(ST_Polygonize(geom)) dump
FROM
(
-- b) Union all rings in one big geometry
SELECT
ST_Union(geom) geom
FROM
(
-- a) First get the exterior ring from all geoms
SELECT
ST_ExteriorRing(geom) geom
FROM
forest
) a
) b
) c
输入:
结果:
此处引用的答案需要自定义扩展:https://gis.stackexchange.com/questions/300800/get-single-part-polygon-by-their-intersection-in-postgis 虽然包括正确的重叠计数和处理孔,但结果也包含重叠的多边形。
WITH geomtable AS (
SELECT 1 id, ST_GeomFromText('POLYGON((0 1, 3 2, 3 0, 0 1), (1.5 1.333, 2 1.333, 2 0.666, 1.5 0.666, 1.5 1.333))') geom
UNION ALL
SELECT 2 id, ST_GeomFromText('POLYGON((1 1, 3.8 2, 4 0, 1 1))') geom
UNION ALL
SELECT 3 id, ST_GeomFromText('POLYGON((2 1, 4.6 2, 5 0, 2 1))') geom
UNION ALL
SELECT 4 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))') geom
UNION ALL
SELECT 5 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))') geom
UNION ALL
SELECT 6 id, ST_GeomFromText('POLYGON((1.75 1, 1 2, 2 2, 1.75 1))') geom
), parts AS (
SELECT a.id, unnest(ST_SplitAgg(a.geom, b.geom, 0.00001)) geom
FROM geomtable a,
geomtable b
WHERE ST_Equals(a.geom, b.geom) OR
ST_Contains(a.geom, b.geom) OR
ST_Contains(b.geom, a.geom) OR
ST_Overlaps(a.geom, b.geom)
GROUP BY a.id, ST_AsEWKB(a.geom)
)
SELECT count(*) nb, ST_Union(geom) geom
FROM parts
GROUP BY ST_Centroid(geom)
结果:
我希望有一种方法可以通过一些调整使其适用于所有类型的多边形...
所以,我再次回答我自己的问题...
这是我想出来的,希望它能帮助其他遇到类似问题的人:
。此代码适用于带孔的多边形(至少对于我测试的情况);
。有两部分:第一部分将多个重叠的多边形分割成单独的部分,第二部分检查(对于每个部分中的一个点)它与多少输入多边形相交;
。此代码将处理 'a few' 重叠的多边形,但未在大型表上进行测试 - 如果输入数据被正确索引,则可以提高性能。
WITH forest AS (
SELECT *
FROM (VALUES
(1,ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(1 1, 1 3, 3 3, 3 1, 1 1))',0))
,(2,ST_GeomFromText('POLYGON((10 0,20 0,20 10,10 10,10 0))',0))
,(3,ST_GeomFromText('POLYGON((2 2,4 2,4 4,2 4,2 2))',0)) /* hole in first */
,(4,ST_GeomFromText('POLYGON((8 5,12 5,12 9,8 9,8 5))',0)) /* overlapping */
,(5,ST_GeomFromText('POLYGON((12 2,14 2,14 4,12 4,12 2))',0)) /* hole in second */
) forest(id, geom)
), parts AS(
SELECT path[1] id, geom FROM ST_Dump((
SELECT ST_Polygonize(the_geom) AS the_geom FROM (
SELECT ST_Union(the_geom) AS the_geom FROM (
SELECT ST_Boundary(geom) AS the_geom FROM forest) AS lines
) AS noded_lines
)
))
SELECT a.geom, count(*) nb
FROM parts a , forest b
WHERE ST_Within(ST_PointOnSurface(a.geom),b.geom)
GROUP BY a.id, a.geom