百度地图墨卡托坐标转高德经纬度坐标(偏移小)

基本上是网上常见的方法进行坐标系的转换,但是误差很大。发现之所以误差大是在于百度的墨卡托坐标转百度的经纬度时误差太大,后面找到一个方法,误差较小,基本吻合。

参考:http://www.site-digger.com/tools/mct2latlng.html

这里的转换是直接调用百度地图SDK中的API,通过对其中JavaScript源代码的执行跟踪,提取出其中的墨卡托坐标转百度经纬度坐标的代码如下:

Java版本:

@Data
public static class Point {
    private double lng, lat;

    public Point(double lng, double lat) {
        this.lng = lng;
        this.lat = lat;
    }

    @Override
    public String toString() {
        return lng + "," + lat;
    }
}

private static double xPi = 3.14159265358979324 * 3000.0 / 180.0;

// 以下参数来自百度地图的SDK
private static double[] MCBAND = {12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0};

private static double[][] MC2LL = {
        {1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, 200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 17337981.2},
        {-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, 96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 10260144.86},
        {-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, 59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37},
        {-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, 40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06},
        {3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, 23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4},
        {2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, 7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596, 0.00010322952773, -0.00000323890364, 826088.5}
};

/**
 * 参考:http://www.site-digger.com/tools/mct2latlng.html
 * 对上述链接中的操作,找到百度地图的SDK的源代码,然后转换成Java
 */
private static Point convertMC2LL(Point mp) {
    Point absPoint = new Point(abs(mp.getLng()), abs(mp.getLat()));
    double[] paramArr = null;
    for (int i = 0; i < MCBAND.length; i++) {
        if (absPoint.getLat() >= MCBAND[i]) {
            paramArr = MC2LL[i];
            break;
        }
    }

    if (mp == null || paramArr == null)
        throw new RuntimeException("转换出错");

    double lng = paramArr[0] + paramArr[1] * abs(mp.getLng());
    double tlat = abs(mp.getLat()) / paramArr[9];
    double lat = paramArr[2]
            + paramArr[3] * tlat
            + paramArr[4] * tlat * tlat
            + paramArr[5] * tlat * tlat * tlat
            + paramArr[6] * tlat * tlat * tlat * tlat
            + paramArr[7] * tlat * tlat * tlat * tlat * tlat
            + paramArr[8] * tlat * tlat * tlat * tlat * tlat * tlat;
    lng *= mp.getLng() < 0 ? -1 : 1;
    lat *= mp.getLat() < 0 ? -1 : 1;

    return new Point(lng, lat);
}

/**
* 百度经纬度坐标转高德经纬度坐标。网上很常见的一种方式。
*/
private static Point BD09ToGCJ02(Point bdp) {
    double x = bdp.getLng() - 0.0065, y = bdp.getLat() - 0.006;
    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * xPi);
    double theta = atan2(y, x) - 0.000003 * cos(x * xPi);
    return new Point(z * cos(theta), z * sin(theta));
}

Python版本:

xPi = 3.14159265358979324 * 3000.0 / 180.0

# 以下参数来自百度地图的SDK
MCBAND = [12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0]

MC2LL = [
    [1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, 200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 17337981.2],
    [-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, 96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 10260144.86],
    [-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, 59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37],
    [-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, 40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06],
    [3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, 23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4],
    [2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, 7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596, 0.00010322952773, -0.00000323890364, 826088.5]
]

# 百度经纬度坐标转高德经纬度坐标。网上很常见的一种方式。
def bd09togcj02(bd_lon, bd_lat):
    """
    百度坐标系(BD-09)转火星坐标系(GCJ-02)
    百度——>谷歌、高德
    :param bd_lat:百度坐标纬度
    :param bd_lon:百度坐标经度
    :return:转换后的坐标列表形式
    """
    x, y = bd_lon - 0.0065, bd_lat - 0.006
    z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * xPi)
    theta = math.atan2(y, x) - 0.000003 * math.cos(x * xPi)
    return z * math.cos(theta), z * math.sin(theta)

 # 参考:http://www.site-digger.com/tools/mct2latlng.html
 # 对上述链接中的操作,找到百度地图的SDK的源代码,然后转换成Java
