基于PostGIS的高级应用(5)-- Polygon Spliting

简介:

一 案例背景

  PostGIS提供了丰富的function用于GIS数据的存储,元数据描述,空间分析,测量,空间图形处理等等,这些函数基本上都很简单,遇到合适的场景时,很容易能知道应该选用哪种function去解决。但有时候的图形处理问题并不是很简单就能实现的,PostGIS核心成员就遇到了社区提出的一个问题:

PostGIS是否有方法能将一个Polygon面切割成若干份小的Polygon面,且每一份的面积差不多大?

输入图形--切割前

输出图形--切割后

其第一反应是:

不可以吧,如此复杂的问题不是sql能解决的。

打脸的是,PostGIS开发者Darafei Praliaskouski解决了这个问题,并分享了解决步骤。本文作者,也就是我,仅仅负责稍微整理下,搬运了下大神们的解决方案,非个人原创。要看原文的朋友,可访问原文:《PostGIS Polygon Splitting》

二 切割步骤

Darafei Praliaskouski提供的切割步骤如下:

  • 使用ST_GeneratePoints方法将一个polygon转换成与面积成比例的一系列的点 (点越多,效果越好,大约1000个点为宜)。
    ST_GeneratePoints
  • 假设计划将Polygon切成k等份,则使用ST_ClusterKMeans方法将这些转换后的点聚合成k簇。
    ST_ClusterKMeans
  • 使用ST_Centroid方法求出每一簇的的均值中心。
    ST_Centroid
  • 将求出的均值中心作为ST_VoronoiPolygons方法的输入参数,可以计算出每个点映射出的Polygon面。
    ST_VoronoiPolygons
  • 使用ST_Intersection将这些映射的面和初始化的Polygon做切割处理,得到结果。
    ST_Intersection

灵活使用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;

ST_ClusterKMeans

  • 获取每一簇的均值中心
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;

voronoi

  • 使用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还是很强大的!!!另外一定要自己练习。。。

相关文章
MyBatisPlus+PostGIS实现Geometry数据的通用读写
MyBatisPlus+PostGIS实现Geometry数据的通用读写
583 0
|
存储 JSON 关系型数据库
基于GeoTools的GeoJson导入到PostGis实战
GeoJson是一种对各种地理数据结构进行编码的格式,基于json的地理空间信息数据交换格式。GeoJson对象可以用来表示几何,特征或者特征集合。支持地理点、线、面、多点、多线、多面及几何集合。GeoJson不是本文的重点,因此不再赘述。
1707 0
基于GeoTools的GeoJson导入到PostGis实战
|
数据可视化 前端开发 关系型数据库
基于Mybatis-Plus实现Geometry字段在PostGis空间数据库中的使用
本文讲解在mybatis-plus中操作geometry空间字段,同时实现查询和插入操作​。通过geojson,结合前端可视化组件即可完成​矢量数据的空间可视化。
2669 0
基于Mybatis-Plus实现Geometry字段在PostGis空间数据库中的使用
|
定位技术 Windows 关系型数据库
PostgreSQL GUI pgadmin4 v3.3 支持 gis geometry 数据编辑、显示
标签 PostgreSQL , pgadmin , gis , 编辑 背景 pgadmin 4 v3.3 开始支持geometry 类型的展示。 https://www.postgresql.org/ftp/pgadmin/pgadmin4/v3.3/windows/ 如果geometry使用的是SRID 4326 (WGS 84 lon/lat)坐标系,则pgadmin会自动从OpenStreetMap 加载图层,作为背景。
2110 0
|
2月前
|
存储 关系型数据库 数据库
PostGIS简介
PostGIS是PostgreSQL的扩展插件,增强其处理地理空间数据的能力,支持空间数据存储、索引、查询及分析等功能。它适用于2D和3D空间数据,提供多种几何类型和栅格数据支持,兼容多种第三方工具。安装需先配置EPEL和PowerTools仓库,然后通过DNF安装PostGIS包,并在目标数据库中启用扩展。PostGIS支持geometry、geography和raster等数据类型,适用于不同场景的空间数据分析。
107 0
|
4月前
|
存储 数据可视化 定位技术
Ganos矢量快显功能
Ganos的2D矢量快显功能提供了亿级二维矢量数据的高效可视化解决方案。通过创新性的稀疏金字塔索引技术,Ganos大幅减少了切片构建时间和存储开销,并支持动态更新。相较于传统离线切片方式,Ganos能在普通云实例上快速构建和更新切片,显著提升了响应速度和更新效率,同时大幅降低了存储需求。本文详细介绍如何使用Ganos进行2D矢量数据的准备、稀疏金字塔构建、切片获取及Web地图服务搭建,帮助读者快速上手体验这一高效功能。
46 1
|
4月前
|
存储 数据可视化 关系型数据库
Ganos矢量快显功能上手
Ganos是由阿里云数据库产品事业部与达摩院合作研发的新一代云原生位置智能引擎,集成于PolarDB、Lindorm、AnalyticDB和RDS PG等核心产品中。Ganos具备十大核心引擎,为数据库提供一体化时空数据处理能力。其2D矢量快显功能采用稀疏金字塔索引技术,显著缩短切片时间和减少存储开销,支持动态更新。通过简单的表结构准备和索引构建,用户可快速实现高效的数据可视化。此外,Ganos还支持3D矢量数据可视化,进一步拓展了应用场景。
59 0
|
关系型数据库
postgis相关插件介绍
postgis相关插件介绍
100 0
|
关系型数据库 数据库连接 数据库
空间数据库系列:PostGIS和qgis的数据连接
如何使用QGIS连接带postGIS扩展的postgresql数据库
855 0
|
Web App开发 关系型数据库 PostgreSQL