基於PostGIS的高階應用(5)–PolygonSpliting
一 案例背景
PostGIS提供了豐富的function用於GIS資料的儲存,後設資料描述,空間分析,測量,空間圖形處理等等,這些函式基本上都很簡單,遇到合適的場景時,很容易能知道應該選用哪種function去解決。但有時候的圖形處理問題並不是很簡單就能實現的,PostGIS核心成員就遇到了社群提出的一個問題:
PostGIS是否有方法能將一個Polygon面切割成若干份小的Polygon面,且每一份的面積差不多大?
其第一反應是:
不可以吧,如此複雜的問題不是sql能解決的。
打臉的是,PostGIS開發者Darafei Praliaskouski解決了這個問題,並分享瞭解決步驟。本文作者,也就是我,僅僅負責稍微整理下,搬運了下大神們的解決方案,非個人原創。要看原文的朋友,可訪問原文:《PostGIS Polygon Splitting》
二 切割步驟
Darafei Praliaskouski提供的切割步驟如下:
- 使用ST_GeneratePoints方法將一個polygon轉換成與面積成比例的一系列的點 (點越多,效果越好,大約1000個點為宜)。
- 假設計劃將Polygon切成k等份,則使用ST_ClusterKMeans方法將這些轉換後的點聚合成k簇。
- 使用ST_Centroid方法求出每一簇的的均值中心。
- 將求出的均值中心作為ST_VoronoiPolygons方法的輸入引數,可以計算出每個點對映出的Polygon面。
- 使用ST_Intersection將這些對映的面和初始化的Polygon做切割處理,得到結果。
靈活使用PostGIS的方法,將如此複雜的問題,簡單的解決了,堪稱完美。
四 實踐總結
百聞不如一見,百看不如一試試,本文作者就是我,看完覺得很贊,於是決定抄抄看看,如何將南京切割成大小相等的十個面,感興趣的朋友可以按照我的步驟也可以測試測試。
準備測試資料:
- 將測試資料寫入臨時表:
create table nanjing as select name,geom from city where name=`南京市`;
- 面轉換為點:
CREATE TABLE nanjing_points AS SELECT (ST_Dump(ST_GeneratePoints(geom, 2000))).geom
AS geom FROM nanjing;
- 點聚合成簇(看原文方法的朋友請注意他的ST_ClusterKMeans寫錯了)
CREATE TABLE nanjing_pts_clustered AS
SELECT geom, ST_ClusterKMeans(geom, 10) over () AS cluster FROM nanjing_points;
- 獲取每一簇的均值中心
CREATE TABLE nanjing_centers AS SELECT cluster, ST_Centroid(ST_collect(geom)) AS geom
FROM nanjing_pts_clustered GROUP BY cluster;
- 使用voronoi演算法生成面
CREATE TABLE nanjing_voronoi AS
SELECT (ST_Dump(ST_VoronoiPolygons(ST_collect(geom)))).geom AS geom
FROM nanjing_centers;
- 使用ST_Intersection方法切割
CREATE TABLE nanjing_divided AS
SELECT ST_Intersection(a.geom, b.geom) AS geom
FROM nanjing a
CROSS JOIN nanjing_voronoi b;
一個個寫sql生成的臨時表寫邏輯方便,但是使用起來比較費勁,我們可以寫個function去處理,我使用了臨時表,怕事務併發衝突,加了uuid字尾。其實這個邏輯不是很複雜的話,多套用幾個with中間表也可以,但是寫多了不是很清晰,我就暫時套用上面表的邏輯改成臨時表做了個事務,測試通過了:
create extension "uuid-ossp";--建立下uuid的擴充套件
create or replace function freegis_polygon_split(
in split_geom geometry(Polygon),--輸入的面
in split_num int,--分割的數量
out geom geometry(Polygon)--輸出切割的面
) returns setof geometry as
$$
declare
rec record;
temp_points text;
temp_ClusterKMeans text;
temp_ClusterCentroid text;
temp_VoronoiPolygons text;
begin
--防止併發的時候,臨時表名稱衝突
temp_points:=`temp_points`||uuid_generate_v4();
temp_ClusterKMeans:=`temp_ClusterKMeans`||uuid_generate_v4();
temp_ClusterCentroid:=`temp_ClusterCentroid`||uuid_generate_v4();
temp_VoronoiPolygons:=`temp_VoronoiPolygons`||uuid_generate_v4();
--生成點
execute format(`create temp table "%s" on commit drop as
SELECT row_number() over() as gid,(ST_Dump(ST_GeneratePoints($1, 2000))).geom`,temp_points) using split_geom;
--點成簇
execute format(`create temp table "%s" on commit drop as SELECT t.geom, ST_ClusterKMeans(t.geom, $1) over () AS cluster from "%s" t`,temp_ClusterKMeans,temp_points) using split_num;
--簇的中心點
execute format(`create temp table "%s" on commit drop as SELECT t.cluster, ST_Centroid(ST_collect(t.geom)) AS geom FROM "%s" t GROUP BY t.cluster`,temp_ClusterCentroid,temp_ClusterKMeans);
--voronoi構造面
execute format(`create temp table "%s" on commit drop as SELECT (ST_Dump(ST_VoronoiPolygons(ST_collect(t.geom)))).geom AS geom FROM "%s" t`,temp_VoronoiPolygons,temp_ClusterCentroid);
--intersection切割
for rec in execute format(`SELECT ST_Intersection($1, b.geom) AS geom FROM "%s" b`,temp_VoronoiPolygons) using split_geom loop
geom:=rec.geom;
return next;
end loop;
return;
end;
$$
language plpgsql strict;
測試下通過了:
結語:PostGIS還是很強大的!!!另外一定要自己練習。。。
相關文章
- 分享Python的5種高階特徵應用Python特徵
- Redis 高階應用Redis
- AWK高階應用
- 基於HTML5的移動Web應用HTMLWeb
- React 高階應用 -- 高階元件 Heigher Order ComponentReact元件
- 向量(高階的隨機化應用)隨機
- react 高階元件的 理解和應用React元件
- 「Mybatis系列」Mybatis高階應用MyBatis
- 基於 HTML5 Canvas 的拓撲元件 ToolTip 應用HTMLCanvas元件
- Docker 運維高階應用管理Docker運維
- LVS高階應用-會話保持會話
- ansible高階應用ansible-vault
- 基於HTML5的移動Web應用——檔案操作HTMLWeb
- 基於 HTML5 的電力接線圖 SCADA 應用HTML
- 說說 vue-router 元件的高階應用Vue元件
- React 中的高階元件及其應用場景React元件
- MACD技術的高階應用--MACD與波浪Mac
- 基於flask的最小的應用Flask
- 高階玩法之類的裝飾器的應用
- C++高階應用_設計模式C++設計模式
- Hive 高階應用開發示例(一)Hive
- 基於HTML5的移動Web應用——Geolocation地理定位HTMLWeb
- kredis:用於Rails的Redis高階資料結構RedisAI資料結構
- STM32F103 高階應用(2)——中斷應用
- 基於Dapr的 Azure 容器應用
- 方案|基於高價效比5G工業閘道器的工業物聯網典型應用
- H5高階H5
- WinRAR初級中級高階等應用
- Jenkins 使用指南 之 高階應用篇Jenkins
- Spring AOP高階應用與原始碼剖析Spring原始碼
- RxJS進階——關於流的理解和應用JS
- 關於React的高階元件React元件
- ArkWeb頁面跳轉與跨應用導航 - 高階應用Web
- 深入理解 C++ 語法:從基礎知識到高階應用C++
- Quanergy釋出新版3D感知軟體,用於高階智慧城市和安全應用3D
- FTP-Vsftpd的高階應用:虛擬使用者FTP
- 基於Redis分散式BitMap的應用Redis分散式
- 基於SpringBoot的國際化應用Spring Boot