🐘
PostGISでポリゴンを分割
市町村ポリゴンを取り扱うとき、1つのポリゴンではサイズが大きすぎて、複数の適度なサイズに分割したい場合もあると思います。SQL文を駆使すれば、よしなに分割することが可能です。
実行環境
- Apple M1(macOS Monterery)
- PostgreSQL 13.6
- PostGIS 3.2
予めデータベースに入れておいた行政区画ポリゴンを選択します。
今回は北海道北見市を例としてますが、ここの箇所は各自環境によります。
CREATE TABLE area AS
SELECT * FROM administrative_border_polygon WHERE name = 'kitami'
ST_GeneratePoints
でポリゴン内にランダムでポイントを生成します。生成されるポイントはMultiPointのため、ST_Dump
で各ポイントを抽出します。geometryの抽出は.geom
で行います。
CREATE TABLE area_pts AS
SELECT (ST_Dump(ST_GeneratePoints(geom,2000))).geom AS geom
FROM area
ST_ClusterKMeans
でクラスタを生成します。ST_ClusterKMeansはWindow関数のためover句を付ける必要があります。
CREATE TABLE area_pts_clustered AS
SELECT geom, ST_ClusterKMeans(geom, 20) over () AS cluster
FROM area_pts
各クラスタのポイントをST_Collect
でMultiPoint化したうえで、ST_Centroid
で各クラスタの重心を求めます。
CREATE TABLE area_centers AS
SELECT cluster, ST_Centroid(ST_collect(geom)) AS geom
FROM area_pts_clustered
GROUP BY cluster
ST_VoronoiPolygons
で各クラスタ重心を母点したボロノイ分割を行います。
CREATE TABLE area_volonoi AS
SELECT (ST_Dump(ST_VoronoiPolygons(ST_collect(geom)))).geom AS geom
FROM area_centers
ボロノイ分割したgeometryをST_Intersection
にて当初のポリゴン形状で抽出します。
CREATE TABLE area_divided AS
SELECT ST_Intersection(a.geom, b.geom) AS geom
FROM area a
CROSS JOIN area_volonoi b
最後に、今までのSQL文を一つにまとめましょう。
CREATE VIEW area_divided AS
SELECT ST_Intersection(a.geom, b.geom) AS geom
FROM (
SELECT *
FROM administrative_border_polygon
WHERE name = 'kitami'
) a
CROSS JOIN (
SELECT (ST_Dump(ST_VoronoiPolygons(ST_collect(geom)))).geom AS geom
FROM (
SELECT cluster, ST_Centroid(ST_collect(geom)) AS geom
FROM (
SELECT geom, ST_ClusterKMeans(geom, 10) over () AS cluster
FROM (
SELECT (ST_Dump(ST_GeneratePoints(geom,2000))).geom AS geom
FROM (
SELECT * FROM administrative_border_polygon
WHERE name = 'kitami')
AS area)
AS area_pts)
AS area_pts_clustered2
GROUP BY cluster
)
AS area_centers
) b
参考サイト
Discussion