def convertMC2LL(ox, oy) :
    x, y = abs(ox), abs(oy)
    for i in range(0, len(MCBAND)) :
        if y >= MCBAND[i] :
            paramArr = MC2LL[i]
            break

    if paramArr == None:
        raise Exception('转换坐标失败')

    lng = paramArr[0] + paramArr[1] * abs(ox)
    tlat = abs(oy) / paramArr[9]
    lat = paramArr[2] + paramArr[3] * tlat + paramArr[4] * tlat * tlat + paramArr[5] * tlat * tlat * tlat + paramArr[6] * tlat * tlat * tlat * tlat + paramArr[7] * tlat * tlat * tlat * tlat * tlat + paramArr[8] * tlat * tlat * tlat * tlat * tlat * tlat
    lng *= (-1 if ox < 0 else 1)
    lat *= (-1 if oy < 0 else 1)

    return lng, lat

效果展示:

// 测试代码
String kejiyuan = "12682891.3894,2559542.0538,12682896.5467,2559793.62794,12682844.7433,2560206.11494,12682734.4366,2561087.88431,12682681.159,2562074.67985,12682831.1964,2562218.1177,12683623.9092,2562188.56753,12683732.2141,2562243.30281,12683877.4858,2562398.46172,12683916.3509,2562839.59511,12683912.6528,2563051.56215,12683997.6458,2563129.82525,12684148.9608,2563136.64739,12684423.9572,2563249.60486,12684687.41,2563412.50587,12685216.0839,2563387.9877,12686427.857,2563282.11338,12687017.2378,2563194.53233,12687547.0621,2563146.47597,12687711.6126,2563191.93924,12688072.3621,2563098.80984,12688551.9725,2562924.51818,12688595.2954,2562866.34103,12688581.4473,2562769.94654,12688592.8397,2562733.23579,12689180.0331,2562464.27042,12689211.9588,2562420.55064,12689195.8798,2562314.3281,12689168.3537,2562313.76442,12688839.1722,2562275.22138,12688521.5892,2562344.85031,12688215.549,2562370.2208,12687875.1633,2562296.16518,12687304.0261,2562224.77222,12686776.2826,2562209.27294,12686464.1449,2562201.14685,12686253.3935,2562183.17902,12686147.8737,2562159.13696,12686097.5228,2562114.03074,12686174.2562,2560903.22104,12686144.5094,2560727.85702,12686162.7094,2560701.00483,12686702.0782,2560744.58401,12686715.7214,2560727.54607,12686694.5355,2560518.79091,12686469.0556,2560122.34138,12686281.1211,2559770.33875,12686231.908,2559542.23454,12686214.5986,2559162.03758,12686197.169,2559118.19258,12685318.8834,2559094.19446,12685143.0646,2559094.6559,12684986.7893,2559013.13744,12684889.126,2558895.30627,12684835.3891,2558858.28003,12684600.8812,2558847.14735,12684139.8292,2558854.49449,12683748.6599,2558894.79101,12683582.3085,2558936.30384,12683435.5368,2559030.43944,12683260.9697,2559068.85924,12682852.8989,2559166.22101,12682834.3698,2559181.22174,12682891.3894,2559542.0538";
String pss = kejiyuan;
String[] points = pss.split(",");
if (points.length % 2 == 0) {
    for (int i = 0; i < points.length; i += 2) {
        System.out.println(
                "[" +
                    BD09ToGCJ02(convertMC2LL(
                        new Point(
                                Double.parseDouble(points[i]),
                                Double.parseDouble(points[i + 1])
                        )
                    ))
                    + "],"
        );
    }
}

打开高德地图多边形绘制DEMO示例,然后将上述代码的对应执行结果,以正确的形式粘贴到DEMO代码的相应地方:

然后点击运行,查看结果:
百度墨卡托坐标转成百度经纬度坐标后,在高德地图上展示情况

将百度坐标转换成高德地图坐标后在高德地图中的展示情况

百度地图原始数据

后面经过尝试、发现差距并不是特别大,已使用这种方法进行坐标转换

