• 【Arcpy学习实践教程】wgs84坐标系和火星坐标系的转换中demo的对与错


    【Arcpy学习实践教程】wgs84坐标系和火星坐标系的转换中demo的对与错

    来自:https://mp.weixin.qq.com/s/7uCaIwwP0tp3LHqdgToM2A?client=tim&ADUIN=276529800&ADSESSION=1582074176&ADTAG=CLIENT.QQ.5603_.0&ADPUBNO=26933

    小源 元凿坊工作室 3天前

    度娘和谷哥已经变成了我们学习工作生活中必不可少的工具。

    更有甚者,甚至已经不用输入法来搜索,而直接通过语音识别来搜索。但是我们搜索的结果真的可靠?我们在找到我们想要的资源之后是否有认真检验一下,我们找到的代码,找到的资料是否正确。当没有思考力和鉴别力的搬运工进入大众视野时,我们就需要谨慎起来了。

    最近,因为工作的原因需要对高德坐标(即火星坐标)和wgs84坐标系实现互转。一直记得有位大神曾经在网上发布过相关的代码,和大家一样,第一步做的也是搜索,信息铺天盖地,随便找几个阅读量大的原创文章,给大家展示一下代码吧。

    1.在《博客园》找到了一篇文章《GCJ-02火星坐标系和WGS-84坐标系转换关系》(ps:一般喜欢在博客园里面找代码,因为这边的文章相对专业一些,附上链接,下面是上面贴的code,python哈)

    # -*- coding: utf-8 -*-import jsonimport mathx_pi = 3.14159265358979324 * 3000.0 / 180.0pi = 3.1415926535897932384626  # πa = 6378245.0  # 长半轴ee = 0.00669342162296594323  # 扁率def wgs84togcj02(lng, lat):
        """    WGS84转GCJ02(火星坐标系)    :param lng:WGS84坐标系的经度    :param lat:WGS84坐标系的纬度    :return:    """
        if out_of_china(lng, lat):  # 判断是否在国内
            return lng, lat
        dlat = transformlat(lng - 105.0, lat - 35.0)
        dlng = transformlng(lng - 105.0, lat - 35.0)
        radlat = lat / 180.0 * pi
        magic = math.sin(radlat)
        magic = 1 - ee * magic * magic
        sqrtmagic = math.sqrt(magic)
        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
        dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
        mglat = lat + dlat
        mglng = lng + dlng
        return [mglng, mglat]def gcj02towgs84(lng, lat):
        """    GCJ02(火星坐标系)转GPS84    :param lng:火星坐标系的经度    :param lat:火星坐标系纬度    :return:    """
        if out_of_china(lng, lat):
            return lng, lat
        dlat = transformlat(lng - 105.0, lat - 35.0)
        dlng = transformlng(lng - 105.0, lat - 35.0)
        radlat = lat / 180.0 * pi
        magic = math.sin(radlat)
        magic = 1 - ee * magic * magic
        sqrtmagic = math.sqrt(magic)
        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
        dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
        mglat = lat + dlat
        mglng = lng + dlng
        return [lng * 2 - mglng, lat * 2 - mglat]def transformlat(lng, lat):
        ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat +         0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
        ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
                math.sin(2.0 * lng * pi)) * 2.0 / 3.0
        ret += (20.0 * math.sin(lat * pi) + 40.0 *
                math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
        ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
                math.sin(lat * pi / 30.0)) * 2.0 / 3.0
        return retdef transformlng(lng, lat):
        ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng +         0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
        ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
                math.sin(2.0 * lng * pi)) * 2.0 / 3.0
        ret += (20.0 * math.sin(lng * pi) + 40.0 *
                math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
        ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
                math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
        return retdef out_of_china(lng, lat):
        """    判断是否在国内,不在国内不做偏移    :param lng:    :param lat:    :return:    """
        if lng < 72.004 or lng > 137.8347:
            return True
        if lat < 0.8293 or lat > 55.8271:
            return True
        return Falseif __name__ == '__main__':
        [lng,lat]=[114.061202,22.529388]
        [dstlng, dstlat] = gcj02towgs84(lng, lat)
        print(dstlng, dstlat)

    2.在csdn中找到一篇2017年的文章,阅读量大概过万了吧,反正应该还是比较权威的吧,或者是说比较早的---《火星坐标、百度坐标、WGS84坐标转换代码(JS、python版)》,链接不可少,哈哈。代码也是不能少的,这个是必须的!!

    # -*- coding: utf-8 -*-
    import json
    import requests
    import math

    key = 'your key here' # 这里填写你的百度开放平台的key
    x_pi = 3.14159265358979324 * 3000.0 / 180.0
    pi = 3.1415926535897932384626 # π
    a = 6378245.0 # 长半轴
    ee = 0.00669342162296594323 # 扁率


    def geocode(address):
    """
    利用百度geocoding服务解析地址获取位置坐标
    :param address:需要解析的地址
    :return:
    """
    geocoding = {'s': 'rsv3',
    'key': key,
    'city': '全国',
    'address': address}
    res = requests.get(
    "http://restapi.amap.com/v3/geocode/geo", params=geocoding)
    if res.status_code == 200:
    json = res.json()
    status = json.get('status')
    count = json.get('count')
    if status == '1' and int(count) >= 1:
    geocodes = json.get('geocodes')[0]
    lng = float(geocodes.get('location').split(',')[0])
    lat = float(geocodes.get('location').split(',')[1])
    return [lng, lat]
    else:
    return None
    else:
    return None


    def gcj02tobd09(lng, lat):
    """
    火星坐标系(GCJ-02)转百度坐标系(BD-09)
    谷歌、高德——>百度
    :param lng:火星坐标经度
    :param lat:火星坐标纬度
    :return:
    """
    z = math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * x_pi)
    theta = math.atan2(lat, lng) + 0.000003 * math.cos(lng * x_pi)
    bd_lng = z * math.cos(theta) + 0.0065
    bd_lat = z * math.sin(theta) + 0.006
    return [bd_lng, bd_lat]


    def bd09togcj02(bd_lon, bd_lat):
    """
    百度坐标系(BD-09)转火星坐标系(GCJ-02)
    百度——>谷歌、高德
    :param bd_lat:百度坐标纬度
    :param bd_lon:百度坐标经度
    :return:转换后的坐标列表形式
    """
    x = bd_lon - 0.0065
    y = bd_lat - 0.006
    z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
    theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
    gg_lng = z * math.cos(theta)
    gg_lat = z * math.sin(theta)
    return [gg_lng, gg_lat]


    def wgs84togcj02(lng, lat):
    """
    WGS84转GCJ02(火星坐标系)
    :param lng:WGS84坐标系的经度
    :param lat:WGS84坐标系的纬度
    :return:
    """
    if out_of_china(lng, lat): # 判断是否在国内
    return lng, lat
    dlat = transformlat(lng - 105.0, lat - 35.0)
    dlng = transformlng(lng - 105.0, lat - 35.0)
    radlat = lat / 180.0 * pi
    magic = math.sin(radlat)
    magic = 1 - ee * magic * magic
    sqrtmagic = math.sqrt(magic)
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
    dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
    mglat = lat + dlat
    mglng = lng + dlng
    return [mglng, mglat]


    def gcj02towgs84(lng, lat):
    """
    GCJ02(火星坐标系)转GPS84
    :param lng:火星坐标系的经度
    :param lat:火星坐标系纬度
    :return:
    """
    if out_of_china(lng, lat):
    return lng, lat
    dlat = transformlat(lng - 105.0, lat - 35.0)
    dlng = transformlng(lng - 105.0, lat - 35.0)
    radlat = lat / 180.0 * pi
    magic = math.sin(radlat)
    magic = 1 - ee * magic * magic
    sqrtmagic = math.sqrt(magic)
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
    dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
    mglat = lat + dlat
    mglng = lng + dlng
    return [lng * 2 - mglng, lat * 2 - mglat]


    def transformlat(lng, lat):
    ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat +
    0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
    math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lat * pi) + 40.0 *
    math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
    ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
    math.sin(lat * pi / 30.0)) * 2.0 / 3.0
    return ret


    def transformlng(lng, lat):
    ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng +
    0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
    math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lng * pi) + 40.0 *
    math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
    ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
    math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
    return ret


    def out_of_china(lng, lat):
    """
    判断是否在国内,不在国内不做偏移
    :param lng:
    :param lat:
    :return:
    """
    if lng < 72.004 or lng > 137.8347:
    return True
    if lat < 0.8293 or lat > 55.8271:
    return True
    return False


    if __name__ == '__main__':
    lng = 128.543
    lat = 37.065
    result1 = gcj02tobd09(lng, lat)
    result2 = bd09togcj02(lng, lat)
    result3 = wgs84togcj02(lng, lat)
    result4 = gcj02towgs84(lng, lat)
    result5 = geocode('北京市朝阳区朝阳公园')
    print result1, result2, result3, result4, result5

    对比了一下,虽然写法有些许不一样,但是算法核心都是一样的。看到这么多的代码都是一样的,我当然也一样照做了。和第一个方法一样,我也做了定位,在高德地图上面发现了一个小问题,其实转出来的结果和实际有非常小的偏差。根据转出的结果,又用代码转回到wgs84,做投影,神奇的事情发生了,相差2m多。

    (转回去之后的wgs84投影差别2m)

    这个时候意识到一个问题,一定是这个算法存在问题。网上继续检索查找,大神浮出水面,geohey大神。用了qgis上他开发的转化工具之后,逆转换没有任何问题,这个时候正常的人也只会做一个事了,趴代码。代码趴到手,这里我也做一下搬运工吧。

    # -*- coding: utf-8 -*-
    ##########################################################################################
    """
    /***************************************************************************
    OffsetWGS84Core
    A QGIS plugin
    Class with methods for geometry and attributes processing
    -------------------
    begin : 2016-10-11
    git sha : $Format:%H$
    copyright : (C) 2017 by sshuair
    email : sshuair@gmail.com
    ***************************************************************************/

    /***************************************************************************
    * *
    * This program is free software; you can redistribute it and/or modify *
    * it under the terms of the GNU General Public License as published by *
    * the Free Software Foundation; either version 2 of the License, or *
    * (at your option) any later version. *
    * *
    ***************************************************************************/
    """
    from __future__ import print_function
    ##########################################################################################
    from builtins import zip
    import math
    from math import sin, cos, sqrt, fabs, atan2
    from math import pi as PI
    # from numba import jit


    # =================================================sshuair=============================================================
    # define ellipsoid
    a = 6378245.0
    f = 1 / 298.3
    b = a * (1 - f)
    ee = 1 - (b * b) / (a * a)

    # check if the point in china
    def outOfChina(lng, lat):
    return not (72.004 <= lng <= 137.8347 and 0.8293 <= lat <= 55.8271)

    # @jit
    def geohey_transformLat(x, y):
    ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x))
    ret = ret + (20.0 * sin(6.0 * x * PI) + 20.0 * sin(2.0 * x * PI)) * 2.0 / 3.0
    ret = ret + (20.0 * sin(y * PI) + 40.0 * sin(y / 3.0 * PI)) * 2.0 / 3.0
    ret = ret + (160.0 * sin(y / 12.0 * PI) + 320.0 * sin(y * PI / 30.0)) * 2.0 / 3.0
    return ret

    # @jit
    def geohey_transformLon(x, y):
    ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x))
    ret = ret + (20.0 * sin(6.0 * x * PI) + 20.0 * sin(2.0 * x * PI)) * 2.0 / 3.0
    ret = ret + (20.0 * sin(x * PI) + 40.0 * sin(x / 3.0 * PI)) * 2.0 / 3.0
    ret = ret + (150.0 * sin(x / 12.0 * PI) + 300.0 * sin(x * PI / 30.0)) * 2.0 / 3.0
    return ret

    # @jit
    def wgs2gcj(wgsLon, wgsLat):
    if outOfChina(wgsLon, wgsLat):
    return wgsLon, wgsLat
    dLat = geohey_transformLat(wgsLon - 105.0, wgsLat - 35.0)
    dLon = geohey_transformLon(wgsLon - 105.0, wgsLat - 35.0)
    radLat = wgsLat / 180.0 * PI
    magic = math.sin(radLat)
    magic = 1 - ee * magic * magic
    sqrtMagic = sqrt(magic)
    dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI)
    dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * PI)
    gcjLat = wgsLat + dLat
    gcjLon = wgsLon + dLon
    return (gcjLon, gcjLat)


    def gcj2wgs(gcjLon, gcjLat):
    g0 = (gcjLon, gcjLat)
    w0 = g0
    g1 = wgs2gcj(w0[0], w0[1])
    # w1 = w0 - (g1 - g0)
    w1 = tuple([x[0]-(x[1]-x[2]) for x in zip(w0,g1,g0)])
    # delta = w1 - w0
    delta = tuple([x[0] - x[1] for x in zip(w1, w0)])
    while (abs(delta[0]) >= 1e-6 or abs(delta[1]) >= 1e-6):
    w0 = w1
    g1 = wgs2gcj(w0[0], w0[1])
    # w1 = w0 - (g1 - g0)
    w1 = tuple([x[0]-(x[1]-x[2]) for x in zip(w0,g1,g0)])
    # delta = w1 - w0
    delta = tuple([x[0] - x[1] for x in zip(w1, w0)])
    return w1


    def gcj2bd(gcjLon, gcjLat):
    z = sqrt(gcjLon * gcjLon + gcjLat * gcjLat) + 0.00002 * sin(gcjLat * PI * 3000.0 / 180.0)
    theta = atan2(gcjLat, gcjLon) + 0.000003 * cos(gcjLon * PI * 3000.0 / 180.0)
    bdLon = z * cos(theta) + 0.0065
    bdLat = z * sin(theta) + 0.006
    return (bdLon, bdLat)


    def bd2gcj(bdLon, bdLat):
    x = bdLon - 0.0065
    y = bdLat - 0.006
    z = sqrt(x * x + y * y) - 0.00002 * sin(y * PI * 3000.0 / 180.0)
    theta = atan2(y, x) - 0.000003 * cos(x * PI * 3000.0 / 180.0)
    gcjLon = z * cos(theta)
    gcjLat = z * sin(theta)
    return (gcjLon, gcjLat)


    def wgs2bd(wgsLon, wgsLat):
    gcj = wgs2gcj(wgsLon, wgsLat)
    return gcj2bd(gcj[0], gcj[1])


    def bd2wgs(bdLon, bdLat):
    gcj = bd2gcj(bdLon, bdLat)
    return gcj2wgs(gcj[0], gcj[1])


    if __name__ == '__main__':
    # wgs2gcj
    # coord = (112, 40)
    # trans = WGS2GCJ()
    print(wgs2gcj(112, 40))
    print(gcj2wgs(112.00678230985764, 40.00112245823686))

    # gcj2wgs

    很明显在火星坐标系转wgs84坐标系过程中的算法存在较大的差异,这是之前误差2m的绝对原因。

    希望以后大家在搬运代码的时候回过去验证一下,做一个有判断力和有辨识力的搬运工。我们虽然可以不重复生产轮子,但是我们不能够把别人的方轮子拿来用吧!!!!

    本文由元凿坊独创,如需转载,请获得作者的授权。如发现问题,请及时告知作者,

    欢迎前来探讨交流!!!!

  • 相关阅读:
    嵌入式Linux系统移植(二)——交叉编译工具集
    嵌入式linux系统移植(一)
    C语言常用关键语法精华总结
    ARM汇编常用指令
    嵌入式Linux系统移植——uboot常用命令
    VHDL的参数写在一个vhd文件里
    [PAT] 1077 Kuchiguse (20 分)Java
    [PAT] 1073 Scientific Notation (20 分)Java
    [PAT] 1069 The Black Hole of Numbers (20 分)Java
    [PAT] 1065 A+B and C (64bit) (20 分)Java
  • 原文地址:https://www.cnblogs.com/gisoracle/p/12329802.html
Copyright © 2020-2023  润新知