空间数据圆转多边形

很多最开始接触WebGIS的人,当业务需求中需要生成保存圆这种空间类型的时候都会感到困惑,不知道该如何保存圆这种类型以及用圆来进行空间查询。其实处理起来也很简单,把圆当成n正多边形来处理就行了。

PostGIS空间类型

PostGIS基于OGC的“Simple Feature for Specification for SQL”规范,在PostgreSQL Geometry对象上实现了一系列的GIS Object(地物对象),列出所有空间类型的WKT描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
点:
POINT(0 0)
线:
LINESTRING(0 0,1 1,1 2)
面:
POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))
多点:
MULTIPOINT((0 0),(1 2))
多线:
MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))
多面:
MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))
几何集合:
GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))

所以至少现阶段PostGIS没有办法存储圆这种空间数据类型。

圆转多边形

所以很多时候都是将圆转成多边形或者使用ST_Buffer函数,将圆转成多边形虽然会损失一定的精度,但是对于一般的WebGIS业务系统来说这种误差都是可以忽略的,同时也可以增大多边形的边数,逼近完美的圆。
JavaScript转换的函数为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* [circleToPolygon description]
* @param Array center 圆的中心点
* @param Number radius 圆的半径
* @param Number section 将圆转为多少边形
* @return Array 返回将圆转换成的多边形
*/
function circleToPolygon (center, radius, section = 32) {

let polygon = [];
let multi = [];
let x,y;

for (var i = section; i >= 0; i--) {
x = center[0] + radius * Math.cos((2 * i * Math.PI) / section);
y = center[1] + radius * Math.sin((2 * i * Math.PI) / section);
multi.push([x, y]);
}

polygon.push(multi);

return polygon;

}

通常将圆转换成32多边形将在较小的比例尺下几乎看不出区别,其实PostGIS的ST_Buffer在获得的默认缓冲区本质上就是一个32多边形。

1
SELECT ST_AsText(ST_Buffer(ST_MakePoint(0,0),100));

1
POLYGON((100 0,98.0785280403231 -19.5090322016128,92.3879532511287 -38.2683432365089,83.1469612302546 -55.5570233019602,70.7106781186548 -70.7106781186547,55.5570233019603 -83.1469612302545,38.2683432365091 -92.3879532511286,19.509032201613 -98.078528040323,0 -100,-19.5090322016126 -98.0785280403231,-38.2683432365088 -92.3879532511287,-55.5570233019601 -83.1469612302546,-70.7106781186546 -70.7106781186549,-83.1469612302544 -55.5570233019604,-92.3879532511286 -38.2683432365092,-98.078528040323 -19.5090322016131,-100 0,-98.0785280403231 19.5090322016125,-92.3879532511288 38.2683432365086,-83.1469612302547 55.5570233019599,-70.710678118655 70.7106781186545,-55.5570233019606 83.1469612302543,-38.2683432365094 92.3879532511285,-19.5090322016132 98.078528040323,0 100,19.5090322016125 98.0785280403231,38.2683432365087 92.3879532511288,55.55702330196 83.1469612302547,70.7106781186545 70.710678118655,83.1469612302544 55.5570233019604,92.3879532511286 38.2683432365092,98.078528040323 19.509032201613,100 0))