目录
前言
一、原始数据介绍
1、原始完整数据
2、Qgis中展示原始数据
二、减少数据精度
1、查询函数简介
2、减少精度实战
三、ST_Simplify抽稀实现
1、ST_Simplify函数介绍
2、ST_Simplify抽稀结果
四、ST_SimplifyPreserveTopology抽稀
1、函数介绍
2、抽稀结果
五、总结
前言
在地理信息系统(GIS)的广阔领域中,空间数据的处理与存储始终占据着核心地位。随着大数据时代的到来,空间数据的规模与复杂性日益增加,如何高效地处理这些数据,成为了一个亟待解决的问题。PostGIS,作为PostgreSQL的一个强大扩展,为空间数据的存储、查询与分析提供了丰富的功能。其中,抽稀(Simplification)技术作为PostGIS的一项重要功能,正逐渐成为优化空间数据处理的关键手段。抽稀,简而言之,是对空间数据进行简化处理的过程,旨在减少数据中的冗余信息,同时保持数据的核心特征和几何关系。在PostGIS中,抽稀技术通过一系列算法实现,这些算法能够智能地识别并去除那些对整体形状影响较小的点,从而在保持数据精度的前提下,大幅度降低数据的复杂度。
实现抽稀的关键在于选择合适的算法和参数。PostGIS提供了多种抽稀算法,如经典的道格拉斯-普克(Douglas-Peucker)算法,以及基于视口(Viewport)和拓扑保持(Topology Preservation)的变体算法。这些算法各具特色,适用于不同的应用场景。例如,道格拉斯-普克算法通过设定一个距离阈值,能够高效地去除那些对曲线形状影响较小的点;而基于视口的算法则能够根据不同的地图缩放级别,动态地调整抽稀的程度,以适应不同的展示需求。抽稀技术在PostGIS中的应用广泛而深入。在GPS轨迹数据的处理中,抽稀技术能够显著减少数据点的数量,从而加快数据的加载和渲染速度,提升用户体验。在行政区划图的展示中,通过抽稀技术,可以在保持图形形状和拓扑关系的前提下,减少图形的节点密度,提高渲染效率。此外,在大数据展示、网络分析、空间索引构建等场景中,抽稀技术也发挥着重要作用。然而,抽稀技术的应用并非毫无挑战。如何选择合适的算法和参数,以在保持数据精度和性能之间找到最佳平衡点,是一个需要深入研究和实验的问题。此外,抽稀过程中可能引入的误差和变形,也需要通过有效的质量控制手段进行监测和纠正。
本文将重点讲解如何在PostGIS进行数据抽稀的实战,以我们之前展示过的全球国家Polygon面数据为例。文章首先介绍通过减少返回数据坐标精度的方式来减少返回数据的大小,然后介绍基于st_simplify简单抽稀的方式来减少数据大小,最后介绍基于st_simplifypreservetopology函数来进行抽稀。在文章阐述过程中,将抽稀后的数据与原始进行对比贯穿始终,让结果直观的展示在大家面前。抽稀是个动态复杂的过程,这里分享是简单的基于数据库的处理模式,实际在做大规模的数据分析时,还需要进行更加高效的处理或者采用更高效的算法。如果您对空间数据抽稀感兴趣,不妨来这里看看。
一、原始数据介绍
为了对各种简化和抽稀的方法的实际效果有一个明显的对比,有必要对最原始的数据进行一个说明,同时为了让面数据的坐标点尽量的多和复杂,这样更能凸显出抽稀的实际效果。这里我们不采用国土面积最大的国家作为实例,而是采用多面的复杂国家-印度尼西亚。在前面介绍过,印度尼西亚有上17508个岛屿,国土面积构成基本满足我们的需求。
1、原始完整数据
在之前的全球国家范围入库及可视化管理当中,我们已经将所有的国家保存到PostGIS数据库中。因此,这里我们直接利用PostGIS数据库来进行空间数据的查询,为了对边界信息进行可视化,我们使用st_asgeojson函数将Geometry数据转换成GeoJSON,然后在Qgis软件中进行展示。后面其它的抽稀函数也是采用这种方式,然后在Qgis中对不同的GeoJSON面数据进行空间叠加,对比其边界来展示数据处理后的效果。
在PostGIS数据库中,查询对应国家的GeoJSON的sql语句如下:
select st_asgeojson(geom) as j1 from biz_world_country where short_chinese_name = '印度尼西亚';
在数据库客户端执行上面的语句后,可以得到以下的查询结果:
2、Qgis中展示原始数据
当我们得到完整的原始数据后,可以将所有的geojson数据直接复制到本地,命名为:yn-full.geojson。将数据库执行结果中的所有GeoJSON文本直接复制到之前新建的geojson文件中。然后在QGIS当中直接展示这个geojson文件。打开之后可以看到以下的矢量边界范围。
在Qgis当中放大局部边界,可以看到,由于我们保留了完整的原始数据,数据的边界面边线还是比较完整的。 尤其是一些细小海岛的矢量边界。
下面将在上述的数据基础上,我们使用三种方式来对面数据的数据量进行减少的详细案例和说明。
二、减少数据精度
之所以这里提减少数据精度,严格意义上来说。数据精度的减少指的是减少返回点的经纬度的精度。通过减少精度来减少返回数据包的大小,从而提高加载速度。这种方式其实也是非常好的方式,通过精度的减少,也能有效减少返回的数据量。这里首先介绍这种方式。
1、查询函数简介
在PostGIS当中,使用st_asgeojson函数将GeoMetry对象转换成GeoJSON,GeoJSON在绝大多数的前端组件中是可以直接进行界面展示的,因此对前端友好。那么我们首先来看一起st_asgeojson方法的官方定义。我们在PostGIS数据库中的函数库中可以看到如下定义:
CREATE OR REPLACE FUNCTION "public"."st_asgeojson"("geom" "public"."geometry", "maxdecimaldigits" int4=9, "options" int4=8)
RETURNS "pg_catalog"."text" AS '$libdir/postgis-3', 'LWGEOM_asGeoJson'
LANGUAGE c IMMUTABLE STRICT
COST 500
通过以上函数体定义可以看到,这个方法是将几何图形作为GeoJSON“几何图形”返回,或将行作为GeoJSON“要素”返回。(请参阅 GeoJSON规范RFC 7946 )。同时支持2D和3D几何图形。GeoJSON仅支持SFS 1.1几何体类型(例如,不支持曲线)。在这个方法中,第一个参数表示空间对象,第二个 maxdecimaldigits
参数可用于减少输出中使用的最大小数位数(默认为9)。如果您使用的是EPSG:4326并且输出的几何图形仅用于显示, maxdecimaldigits
=6对于许多贴图来说可能是一个很好的选择。
温馨提示:使用
最大小数位数
参数可能会导致输出几何图形无效。为了避免这种使用 ST_ReducePrecision 首先要有一个合适的网格大小。
这个 options 参数可用于在GeoJSON输出中添加BBox或CRS:
0:表示无选项
1:GeoJSON BBox
2:GeoJSON短CRS(例如EPSG:4326)
4:GeoJSON长CRS(例如urn:ogc:def:crs:epsg::4326)
8:GeoJSON短CRS,如果不是EPSG:4326(默认)
GeoJSON规范规定,使用右手规则来确定多边形的方向,有些客户端要求使用此方向。这可以通过使用 ST_ForcePolygonCCW 。规范还要求几何图形采用WGS84坐标系(SRID=4326)。如有必要,可以使用将几何图形投影到WGS84中 ST_Transform : ST_Transform( geom, 4326 ) 。
2、减少精度实战
在了解了上述的函数及其参数说明之后,我们就可以在其参数上做一些文章,比如这里的maxdecimaldigits
,指的就是小数点后数字的长度。默认的情况下是9位,如下所示:
[114.242362976,-3.409444332]
而针对面数据,其包含非常多的连续坐标。因此如果能大大的减少数据精度,那么返回的整体数据也将变得很客观。 按照管网文档的建议,我们将精度有默认的9位减少到6位,使用的查询sql如下:
select st_asgeojson(geom),st_asgeojson(geom, 6) from biz_world_country where short_chinese_name = '印度尼西亚';
按照之前的方法,我们将使用6位长度的GeoJSON保存到本地,重命名为yn-full6.geojson。通过对比这两个文件的大小不难发现,原始文件的大小是: 2420KB,而采用精度缩短的方式,得到的文件大小是:1906KB,虽然还是比较大,但是实际大小是变小了,文件的压缩率是:78%。不是很明显,但是有效果。在Qgis中来看一下处理之后的数据:
你会发现,虽然在坐标经纬度的精度上做了压缩,但是对数据的边界展示影响不大,几乎没有发现有边界不吻合的情况。可以放大局部坐标观察,依然是保持吻合的状态,重点是看一些边缘的边界处理情况。
可以看到,采用经纬度精度缩短的方案,对于减少数据量大小有一定的作用,但是对边界的影响几乎没有,跟缩小精度之前的编辑保持一致。
三、ST_Simplify抽稀实现
上面的介绍方式其实不是抽稀的实现,从这一节开始,就真正的来介绍如何在PostGIS当中实现抽稀。由简到难,首先来介绍简单的抽稀实现,再来介绍稍微复杂一点的。因此本节首先介绍ST_Simplify这个方法。
1、ST_Simplify函数介绍
首先我们在数据库的函数库中找一下ST_Simplify这个函数,看一下它的定义,如下所示:
CREATE OR REPLACE FUNCTION "public"."st_simplify"("public"."geometry", float8, bool)
RETURNS "public"."geometry" AS '$libdir/postgis-3', 'LWGEOM_simplify2d'
LANGUAGE c IMMUTABLE STRICT
COST 50
ST_Simplify是使用Douglas-Peucker算法计算几何图形的简化表示。简化的tolerance
是一个距离值,以输入SRS的单位为准。简化会移除在简化线条的公差距离内的顶点。即使输入是有效的,结果可能不是有效的。该函数可用于任何类型的几何图形(包括GeometryCollections),但只有线和多边形元素会被简化。线性几何的端点将被保留。
preserveCollapsed
标志保留那些在给定公差下本应被移除的小几何图形。例如,如果将一个1米长的线条使用10米的公差进行简化,当preserveCollapsed
为true时,该线条将不会消失。这个标志对于渲染目的很有用,以防止地图上非常小的特征消失。
返回的几何图形可能会失去其简单性(参见ST_IsSimple),拓扑可能不会被保留,并且多边形结果可能是无效的(参见ST_IsValid)。使用ST_SimplifyPreserveTopology来保留拓扑并确保有效性。
2、ST_Simplify抽稀结果
使用ST_Simplify进行抽稀最重要的参数就是系数。PostGIS会根据我们传入的系数来进行对应的抽稀操作。这里我们采用多组样本来进行展示。比如分别采用0.85,0.5,0.1,0.05,0.01等等。这些值其实都是经验值,不同的值它的处理之后的数据是不一样的。这里我根据本次的测试数据给出一个表格,供大家参考:
序号 | 抽稀系数 | 抽稀后文件大小 | 抽稀后文件占比 | 边界吻合度 |
1 | 0.85 | 3KB | 0.1% | 差异明显 |
2 | 0.5 | 4KB | 0.1% | 差异明显 |
3 | 0.1 | 30KB | 1.2% | 有差异 |
4 | 0.05 | 67KB | 2.7% | 有差异 |
5 | 0.01 | 367KB | 15.16% | 有一定差异 |
使用ST_Simplify 是一个双刃剑,在数据总量和数据质量上需要平衡,如果抽稀系数太大,文件大小可以急剧下降,但是返回数据的边界信息也会极大的受到影响。以0.5的抽稀率来看一下整体的效果,如下图所示:
不细致看的话基本是看不出来的,但是我们放大到局部再来看一些边界信息:
可以看到,使用了抽稀之后,数据的数据减少了,但是边界信息也极大的减少了。0.5减少了很多的数据,一些岛屿直接都被抹掉了,因此0.5的系数高。实际情况中,我们的抽稀率不会定的这么高,会低许多 。如果大家在实战过程中会使用到这个数据,必须要进行计算,不能随便抽稀,否则返回的数据在后面将无法进行更优质的空间分析。抽稀掉的数据很多空间范围被删除了。这肯定是不允许的。
四、ST_SimplifyPreserveTopology抽稀
既然有了ST_Simplify,为什么还要介绍st_simplifypreservetopology呢。在PostGIS中,使用ST_Simplify函数对多边形对象进行抽稀时,如果需要保持边界的吻合,可以考虑使用ST_SimplifyPreserveTopology函数。这个函数是ST_Simplify的一个变体,它使用Douglas-Peucker算法来计算几何图形的简化表示,同时限制简化以确保结果具有与输入相同的拓扑。这意味着,只要保留拓扑,简化会移除在简化线条的公差距离内的顶点,但如果输入是有效和简单的,则结果也将是有效和简单的。因此使用ST_SimplifyPreserveTopology函数时,对于多边形输入,结果将具有相同数量的环(外壳和内环),并且这些环不会相交。环的端点可能会被简化,但整体的拓扑结构将被保留,从而保持边界的吻合。如果多个面要保持边界的问题,就需要使用ST_SimplifyPreserveTopology函数支持。
1、函数介绍
首先我们在PostGIS函数库中看一下它的定义,如下代码所示:
CREATE OR REPLACE FUNCTION "public"."st_simplifypreservetopology"("public"."geometry", float8)
RETURNS "public"."geometry" AS '$libdir/postgis-3', 'topologypreservesimplify'
LANGUAGE c IMMUTABLE STRICT
COST 10000
从参数列表来看,与st_simplify差不多。都是通过控制容差系数来进行抽稀实现的。结合印尼的国家面查询,其实现的SQL语句如下所示:
select st_asgeojson(st_simplifypreservetopology(geom, 0.005)) from biz_world_country where short_chinese_name = '印度尼西亚';
2、抽稀结果
同样的,为了对抽稀效果有一个直观的对比,这里也采用不同的抽稀系数,然后对比不同抽稀系数下的GeoJSON文件大小以及空间数据的损耗情况进行综合的对比。
序号 | 抽稀系数 | 抽稀后文件大小 | 抽稀后文件占比 | 边界吻合度 |
1 | 0.5 | 283KB | 12% | 有一定差异 |
2 | 0.05 | 327KB | 13.5% | 有一定差异 |
3 | 0.01 | 532KB | 22% | 差异较小 |
4 | 0.005 | 755KB | 31% | 差异较小 |
通过实例可以看到,从整体的效果来看,差别并不大。然后我们来看一些细节的处理。
图中,黄色是兼容拓扑边界的抽稀实现,而另外一种颜色是简单抽稀。简单抽稀的方法直接将一些小面积的海岛直接抽稀掉了。对数据的影响较大。因此建议在进行面数据的抽稀时采用这里的方式。能极大的保留数据的原始边界。
五、总结
以上就是本文的主要内容,本文将重点讲解如何在PostGIS进行数据抽稀的实战,以我们之前展示过的全球国家Polygon面数据为例。文章首先介绍通过减少返回数据坐标精度的方式来减少返回数据的大小,然后介绍基于st_simplify简单抽稀的方式来减少数据大小,最后介绍基于st_simplifypreservetopology函数来进行抽稀。
深入探索PostGIS中的抽稀技术,不仅有助于我们更好地理解空间数据的处理机制,还能够为优化空间数据存储、查询与分析提供有力的支持。通过不断的研究和实践,我们可以逐步掌握抽稀技术的精髓,将其应用于更广泛的场景中,推动GIS技术的持续发展和创新。总之,PostGIS中的抽稀技术是实现高效空间数据处理的关键。它不仅能够降低数据的复杂度,提升系统的性能,还能够为空间数据的可视化、分析和应用提供更为灵活和高效的解决方案。随着技术的不断进步和应用场景的不断拓展,我们有理由相信,抽稀技术将在GIS领域发挥越来越重要的作用。行文仓促,定有许多不足之处,如有不足还恳请各位专家博主在评论区留言批评指正,不甚感谢。