经纬度坐标为中心点生成米距离长度半径的圆形面,含java js源码+在线绘制,代码简单零依赖
- java版源码
- js版源码
- 在线绘制预览效果
- 关于计算的精确度
前些时间在更新我的坐标边界查询工具的时候,需要用到经纬度坐标点的距离计算,和以坐标点为中心生成一个指定距离为半径的圆,搜了一下没有找到现成简单又合适的代码,于是把自己压箱底的代码翻出来了,简化完善了一下,嘿,代码量也不大,还挺好用。
本方法是通过计算得到圆上的多个坐标点,来得到的一个近似的圆形面,只要坐标点够多,这个圆就能足够圆;有了这些坐标点就很容易表示成不同的格式,比如:GeoJSON文本、WKT文本、Geometry实例。
源自 坐标边界查询工具 开源库:https://github.com/xiangyuecn/AreaCity-Query-Geometry (github可以换成gitee),高性能的坐标数据、边界数据查询工具,Java开源程序、带http查询接口,内存占用低(1秒可查1万个以上坐标对应的城市信息)。
java版源码
js版源码
在线绘制预览效果
生成了圆形面的WKT文本后,可以粘贴进在线预览页面绘制显示:https://xiangyuecn.gitee.io/areacity-jsspider-statsgov/assets/geo-echarts.html ,方便代码调试,地图上有测距功能,可以测量圆面的准确度;页面上的画圆功能,采用的就是js版的代码。

关于计算的精确度
两个经纬度坐标的距离计算,采用的Haversine formula算法,下面的计算代码中高德地图的api同样是Haversine formula算法,和百度地图的计算结果误差在0.2%以内:
bMap=window.BMapGL&&BMapGL.Map.prototype||{getDistance:function(a,b){return BMap.Map.prototype.getDistance(new BMap.Point(a.lng,a.lat),new BMap.Point(b.lng,b.lat)) }};
//地图api计算【纬度】之间的距离,每一度之间的距离是相同的
bMap.getDistance({lng:111,lat:15},{lng:111,lat:16}) //百度111194.86米
new AMap.LngLat(111,15).distance(new AMap.LngLat(111,16)) //高德111319.49米
bMap.getDistance({lng:121,lat:55},{lng:121,lat:56}) //百度111194.78米
new AMap.LngLat(121,55).distance(new AMap.LngLat(121,56)) //高德111319.49米
//地图api计算【经度】之间的距离,会随着纬度的不同而不同
bMap.getDistance({lng:111,lat:15},{lng:112,lat:15}) //百度107405.91米
new AMap.LngLat(111,15).distance(new AMap.LngLat(112,15)) //高德107526.28米
bMap.getDistance({lng:111,lat:55},{lng:112,lat:55}) //百度63778.21米
new AMap.LngLat(111,55).distance(new AMap.LngLat(112,55)) //高德63849.69米
//经度在相同纬度下每一度之间的距离是相同的
bMap.getDistance({lng:121,lat:55},{lng:122,lat:55}) //百度63778.21米
new AMap.LngLat(121,55).distance(new AMap.LngLat(122,55)) //高德63849.69米
对于构成圆的坐标点的计算,使用的以前压箱底的代码,计算比较简单,经度和纬度分别计算出一度的距离长度,在等比例的换算出半径对应的度数大小,比如算出来的经度1°是100km,那么20km半径对应的度数就是1° * 20 / 100 = 0.2°。
- 纬度每一度之间的距离都是固定的长度,等比例换算后的结果是没有误差的。
- 经度每一度之间的距离长度会随着纬度变化,低纬度长高纬度短,圆面的上下纬度不同,半径小的时候误差小,半径越大误差越大。
所以按等比例换算在纬度上没有问题,但经度上会产生一定的误差,但只要圆的半径不超过10km,误差就能控制在0.5%以内,可通过下面代码直接计算观察到:
//经度之间的距离,不同纬度下的误差计算
d1=new AMap.LngLat(111,15.0).distance(new AMap.LngLat(111.2,15.0));
d2=new AMap.LngLat(111,15.2).distance(new AMap.LngLat(111.2,15.2));
console.log(d2, (d1-d2)/d2*100+"%") //低纬度下经度0.2°距离≈20km,纬度0.2°导致0.09%误差
d1=new AMap.LngLat(111,55.0).distance(new AMap.LngLat(111.2,55.0));
d2=new AMap.LngLat(111,55.2).distance(new AMap.LngLat(111.2,55.2));
console.log(d2, (d1-d2)/d2*100+"%") //高纬度下经度0.2°距离≈10km,纬度0.2°导致0.50%误差
d1=new AMap.LngLat(111,15).distance(new AMap.LngLat(112,15));
d2=new AMap.LngLat(111,16).distance(new AMap.LngLat(112,16));
console.log(d2, (d1-d2)/d2*100+"%") //低纬度下经度1°距离≈100km,纬度1°导致0.49%误差
d1=new AMap.LngLat(111,55).distance(new AMap.LngLat(112,55));
d2=new AMap.LngLat(111,56).distance(new AMap.LngLat(112,56));
console.log(d2, (d1-d2)/d2*100+"%") //高纬度下经度1°距离≈60km,纬度1°导致2.57%误差
由于是通过圆上的坐标点连起来得到的一个圆,本质上是一个近似圆的多边形,只要坐标点足够多就越接近圆,当坐标点少的情况下肉眼可见的不是那么圆(最少3个坐标点,三角形),误差也会很大。但考虑到点数越多,会导致使用上很多地方的计算量会变的很大,所以构成圆的坐标点数也是一个综合考虑的数量,我选择24个坐标点构成一个圆,每个象限6个点,点之间角度为15°。
【完】