百度坐标系下经纬度距离的计算

标签: 程序开发 GIS | 发表时间:2017-08-14 17:26 | 作者:标点符
出处:https://www.biaodianfu.com

最近的一个项目中有用到经纬度距离的计算,数据库中存储的是百度的经纬度。由于先前学习过一些 地图经纬度坐标系的知识,所以心中产生了困惑:使用随机偏移过的经纬度地址计算出来的距离是否是正确的?重新梳理了一些基本知识:

地球坐标 (WGS84)

  • 国际标准,从 GPS 设备中取出的数据的坐标系
  • 国际地图提供商使用的坐标系

火星坐标 (GCJ-02)也叫国测局坐标系

  • 中国标准,从国行移动设备中定位获取的坐标数据使用这个坐标系
  • 国家规定: 国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密。

百度坐标 (BD-09)

  • 百度标准,百度 SDK,百度地图,Geocoding 使用(本来就乱了,百度又在火星坐标上来个二次加密)

从设备获取经纬度(GPS)坐标

  • 如果使用的是百度sdk那么可以获得百度坐标(bd09)或者火星坐标(GCJ02),默认是bd09
  • 如果使用的是ios的原生定位库,那么获得的坐标是WGS84
  • 如果使用的是高德sdk,那么获取的坐标是GCJ02

更多参考信息:

最准确的距离计算应当采用WGS84的坐标,采用火星坐标系和百度坐标从原理上就可能存在偏差。但是是否可以对经纬度直接进行计算呢,考虑到百度地图有测量距离的功能,于是拔了他的代码用来研究:

代码来源: http://api.map.baidu.com/getscript?v=2.0

var j = void 0,
        p = null,
H.prototype.nb = function(a) {
        return a && this.lat == a.lat && this.lng == a.lng
};

getDistance: function(a, b) {
            if (a && b) {
                if (a.nb(b)) return 0;
                var c = 0,
                    c = R.To(a, b);
                if (c === p || c === j) c = 0;
                return c
            }
        },

nb: function(a) {
            return !(a instanceof eb) || this.xj() ? q : this.se().nb(a.se()) && this.of().nb(a.of())
        },

function R() {}
    R.prototype = new gc;
    x.extend(R, {
        To: function(a, b) {
            if (!a || !b) return 0;
            a.lng = this.ND(a.lng, -180, 180);
            a.lat = this.RD(a.lat, -74, 74);
            b.lng = this.ND(b.lng, -180, 180);
            b.lat = this.RD(b.lat, -74, 74);
            return this.Re(this.Sk(a.lng), this.Sk(b.lng), this.Sk(a.lat), this.Sk(b.lat))
        },
Re: function(a, b, c, d) {
            return this.jP * Math.acos(Math.sin(c) * Math.sin(d) + Math.cos(c) * Math.cos(d) * Math.cos(b - a))
        },
		jP: 6370996.81,

		RD: function(a, b, c) {
            b != p && (a = Math.max(a, b));
            c != p && (a = Math.min(a, c));
            return a
        },
        ND: function(a, b, c) {
            for (; a > c;) a -= c - b;
            for (; a < b;) a += c - b;
            return a
        }
		Sk: function(a) {
            return Math.PI * a / 180
        },        
});

使用Python对上述代码进行了重写:

def get_distance_bd09(point_a, point_b):
    """
    算法来源:http://developer.baidu.com/map/jsdemo.htm#a6_1
    :param pointA: {lat:29.490295, lng:106.486654}
    :param pointB: {lat:29.615467, lng:106.581515}
    :return:米
    """
    Radius = 6370996.81 #球半径

    if (point_a and point_b):
        if point_a["lat"] == point_b["lat"] and point_a["lng"] == point_b["lng"]:
            distance = 0
        else:
            a_lat = point_a["lat"] * math.pi / 180
            a_lng = point_a["lng"] * math.pi / 180
            b_lat = point_b["lat"] * math.pi / 180
            b_lng = point_b["lng"] * math.pi / 180
            # print(a_lng,b_lng,a_lat,b_lat)
            distance = Radius * math.acos(math.sin(a_lat) * math.sin(b_lat) + math.cos(a_lat) * math.cos(b_lat) * math.cos(b_lng - a_lng))
        print(distance)