原文地址:https://www.cnblogs.com/asahii/p/11152671.html

时间: 2024-08-28 03:09:41

百度地图墨卡托坐标转高德经纬度坐标(偏移小)的相关文章

利用百度地图API根据地址查询经纬度

传上来只是为了记录下三种jsonp方式,$.get(url, callback)方式不行,会出错 -- 必须指明返回类型为"json"才行. 必须使用$.getJSON()或者$.ajax({}). <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compati

百度地图API 根据地址查询经纬度

html页面.引用上API: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>根据地址查询经纬度</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascrip

百度地图JavaScript API覆盖物旋转时出现偏移

在项目中,调用百度地图JavaScript API,做覆盖物的旋转再添加到地图上,结果出现偏移了. 调试过程中的效果图: 发现图片的旋转并不是按车子的中心来的,而是之外的一个点.最后发现犯了一个很细节的错: <script type="text/javascript"> // 百度地图API功能 var map = new BMap.Map("allmap"); var point = new BMap.Point(121.38750613, 31.17

Python通过百度地图API获取地址的经纬度

API 地址:http://developer.baidu.com/map/index.php?title=webapi/guide/webservice-geocoding 一个简单的API,可以通过地址(地名)获得经纬度,或者通过经纬度获取周边的位置信息. ak是百度开发者APIKEY,注册地址:http://developer.baidu.com/ #!/usr/bin/env python3 import requests import json def locatebyAddr(add

Python利用百度地图api批量获取地址经纬度

1.pip安装xlrd,xlwt,requests模块. 2.在工程目录处放置地点Excel文件. python代码: #coding:utf-8 import xlrd import xlwt import requests import urllib import math import re pattern_x = re.compile(r'"x":(".+?")') pattern_y = re.compile(r'"y":("

java调用百度地图API根据地理位置获取经纬度

public Map<String, BigDecimal> getLatAndLngByAddress(String addr){ String address = ""; String lat = ""; String lng = ""; try { address = java.net.URLEncoder.encode(addr,"UTF-8"); } catch (UnsupportedEncodingE

arcgis api for javascipt 加载天地图、百度地图

写在前面的话: 1.百度地图是自己定义的坐标系统,wkid=102100.百度地图数据是加密的产物.下文将附上百度坐标与WGS84,谷歌等坐标系统转换方法(地理-地理),此方法并未亲测,据说准 2.百度地图可以直接加载经纬度坐标 3.百度地图如果加载的arcgis api中会出现坐标偏移,1.中已经解决了地理坐标转换,那么找到百度投影-地理坐标的转换方式,则arcgis就可以直接无偏加载了,网上很多方法,但是亲测不行. 4.天地图不是涉密数据,根据本文提供的类库,arcgis api for j

微信小程序--百度地图坐标转换成腾讯地图坐标

最近开发小程序时出现一个问题,后台程序坐标采用的时百度地图的坐标,因为小程序地图时采用的腾讯地图的坐标系,两种坐标有一定的误差,导致位置信息显示不正确.现在需要一个可以转换两种坐标的方法,经过查询发现腾讯地图提供了一个接口用来将多种坐标类型转换成腾讯可用的坐标. 方法如下: reverseGeocoder(options:Object) 本接口提供由坐标到坐标所在位置的文字描述的转换,输入坐标返回地理位置信息和附近poi列表. options参数属性说明: 如图上所示,只需要传递坐标时加上参数c

openlayers3应用“三’”:百度地图坐标纠偏

前两篇文章介绍了openlayers3加载百度在线和离线瓦片地图,页面上能够正常显示.地图加载后在地图上显示一条GPS轨迹,发现离实际位置相差太远,如下图所示: 轨迹形状和实际形状相同,但是位移太远,采用坐标加偏移的方法(在原有经纬度坐标基础上进行数值增减),得到和实际轨迹完全重新的新的轨迹,如下图所示: 在地图上添加另外一条车辆轨迹,发现使用相同的坐标偏移量后,第二条轨迹又存在偏差,第二条轨迹未做偏移前如图所示: 经过坐标偏移后如下图: 可以看到地图上两条轨迹,使用相同的坐标偏移量,不能进行"