码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-07-08 17:56:06      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:href   ret   图片   pre   方法   ISE   bd09   谷歌   mat   

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

参考: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代码的相应地方:
技术图片
然后点击运行,查看结果:
百度墨卡托坐标转成百度经纬度坐标后,在高德地图上展示情况
技术图片
将百度坐标转换成高德地图坐标后在高德地图中的展示情况
技术图片
百度地图原始数据
技术图片

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

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

标签:href   ret   图片   pre   方法   ISE   bd09   谷歌   mat   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!