发现此计算方法与wgs84的算法完全一致。

def get_distance_wgs84(point_a, point_b):
    """
    算法来源:https://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula
    :param pointA: {lat:29.490295, lng:106.486654}
    :param pointB: {lat:29.615467, lng:106.581515}
    :return:米
    """
    Radius = 6370996.81 #球半径

    d_lat = math.radians(point_b["lat"] - point_a["lat"])
    d_lng = math.radians(point_b["lng"] - point_a["lng"])

    a = math.sin(d_lat/2) * math.sin(d_lat/2) + \
        math.cos(math.radians(point_a["lat"])) * math.cos(math.radians(point_b["lat"])) * \
        math.sin(d_lng/2) * math.sin(d_lng/2)
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
    d = Radius * c
    return d

也就是说百度忽略了经纬度的偏移,可能原因是经纬度距离越是距离的近,算出的距离偏差越小,越是距离远,算出的偏差才会远。

补充知识

地理空间距离计算方法较多,可以分为两类:

  • 球面模型,这种模型将地球看成一个标准球体,球面上两点之间的最短距离即大圆弧长,这种方法使用较广
  • 椭球模型,该模型最贴近真实地球,精度也最高,但计算较为复杂

基于球面模型的地理空间距离计算公式,将地球看成圆球,假设地球上有A(ja,wa),B(jb,wb)两点(注:ja和jb分别是A和B的经度,wa和wb分别是A和B的纬度),A和B两点的球面距离就是AB的弧长,AB弧长=R*角AOB(注:角AOB是A跟B的夹角,O是地球的球心,R是地球半径,约为6367000米)。如何求出角AOB呢?可以先求AOB的最大边AB的长度,再根据余弦定律可以求夹角。

如果业务场景仅仅是在一个城市范围内进行距离计算,也就是说两个点之间的距离一般不会超过200多千米。由于范围小,可以认为经线和纬线是垂直的,如图所示,要求A(116.8,39,78)和B(116.9,39.68)两点的距离,我们可以先求出南北方向距离AM,然后求出东西方向距离BM,最后求矩形对角线距离,即sqrt(AMAM + BMBM)。

public static double distanceSimplify(double lat1, double lng1, double lat2, double lng2, double[] a) {
     double dx = lng1 - lng2; // 经度差值
     double dy = lat1 - lat2; // 纬度差值
     double b = (lat1 + lat2) / 2.0; // 平均纬度
     double Lx = toRadians(dx) * 6367000.0* Math.cos(toRadians(b)); // 东西距离
     double Ly = 6367000.0 * toRadians(dy); // 南北距离
     return Math.sqrt(Lx * Lx + Ly * Ly);  // 用平面的矩形对角距离公式计算总距离
    }
}

参考内容:

相关 [百度 坐标系 经纬度] 推荐:

百度坐标系下经纬度距离的计算

- - 标点符
最近的一个项目中有用到经纬度距离的计算,数据库中存储的是百度的经纬度. 由于先前学习过一些 地图经纬度坐标系的知识,所以心中产生了困惑:使用随机偏移过的经纬度地址计算出来的距离是否是正确的. 国际标准,从 GPS 设备中取出的数据的坐标系. 国际地图提供商使用的坐标系. 火星坐标 (GCJ-02)也叫国测局坐标系.

地图经纬度及坐标系统转换的那点事

- - 标点符
美国GPS使用的是WGS84的坐标系统,以经纬度的形式来表示地球平面上的某一个位置. 但在我国,出于国家安全考虑,国内所有导航电子地图必须使用国家测绘局制定的加密坐标系统,即将一个真实的经纬度坐标加密成一个不正确的经纬度坐标,在业内将前者称之为地球坐标,后者称之为火星坐标. 《条例》要求地图不得“危害国家统一、主权和领土完整;危害国家安全、损害国家荣誉和利益;国家秘密;影响民族团结、侵害民族风俗习惯”,规定互联网地图服务必须经过审批,要求“从事互联网地图服务的,应当将存放地图数据的服务器设在中华人民共和国境内,建立互联网地图数据安全管理制度和保障措施,并具有经测绘行政主管部门考核合格的互联网地图安全审校人员.

