我正在寻找一种在PostGIS几何周围添加缓冲区的方法,但是缓冲区的大小应取决于几何的大小。也就是说,我希望每个几何图形都扩大5%。
我的想法是我正在寻找相交的几何,但是我想考虑的每个几何可能有多达5%的误差。
有人知道最好的方法吗?
该数据库的行数为一百万行,因此我希望它的运行速度相当快。
我正在寻找一种在PostGIS几何周围添加缓冲区的方法,但是缓冲区的大小应取决于几何的大小。也就是说,我希望每个几何图形都扩大5%。
我的想法是我正在寻找相交的几何,但是我想考虑的每个几何可能有多达5%的误差。
有人知道最好的方法吗?
该数据库的行数为一百万行,因此我希望它的运行速度相当快。
Answers:
评论表明不需要高精度地达到5%。(如果这样做,将需要很长时间来缓冲一百万个多边形!)因此,我们可以调用“ 比萨饼原理”:将2D要素线性缩放比例为一个因子,将其面积缩放为 ^ 2。
推理方法如下:
当形状不太复杂时(尤其是凸形时),缓冲产生的结果可与围绕中心点缩放比例相媲美。(但是,重要的是要理解,对于磁盘以外的任何形状,缓冲永远都不等同于重新缩放。对于某些凹形,通过重新缩放计算出的“缓冲区”实际上可能不包括原始形状本身的一部分!因此最终我们将计算形状的真实缓冲区,但仅将这种近似等价作为启发式方法来估算要缓冲的量。)
如果缓冲区域要大5%,则重新缩放的大小应为sqrt(1 + 5/100),接近1.025:也就是说,我们应该在所有方向上将形状扩展2.5% 。
同样,如果我们认为形状具有“直径”(等于典型的跨距),则其半径应增加2.5%。等于直径的2.5%/ 2 = 1.25%。
我们可以从形状的边界框估算出典型直径。例如,使用盒子侧面长度的算术或几何平均值。
这建议以下工作流程:
获取形状的边界框。
令e为盒子的边长的平均值。
用e的1.25%缓冲形状;也就是说,乘以(5/100)/ 4 * e。
因为步骤1和2需要很少的计算,所以它本身就是最快速的解决方案之一。作为准确性检查,您可以(当然)计算缓冲形状的面积并将它们与原始面积进行比较,以查看它们达到所需的5%增长的程度。有时,缓冲区的大小会大于5%,但很少有缓冲区会变小,并且不可能将缓冲区显着减小。
作为检查和说明,让我们考虑一些简单的形状。
半径为r的磁盘具有一个边长为2 r的边界框。我们的公式计算出e =(5/100)/ 4 * 2 * r = r /40。缓冲的形状显然是半径r + r / 40 = 1.025 r的同心圆盘。旧区域为pi * r ^ 2,而新区域为pi *(1.025 r)^ 2 = pi * 1.0506 * r ^ 2,增加了5.06%。
边与长度为r和s的坐标轴平行的矩形给出e =(r + s)/ 2。缓冲矩形产生的额外区域来自四个以边为边界的宽度(5/100)/ 4 e = e / 80 =(r + s)/ 160的矩形,以及在拐角处四个半径为e / 80的四分之一圆。忽略四分之一圆,该四分之一圆与其他区域相比要小,所以新的总面积等于
2(r + s)*(r + s)/ 160 =(r ^ 2 + s ^ 2 + 2 r * s)/ 80。
当r和s差别不大时,我们可以得出r ^ 2 + s ^ 2约为2 r * s。这种近似将新的总面积简化为4 r * s / 80 = r * s原始面积的5%。
我想将ST_Scale(http://postgis.net/docs/ST_Scale.html)和ST_Translate(http://postgis.net/docs/ST_Translate.html)结合使用。我们在PostGIS in Action中有一个示例,在第8章中也有类似示例。如果您没有这本书,则可以在此处下载该章的代码:
http://www.postgis.us/chapter_08
书中的片段请看示例8.26:
-- Listing 8.26 Combining Scale and Translation to maintain centroid
SELECT xfactor, yfactor,
ST_Translate(ST_Scale(hex.the_geom, xfactor, yfactor),
ST_X(ST_Centroid(the_geom))*(1 - xfactor),
ST_Y(ST_Centroid(the_geom))*(1 - yfactor) ) As scaled_geometry
FROM
( SELECT ST_GeomFromText('POLYGON((0 0,64 64,64 128,0 192,-64 128,-64 64,0 0))') As the_geom) As hex
CROSS JOIN (SELECT x*0.5 As xfactor
FROM generate_series(1,4) As x) As xf
CROSS JOIN (SELECT y*0.5 As yfactor
FROM generate_series(1,4) As y) As yf;
ST_Transscale
但不知