经纬度坐标互换

什么是 WGS-84GCJ-02

两个坐标都是以经度、纬度对来标识地球上任意一点的坐标系统。

WGS-84

WGS 全称 World Geodetic System,于1984年建立。

通过 GPS 获得的经纬坐标,以及 Google Maps 上记录各地形、街道、建筑所使用的经纬坐标,都是 WGS-84 坐标系中的坐标WGS-84 亦是最通用的地球坐标系。其起初就是因 GPS 的诞生而被设立。

GCJ-02

某毒百科声称:

GCJ-02是由中国国家测绘局制订的地理信息系统的坐标系统。
它是一种对经纬度数据的加密算法,即加入随机的偏差。
国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密。

Wikipedia 亦有描述:

中国官方要求所有在中国运行的地图服务商要加装“国家保密插件”(亦称加密插件、加偏或SM模组),以“保障国家安全”。此插件会将真实的坐标加密成虚假的坐标,且此加偏并非线性加偏,所以各地的偏移情况都会有所不同。

事实上,GCJ-02 意味“国测局-2002”,也就是说,这是国家测绘局于2002年弄出的标准。

事实上,百毒等在线地图为了配合政府,以及保护自己的商业利益,在GCJ-02的基础上都使用了进一步的其它坐标加密算法。当然,那些不属于此篇文章的讨论范围之内。

Case study: Google 地图

上面说过,很多国内地图提供商都龌龊进行了二次加密。但 Google 即使不得不配合中国政府,也只使用了一次加密,也就是 WGS-84 至 GCJ-02

事实上,Google 的地图服务有两个版本:
一为 Google Maps,可以通过 maps.google.com 访问
二为 Google Ditu,可以通过 ditu.google.cn 或 ditu.google.com 或 maps.google.cn 访问
显而易见,第二个版本是为了中国准备的。

可以注意到,在 Google Ditu 下,卫星图和公路图是重合的,没有任何问题;然而在 Google Maps 下,看中国内的区域,在同一个地方从公路图切换到卫星图时,可以发现发生了较大偏移。借助 Google 官方的经纬度标注工具,用下面这张图加以说明:

很容易看出,在 Google Ditu 上,公路图是在 GCJ-02 坐标系中的,为了让卫星图与之重合,Google 把卫星图也进行了同样的加偏。而在 Google Maps 中,虽然公路图依然是在 GCJ-02 坐标系中的(测绘阶段受中国政府限制),然而卫星图却是未经过加偏的。

通过取了很多点的两组不同坐标,进行偏移计算并与之前流传的算法进行比对,证明之前流传的算法是完全属实的

对于 GCJ-02 的评论

GCJ-02 与 WGS-84 间的转换实际上很容易做到,因为算法已经流传甚广。然而,这样的转换造成了大量的麻烦。

有人曾经评论过

国家的保密插件,是需要收费的,早期的时候,一个导航仪就需要10块钱的保密插件许可费。

至于这个插件的影响,使用过iPhone(iOS4.2以下版本)以及Android手机的用户应该体验深刻,用户在iPhone版的谷歌地图里打开“我的位置”,会发现自己的定位被偏移了几百米,在外出找路的时候尤其麻烦,让用户根本就无法通过谷歌地图来确定方位,以至于迷路。不明真相的用户纷纷谴责谷歌地图的定位准确度不好,其实真的是冤枉了谷歌。

好在这个所谓的“国家的保密插件”并不难破解,网友很容易就可以将其解密,把虚假的坐标转换成真实的坐标,这样,iPhone用户只需安装一个“中国地图校正”插件,就可以自动解决地图偏移的问题。对于Android用户来说,也有修改版的谷歌地图可以下载使用。

总之,国家测绘局的这个所谓的发明创新,最大的用处就是收钱和折腾用户,至于其实际保密效果就不敢恭维了。

WGS-84 与 GCJ-02间的转换

