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

Freda ·
更新时间:2024-09-21
· 500 次阅读

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

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

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

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

# -*- coding: utf-8 -*- import json import math x_pi = 3.14159265358979324 * 3000.0 / 180.0 pi = 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 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 137.8347: return True if lat 55.8271: return True return False if __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 137.8347: return True if 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 = 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的绝对原因。

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

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

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

发布于 17:28


作者:桃花浪子立



wgs84 demo 教程

需要 登录 后方可回复, 如果你还没有账号请 注册新账号