本文主要是介绍【Arcpy学习实践教程】wgs84坐标系和火星坐标系的转换中demo的对与错,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
度娘和谷哥已经变成了我们学习工作生活中必不可少的工具。
更有甚者,甚至已经不用输入法来搜索,而直接通过语音识别来搜索。但是我们搜索的结果真的可靠?我们在找到我们想要的资源之后是否有认真检验一下,我们找到的代码,找到的资料是否正确。当没有思考力和鉴别力的搬运工进入大众视野时,我们就需要谨慎起来了。
最近,因为工作的原因需要对高德坐标(即火星坐标)和wgs84坐标系实现互转。一直记得有位大神曾经在网上发布过相关的代码,和大家一样,第一步做的也是搜索,信息铺天盖地,随便找几个阅读量大的原创文章,给大家展示一下代码吧。
1.在《博客园》找到了一篇文章《GCJ-02火星坐标系和WGS-84坐标系转换关系》(ps:一般喜欢在博客园里面找代码,因为这边的文章相对专业一些,附上链接,下面是上面贴的code,python哈)
# -*- coding: utf-8 -*-
import json
import mathx_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, latdlat = transformlat(lng - 105.0, lat - 35.0)dlng = transformlng(lng - 105.0, lat - 35.0)radlat = lat / 180.0 * pimagic = math.sin(radlat)magic = 1 - ee * magic * magicsqrtmagic = 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 + dlatmglng = lng + dlngreturn [mglng, mglat]def gcj02towgs84(lng, lat):"""GCJ02(火星坐标系)转GPS84:param lng:火星坐标系的经度:param lat:火星坐标系纬度:return:"""if out_of_china(lng, lat):return lng, latdlat = transformlat(lng - 105.0, lat - 35.0)dlng = transformlng(lng - 105.0, lat - 35.0)radlat = lat / 180.0 * pimagic = math.sin(radlat)magic = 1 - ee * magic * magicsqrtmagic = 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 + dlatmglng = lng + dlngreturn [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.0ret += (20.0 * math.sin(lat * pi) + 40.0 *math.sin(lat / 3.0 * pi)) * 2.0 / 3.0ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *math.sin(lat * pi / 30.0)) * 2.0 / 3.0return 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.0ret += (20.0 * math.sin(lng * pi) + 40.0 *math.sin(lng / 3.0 * pi)) * 2.0 / 3.0ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *math.sin(lng / 30.0 * pi)) * 2.0 / 3.0return retdef out_of_china(lng, lat):"""判断是否在国内,不在国内不做偏移:param lng::param lat::return:"""if lng < 72.004 or lng > 137.8347:return Trueif lat < 0.8293 or lat > 55.8271:return Truereturn 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 mathkey = '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 Noneelse:return Nonedef 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.0065bd_lat = z * math.sin(theta) + 0.006return [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.0065y = bd_lat - 0.006z = 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, latdlat = transformlat(lng - 105.0, lat - 35.0)dlng = transformlng(lng - 105.0, lat - 35.0)radlat = lat / 180.0 * pimagic = math.sin(radlat)magic = 1 - ee * magic * magicsqrtmagic = 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 + dlatmglng = lng + dlngreturn [mglng, mglat]def gcj02towgs84(lng, lat):"""GCJ02(火星坐标系)转GPS84:param lng:火星坐标系的经度:param lat:火星坐标系纬度:return:"""if out_of_china(lng, lat):return lng, latdlat = transformlat(lng - 105.0, lat - 35.0)dlng = transformlng(lng - 105.0, lat - 35.0)radlat = lat / 180.0 * pimagic = math.sin(radlat)magic = 1 - ee * magic * magicsqrtmagic = 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 + dlatmglng = lng + dlngreturn [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.0ret += (20.0 * math.sin(lat * pi) + 40.0 *math.sin(lat / 3.0 * pi)) * 2.0 / 3.0ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *math.sin(lat * pi / 30.0)) * 2.0 / 3.0return 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.0ret += (20.0 * math.sin(lng * pi) + 40.0 *math.sin(lng / 3.0 * pi)) * 2.0 / 3.0ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *math.sin(lng / 30.0 * pi)) * 2.0 / 3.0return retdef out_of_china(lng, lat):"""判断是否在国内,不在国内不做偏移:param lng::param lat::return:"""if lng < 72.004 or lng > 137.8347:return Trueif lat < 0.8293 or lat > 55.8271:return Truereturn Falseif __name__ == '__main__':lng = 128.543lat = 37.065result1 = 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多。
这个时候意识到一个问题,一定是这个算法存在问题。网上继续检索查找,大神浮出水面,geohey大神。用了qgis上他开发的转化工具之后,逆转换没有任何问题,这个时候正常的人也只会做一个事了,趴代码。代码趴到手,这里我也做一下搬运工吧。
# -*- coding: utf-8 -*-
##########################################################################################
"""
/***************************************************************************OffsetWGS84CoreA QGIS pluginClass with methods for geometry and attributes processing-------------------begin : 2016-10-11git sha : $Format:%H$copyright : (C) 2017 by sshuairemail : 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.0ret = ret + (20.0 * sin(y * PI) + 40.0 * sin(y / 3.0 * PI)) * 2.0 / 3.0ret = ret + (160.0 * sin(y / 12.0 * PI) + 320.0 * sin(y * PI / 30.0)) * 2.0 / 3.0return 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.0ret = ret + (20.0 * sin(x * PI) + 40.0 * sin(x / 3.0 * PI)) * 2.0 / 3.0ret = ret + (150.0 * sin(x / 12.0 * PI) + 300.0 * sin(x * PI / 30.0)) * 2.0 / 3.0return ret# @jit
def wgs2gcj(wgsLon, wgsLat):if outOfChina(wgsLon, wgsLat):return wgsLon, wgsLatdLat = geohey_transformLat(wgsLon - 105.0, wgsLat - 35.0)dLon = geohey_transformLon(wgsLon - 105.0, wgsLat - 35.0)radLat = wgsLat / 180.0 * PImagic = math.sin(radLat)magic = 1 - ee * magic * magicsqrtMagic = sqrt(magic)dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI)dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * PI)gcjLat = wgsLat + dLatgcjLon = wgsLon + dLonreturn (gcjLon, gcjLat)def gcj2wgs(gcjLon, gcjLat):g0 = (gcjLon, gcjLat)w0 = g0g1 = 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 - w0delta = tuple([x[0] - x[1] for x in zip(w1, w0)])while (abs(delta[0]) >= 1e-6 or abs(delta[1]) >= 1e-6):w0 = w1g1 = 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 - w0delta = tuple([x[0] - x[1] for x in zip(w1, w0)])return w1def 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.0065bdLat = z * sin(theta) + 0.006return (bdLon, bdLat)def bd2gcj(bdLon, bdLat):x = bdLon - 0.0065y = bdLat - 0.006z = 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
这篇关于【Arcpy学习实践教程】wgs84坐标系和火星坐标系的转换中demo的对与错的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!