两个坐标系都要能够唯一标识地球上的每一个点。因而 WGS-84 和 GCJ-02 间的转换必然是一一对应的。一个 WGS-84 坐标便有一个对应的 GCJ-02 坐标,反之亦然。也就是说,他们相互之间的转换讲的也就是同一个点在两个坐标系里坐标的转换而已,没有什么特别的。

也就是说,转换的输入为一对 WGS-84 下的经纬度对,输出为 GCJ-02 下同一点的经纬度对。

我所能找到的最早流出的 WGS-84 至 GCJ-02 的转换算法出自 https://on4wp7.codeplex.com/SourceControl/changeset/view/21483。我们看一下它的代码中的一小部分,处理纬度加偏的前半部分:

-100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.Sqrt(Math.Abs(x)) + (20.0 * Math.Sin(6.0 * x * pi) + 20.0 * Math.Sin(2.0 * x * pi)) * 2.0 / 3.0 + (20.0 * Math.Sin(y * pi) + 40.0 * Math.Sin(y / 3.0 * pi)) * 2.0 / 3.0 + (160.0 * Math.Sin(y / 12.0 * pi) + 320 * Math.Sin(y * pi / 30.0)) * 2.0 / 3.0

这一部分已经体现了 GCJ-02 设计精巧的几点:

这是一个很长的多项式,并且是很复杂的多项超越式。于是它难以进行反向运算、难以根据已知数据点反推出计算公式。且就算我们拿到了这个已知的转换算法的公式,要想求出它的反函数是非常困难的,于是如果我们要完成 GCJ-02 到 WGS-84 的逆转换,只能通过二分法来逼近。

这个转换算法需要达到的要求是显而易见的:它必须是连续的,并且是单调的。连续才能确保地图不出现断点且覆盖所有区域;单调才能保证原先的位置相互关系转换后依旧成立。

进一步分析

既然转换太复杂,我实在是连求个导的心情都没有,我们就进行一些数值计算看看吧。

若以墨卡托投影来看,进行计算的范围在一个矩形内:
最西为东经 72°,最东为东经 135°。最男为北纬 18°,最北为北纬 54°。这个矩形恰好能包含除了南海诸岛外的中国领土。

通过以很小的步长进行穷算,并且再进一步进行逼近,我们发现:

在这个矩形内,纬度偏差最大处在 26.71°N, 72.60°E。纬度偏差为 -0.0040°。该位于印度。
经度偏差最大处在 54.02°N, 131.40°E。经度偏差为 0.0102°。该地位于俄罗斯。

这体现了 GCJ-02 的精妙:误差最大地方的都在国外。也就是说,GCJ-02 把在国内的误差控制在了较小的水平。

借助计算地球表面任意两点距离的算法,我们可以计算误差的具体距离。这个过程中考虑到了地球是个椭球体。不过由于偏移量较小,我们可以部分忽略两点是球面而不是平面这个事实。

计算结果是:
在矩形中,便宜最大的点偏移量为 718.3 米,坐标为 53.89°N, 131.40°E。该地位于俄罗斯。
在中国实际领土上:
偏移量最大值为 700 米,位于黑龙江省。
偏移量最小值为 18 米,位于青海省德令哈附近。

下面贴上两张图:第一张是进行计算的矩形内偏移量分布情况。颜色越深,偏移量越大,颜色越浅,偏移量越小。

第二张是贴上了政区图后的结果。红色为偏移量大,蓝色为偏移量小。

两张图都使用 Web Mercator 投影法(和墨卡托投影法类似,但忽略了地球的椭率)。第一张图略有拉伸。

结论

    • 流传的转换算法完全正确属实。可以很容易实现自动将 .kml、.gpx 等等坐标和轨迹文件自动转换为另一个坐标系下适用的。
    • 所谓“GCJ-02 偏移有两三公里”的说法是不靠谱的。事实证明 WGS-84 到 GCJ-02 所带来的偏移不超过 700 米。
时间: 2024-08-29 11:50:53

经纬度坐标互换的相关文章

【转】通过经纬度坐标计算距离的方法(经纬度距离计算)