【百度地图API】如何批量转换为百度经纬度

- Pei - 博客园-首页原创精华区
     百度地图API的官网上提供了常用坐标转换的示例. 但是,一次只能转换一个,真的非常麻烦. 这里结合了官方的示例,自制一个批量转换工具,供大家参考. 因为我没有GPS坐标,就拿谷歌坐标做个示例了. 首先要注意的是,百度和谷歌的经纬度坐标顺序是相反的. 传入坐标转换接口的百度经纬度应该是. 所以,我建立一个数组,存放转换前的经纬度.

Google未公开API:转MAC地址为经纬度

- Hermes - 酷壳 - CoolShell.cn
这里有一个POC(Proof of Concept)可以通过你Web浏览器后面的路由器XSS攻击得到一个准确的GPS坐标. 注意:路由器和Web浏览器以及IP地址并不包含任和地理信息. 其方法是使用了一个Google未公开的API. 访问一个网页,这个网页隐藏了一个基于你WiFi路由器的XSS( 参见: XSS  Verizon FiOS router).

Android中通过当前经纬度获得城市

- - CSDN博客移动开发推荐文章
  * 借助Google MAP 通过用户当前经纬度 获得用户当前城市.  private String city="全国";.   //只是简单的获取城市 不需要实时更新 所以这里先注释. //      //当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发 . //      System.out.println(".onProviderDisabled(关闭)"+arg0);.

[转] Sphinx SetGeoAnchor 经纬度查找附近地点

- - 互联网 - ITeye博客
原文地址 http://www.douban.com/group/topic/30286342. Sphinx 的 SetGeoAnchor方法,(LinkWith:http://sphinxsearch.com/docs/manual-0.9.9.html#api-func-setgeoanchor).

ElasticSearch实现基于经纬度的附近搜索

- - 标点符
ElasticSearch除了支持文本检索外,还支持地理信息检索. 它主要支持两种类型的地理查询:一种是地理点(geo_point),即经纬度查询,另一种是地理形状查询(geo_shape),即支持点、线、圈、多边形查询等. ElasticSearch实现经纬度附近搜索. 1、创建映射(mapping).

百度急了

- - 创业家杂志社
来源: 21世纪经济报道 作者:汤浔芳. 2013年1月,百度CEO李彦宏在百度2012年表现中“公司系数”一栏的打分是0. 在不少员工看来,这是Robin(李彦宏的英文名)对百度在“移动互联网”上的表现不满意. 这个史无前例的差评让不少员工开始在网上吐槽年终奖会不会大幅缩水,因为公司系数占年终奖的30%.

该死的百度

- 菡萏 - Pure Pleasure - Reborn
之前,百度把收费的医药、医院广告链接掺杂在搜索结果里,被央视点名批评(其实谁都知道它们都心怀不轨),但百度是不怕的,受伤的是民众、草根,发不出声音——于是此事不了了之(后来的结果是李彦宏在央视打广告、上春晚). 再后来,百度封杀淘宝联盟的40万站长,很多小站被迫停止运营;站长们跑到百度办公楼前抗议,但百度是不怕的,因为这些站长还是发不出声音(网站都开不下去了,只能亲自示威)——于是此事再次不了了之⋯⋯可这次,百度惹到作者头上了,别管这些作者质量是否良莠不齐(韩寒、郭敬明、贾平凹、王三表等等一并出现在声讨百度的队伍中),但他们是天然的“自媒体”,百度开始以为没事儿,两三天下来才发现捅了马蜂窝⋯⋯.

百度献礼门

- Shawn - wsmlby的Plog
来源: 温广阳KinKer的日志. 如果你以为我单指在百度里面输入“建党”就会看见的红旗赞歌的话,你就大错特错了. 本来这种媚上的传统也算是几千年文化的一部分了,无需大惊小怪,发这样的状态,估计只会被认为是抓住一切机会讥讽社会主义伟大建设的行为,所以我看见梅姐也同瞎就很开心地继续复习了,但是师傅说他献了整整10束花才发现没有献花上限,令我心里陡然一动.