这个问题是我在计算公交站点覆盖率(公交300米范围面积/服务区面积)中遇到的。
有以下两种计算方式
1、ArcGIS
使用buffer(缓冲区)工具,将所有的公交站点生成300米的缓冲圆
注意:融合类型选择为全部
2、自己实现
之前以为这个计算应该不难,用纯数学计算就可以求得结果,但是接下来的问题让我陷入了对人生的思考,经过查找文献,得到以下结论。
1)两圆重叠—简单!!!
2)两个圆以上的重叠精确计算—数学界的世纪难题!!!
所以,只能通过模拟计算,这也是计算机最初诞生的原因。
经典的蒙特卡洛模拟计算真是屡试不爽。
这里我以前端的JavaScript为例
情景:在地图上随机框画了一个圆形区域,框选区域内部有若干个公交站点
通过模拟计算的流程是这样:
代码脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
function calculateStopCoverRate(sample, drawCircleToPolygon, stopsLngLatList, distance) { let insidePointsNumber = 0; let randomPoints = turf.random('points', sample, {bbox: drawCircleToPolygon.getExtent()}).features.map(value => value.geometry.coordinates); for (let m = 0, n = randomPoints.length; m < n; m++) { for (let i = 0, j = stopsLngLatList.length; i < j; i++) { let centerRandomPoint = ol.proj.fromLonLat([randomPoints[m][0], randomPoints[m][1]]); if (Math.pow(centerRandomPoint[0] - stopsLngLatList[i][0], 2) + Math.pow(centerRandomPoint[1] - stopsLngLatList[i][1], 2) <= distance * distance) { insidePointsNumber = insidePointsNumber + 1; break } } } return (insidePointsNumber / sample * 100).toFixed(2) + ' %'; }
|
1)首先引入turf插件,使用turf.random在所画的圆内生成随机点,获取每个随机点的坐标;
2)使用openlayers的ol.proj.fromLonLat转换方法,将经纬度转为平面坐标;
3)计算随机点是否在圈出的站点300米(distance)范围内,如果在,标记一下,break该点退出,计算下一个随机点,
4)用标记到在站点范围的统计数值insidePointsNumber除以样本值就是站点覆盖率,
5)同样,覆盖面积就等于所画圆的面积乘以覆盖率
**
sample 样本数数值越大,所需时间越长,计算结果越准确
关于蒙特卡洛,有很多有趣的事,比如计算Π值,古代的蒲丰投针
相比精确的数学计算,模拟计算有点玄学的意味,但不失为简单粗暴的途径。