最近在网上搜索“通过经纬度坐标计算距离的方法”,发现网上大部分都是如下的代码: #define PI 3.14159265 static double Rc = 6378137;  // 赤道半径 static double Rj = 6356725;  // 极半径 class JWD { public: double m_Longitude, m_Latitude; double m_RadLo, m_RadLa; double Ec; double Ed; public: JWD(doub

发送经纬度坐标给指定手机

public class LocationService extends Service { @Override public void onCreate() { super.onCreate(); //获取手机的经纬度坐标 //1,获取位置管理者对象 LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE); //2,以最优的方式获取经纬度坐标() Criteria criteria = new Crit

利用百度地图API,获取经纬度坐标

利用百度地图API,获取经纬度坐标 代码很简单,但在网上没找到现成的获取地图经纬度的页面. 就是想,给当前页面传递一个经纬度,自动定位到此经纬度.然后可以重新选择,选择完返回经纬度. 效果如下: 源代码下载:http://files.cnblogs.com/zjfree/select_map.rar 利用百度地图API,获取经纬度坐标,布布扣,bubuko.com

Android中由IP地址查询经纬度坐标的实例

大家都知道,根据IP地址就可以知道它所在的具体位置,在Android中同样可以由IP地址得到它的位置,即具体的地理经纬度坐标. 本文就直接以代码的方式演示如何根据IP地址查询地理经纬度坐标位置,下面的例子中演示的就是由58.192.32.1这个IP地址查询到其所在的经纬度坐标为(118.777802,32.061699). Java代码 package eoe.demo; import com.mapdigit.gis.DigitalMap; import com.mapdigit.gis.Ma

微信lbs---返回两个经纬度坐标点的距离

微信开发:lbs附近的商家,在数据库里记录商家的坐标,lbs设置里管理搜索半径,查询的时候,查询 客户当前坐标的半径内的所有商家列表.个人喜欢不一样,我选择了执行sql ,毕竟效果高点.微信开发必须得将就效率问题.不然等半天出不来,急死人,半天出不来结果,客户直接走人.不多说,直接上代码 \\返回两个经纬度坐标点的距离(单位:米) \\C#  方法 ///<summary>返回两个经纬度坐标点的距离(单位:米) by Alex.Y</summary>         ///<

提取行政区边界经纬度坐标(高德+百度)

前言 近来由于工作需要,需要提取某些城市的经纬度坐标,稍微搜索了一下,发现百度地图和高德地图都提供了相关的函数和例子.那么剩余的工作也就比较简单了,保存坐标,然后转换为WGS坐标,这样才能和现有的GPS数据以及地图匹配. 主要问题和解决方法 本地保存文件跨浏览器支持 由于安全的原因,JavaScript本地保存文件的方式通常都只有IE支持的ActiveXObject/Open方法,每次都要提示不安全和允许运行,非常麻烦.好在其他浏览器目前都支持<a>标签实现文件下载的方法.经测试最新的Goog

微信获取到的经纬度坐标不精准的问题

(转自:风行天下 http://www.cnblogs.com/php-linux/p/4730744.html) 微信如何根据经纬度坐标查询具体地理位置 好多人会问为什么微信高级接口获取的坐标信息位置不准,主要原因不是微信获取的不准,而是微信获取的是gps坐标,如果你直接用百度或google的api去解析的话肯定会出现误差的. 首先你需要吧gps位置转换成google或者百度的坐标,然后在通过转换后的坐标去获取准确的地理位置. 方法一:gps转换成google或者百度坐标,转换gps的接口 h

根据经纬度坐标获取对应的切片算法

根据经纬度坐标获取对应的切片算法,含天地图.谷歌等. Javascript: 1 function getPoints2() 2 { 3 var topTileFromX = -180; 4 var topTileFromY = 90; 5 6 var tdtScale={18:5.36441802978515E-06,17:1.07288360595703E-05,16:2.1457672119140625E-05,15:4.29153442382814E-05,14:8.5830688476

经纬度坐标与地图容器像素坐标相互转换

<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="initial-scale=1.0, user-scalable=no, wi