在涉及到经纬度的地方,我们在编码的时候,经常需要进行转换。而且转换代码似乎非常复杂,真正理解,其实需要做一些工作,这里我将了解的经纬度坐标相关的知识做一个梳理。

首先了解经纬度坐标系统。

因为地球并不是一个规则的球体,而是一个椭球体。如何对椭球体进行坐标划定,这里有以下几种:

这里面提到的WGS84,也叫大地坐标系,它是原始坐标系统,为了数据安全和保密,通过地形图非线性保密处理算法(俗称火星加密)加密过的WGS84坐标系,俗称国测局坐标系,或火星坐标系就是我们今天所要提到的GCJ02,目前谷歌地图(中国cn)、腾讯地图、高德地图,使用的都是GCJ02,只有百度地图没有使用这种加密算法,而是使用的是BD09,从名字上可以看出,GCJ02是2002年提出来的算法,BD09则是2009年提出来的,虽然百度地图没有使用GCJ02加密算法,但是他却是在GCJ02基础上做了一个二次加密,所以说,从WGS84坐标系不能直接转BD09,中间需要跨越一个GCJ02,反过来,需要将GCJ02或者BD09转为WGS84就是纠偏算法,相当于逆向解密,同样的DB09直接到不了WGS84,中间还需要转为GCJ02,所以现在的很多算法,如果你看到有百度坐标转大地坐标,基本上需要借助火星坐标来计算。

上面说了坐标转换算法之间的关系,下面来说说具体的算法:

一般,你的算法里面,可能会有如下几个变量:

  public static double pi = 3.1415926535897932384626;public static double a = 6378245.0;public static double ee = 0.00669342162296594323;

结合上面的表格,你就知道,它采用了何种椭球系数。显然,这是采用了克拉索索夫斯基椭球系数。有的地方称ee是扁率,其实不对,其实是我们上面提到的第一偏心率e的平方。

WGS84转GCJ02的理论公式:

上面公式里面有个经纬度偏移值:{105,35}。这个其实是中华人民共和国大地原点坐标。位置在中国陕西省咸阳市下的泾阳县。

这个公式看着很复杂,最麻烦的在于对经纬度做一个多项式转换。即使很麻烦,但是根据公式,我们通过代码也能一步步算出最终的结果。

反过来,火星坐标系转大地坐标系,推导公式:

package com.xxx.huali.hualitest.algorithm;
/**** wgs84 84年提出,大地坐标,也是原始坐标。* gcj02 02年提出,火星坐标,经过加密算法。大多数非百度中国地图厂商基本都是使用的火星坐标:高德,腾讯,谷歌中国cn* bd09  09年提出,百度坐标,经过火星坐标再次加密,相当于对大地坐标经过了二次加密。百度自己使用* 一般的算法,没有直接bd09->wgs84或者wgs84->bd09,都需要借助wgs84->gcj02或者gcj02->wgs84算法推导。*/
public class GpsTransfer {//π的定义public static double pi = 3.1415926535897932384626;//椭球长半径,依据克拉索索夫斯基椭球系数计算public static double a = 6378245.0;  //第一偏心率的平方public static double ee = 0.00669342162296594323;public static double transformLat(double x, double y) {double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y+ 0.2 * Math.sqrt(Math.abs(x));ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;return ret;}public static double transformLon(double x, double y) {double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1* Math.sqrt(Math.abs(x));ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0* pi)) * 2.0 / 3.0;return ret;}/**** 判断是否在中国范围之内* @param lat* @param lon* @return*/public static boolean outOfChina(double lat, double lon) {if (lon < 72.004 || lon > 137.8347)return true;if (lat < 0.8293 || lat > 55.8271)return true;return false;}/**** 把公式部分抽取出来* @param lat* @param lon* @return*/public static Gps transform(double lat, double lon) {if (outOfChina(lat, lon)) {return new Gps(lat, lon);}double dLat = transformLat(lon - 105.0, lat - 35.0);double dLon = transformLon(lon - 105.0, lat - 35.0);double radLat = lat / 180.0 * pi;double magic = Math.sin(radLat);magic = 1 - ee * magic * magic;double sqrtMagic = Math.sqrt(magic);dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);double mgLat = lat + dLat;double mgLon = lon + dLon;return new Gps(mgLat, mgLon);}/**** wgs84到gcj02转换* @param lat* @param lon* @return*/public static Gps wgs84_To_Gcj02(double lat, double lon) {return transform(lat, lon);}/**** 简单的gcj02到wgs84坐标类型转换,只做了一次迭代*/public static Gps gcj02_To_Wgs84(double lat, double lon) {Gps gps = transform(lat, lon);double lontitude = lon * 2 - gps.lon;double latitude = lat * 2 - gps.lat;return new Gps(latitude, lontitude);}/**** 稍微精确一点的gcj02到wgs84转换* @param lat* @param lon* @return*/public static Gps gcj02_To_Wgs84_exact(double lat,double lon) {if (outOfChina(lat, lon)) {return gcj02_To_Wgs84(lat, lon);}double initDelta = 0.01;double threshold = 0.000001;double dLat = initDelta;double dLon = initDelta;double mLat = lat - dLat;double mLon = lon - dLon;double pLat = lat + dLat;double pLon = lon + dLon;double wgsLat = 0;double wgsLon = 0;int i = 0;while (true) {wgsLat = (mLat + pLat) / 2;wgsLon = (mLon + pLon) / 2;Gps tmp = wgs84_To_Gcj02(wgsLat, wgsLon);dLat = tmp.lat - lat;dLon = tmp.lon - lon;if ((Math.abs(dLat) < threshold) && (Math.abs(dLon) < threshold)) {break;}if (dLat > 0) { pLat = wgsLat; } else { mLat = wgsLat;}if (dLon > 0) { pLon = wgsLon; } else { mLon = wgsLon;}if (++i > 1000) break;}return new Gps(wgsLat, wgsLon);}/**** 百度坐标是在火星坐标基础上做的二次加密* @param gg_lat* @param gg_lon* @return*/public static Gps gcj02_To_Bd09(double gg_lat, double gg_lon) {double x = gg_lon, y = gg_lat;double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);double bd_lon = z * Math.cos(theta) + 0.0065;double bd_lat = z * Math.sin(theta) + 0.006;return new Gps(bd_lat, bd_lon);}/**** 百度坐标与火星坐标逆向转换* @param bd_lat* @param bd_lon* @return*/public static Gps bd09_To_Gcj02(double bd_lat, double bd_lon) {double x = bd_lon - 0.0065, y = bd_lat - 0.006;double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi);double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi);double gg_lon = z * Math.cos(theta);double gg_lat = z * Math.sin(theta);return new Gps(gg_lat, gg_lon);}public static void main(String[] args) {Gps gps = new Gps(39.9072885060602, 116.39123343289631);System.out.println(gps);//{39.9072885060602,116.39123343289631}Gps gps2 = wgs84_To_Gcj02(gps.lat, gps.lon);System.out.println(gps2);//{39.9086897410389,116.39747455259267}Gps gps3 = gcj02_To_Wgs84(gps2.lat, gps2.lon);System.out.println(gps3);//{39.907286247736586,116.39123098626051}Gps gps4 = gcj02_To_Wgs84_exact(gps2.lat, gps2.lon);System.out.println(gps4);//{39.907288984202964,116.3912337078661} 相对一次迭代是精确了,但是好像也不是完全还原}}class Gps{double lat,lon;public Gps() {}public Gps(double lat,double lon){this.lat = lat;this.lon = lon;}@Overridepublic String toString() {return "{"+lat+","+lon+"}";}
}

上面这段代码,没有对百度坐标bd09转大地坐标wgs84、大地坐标wgs84转百度坐标bd09进行书写,如果你了解了前面所说的坐标之间的关系,你大概就能猜到,只需要借助wgs84->gcj02  gcj02->bd09就能实现wgs84->bd09的实现。相反,借助bd09->gcj02  gcj02->wgs84就能实现bd09->wgs84的转换了。

我以前不了解这些坐标之间的关系,以为他们之间的转换非常复杂,其实当你了解了坐标之间的关系,就很容易理解了。

总结一下就是:

WGS84是大地坐标系,这是一种国际通用的坐标,中国的大地坐标是CGCS2000,也是原始坐标系,一般的终端设备,如果自己有定位功能,比如车载系统,他们发出的gps坐标就是原始坐标,我们在一些地图应用中使用的定位,比如打车软件,其他自带地图的软件,他们一般都是火星坐标系GCJ02,需要进行一个坐标转换。而百度地图相关的应用,基本都是使用的百度坐标,这个是在火星坐标基础上进行的再次加密,所以它还是与火星坐标有关系。

WGS84与GCJ02经纬度坐标转换介绍相关推荐

  1. WGS84与GCJ02、BD09经纬度坐标转换介绍

    在涉及到经纬度的地方,我们在编码的时候,经常需要进行转换.而且转换代码似乎非常复杂,真正理解,其实需要做一些工作,这里我将了解的经纬度坐标相关的知识做一个梳理. 首先了解经纬度坐标系统. 因为地球并不 ...

  2. php 经纬度坐标转换 WGS84、火星坐标 (GCJ-02)、百度坐标 (BD-09)

    项目有gps上报的功能, 由于前端插件问题导致大量gps定位数据转换百度坐标(BD-09)时产生极大偏移, 故需要后端做经纬度坐标转换, 看到一篇java的相关技术帖, 拿来做了修改 Ps: 坐标转换 ...

  3. WGS84、GCJ-02、BD-09、图吧坐标简介及坐标转换实现(js版)

    1.不同地图服务商的坐标系 出于国家安全考虑不同的国家在规定地图服务提供商在提供地图服务的时候需要将地图数据进行加密.现在比较流行的坐标系有WGS84.GCJ-02.BD-09,且各个坐标之间存在偏差 ...

  4. WGS84、GCJ-02、BD-09、图吧坐标简介及坐标转换实现(java版)

    1.定位系统及如何定位 现在全球有四个卫星定位系统:美国的全球定位系统GPS(Global Positioning System),俄罗斯的格洛纳斯GIONASS, 欧盟的伽利略系统,我国的北斗. 每 ...

  5. Android开发:WGS-84、GCJ02坐标名词解释及坐标转换

    WGS-84.GCJ02坐标名词解释及坐标转换 目录 一.什么是WSG-84坐标系? 二 .什么是GCJ-02坐标系? 三.GCJ-02坐标系使用场景 四.函数说明 五.工具类代码 注:本文仅包含国测 ...

  6. GIS数据格式坐标转换(地球坐标WGS84、GCJ-02、火星坐标、百度坐标BD-09、国家大地坐标系CGCS2000)

    文章目录 前言 一.坐标系 1.地球坐标 (WGS84) 2.国测局坐标系(GCJ-02.火星坐标系) 3.百度坐标(BD-09) 4.国家大地2000坐标系(CGCS2000) 二.百度坐标系(BD ...

  7. wgs84坐标格式转换度分秒_WGS84经纬度坐标转换到西安80高斯投影坐标。

    带号18,并且对应的中央子午线是105°,说明是按6度带划分计算的.你注意看你的标题"WGS84经纬度坐标转换到西安80高斯投影坐标",就是说是在高斯坐标系下的平面坐标,高斯投影坐 ...

  8. Unity经纬度相互转换(WGS-84、GCJ-02、BD-09)

    /***  *   *    Title: MXFramework  *           主题: GPS工具类  *    Description:   *           功能:1.各种坐标 ...

  9. CesiumForUnreal之UE世界坐标与WGS84经纬度坐标转换原理与应用

    文章目录 1.UE世界坐标与经纬度坐标转换原理 1.1 坐标系介绍 1.1.1 UE坐标系 1.1.2 地理坐标系 1.1.3 ECEF坐标系 1.1.4 投影坐标系 1.1.5 ENU坐标系 1.2 ...

  10. WGS84 / BD09 / GCJ02 / MapBar 经纬度坐标互转

    WGS84 / BD09 / GCJ02 / MapBar 经纬度坐标互转 Geolocataion converting between WGS84, BD09 and GCJ02. WGS84 / ...

最新文章

  1. SQL Server 跨域访问
  2. 如何委婉的表达你的心思?
  3. linux下载带中文名的文件夹,如何在Linux下删除文件名是乱码或者带有特殊字符的文件...
  4. Java和ABAP里的外部类和内部类
  5. nessuss中文使用手册
  6. 谷歌浏览器如何设置flash访问权限
  7. 线性回归(一元、多元)
  8. ubuntu安装 opencv-3.4.3
  9. 如何深入学习c语言,如何深入学习C语言?
  10. dotween路径移动_unity 移动物体到指定位置的几种方法
  11. javascript提取顶级域名 js获取一级域名
  12. 微信小程序自定义标题栏
  13. 广告是如何找到你的?
  14. c语言 小学生测试题,C语言编程测试题(含答案)
  15. Webstorm 2019激活码(有效期至2020年6月)
  16. JavaScript_第一天
  17. 泰森多面体Voronoi 3D-V5.0 功能介绍
  18. 遅くまで起きる vs 遅くまで寝る
  19. Windin10 Vs2017找不到 stdio.h
  20. 秉火429笔记之八 RCC时钟

热门文章

  1. 前端工程师找工作,你需要准备什么?
  2. 用python做探索性因子分析(Exploratory Factor Analysis,EFA)全代码
  3. 你要的理论、法则、定律、效应都在这里了
  4. python给批量图片添加文字_Python之利用PIL批量给图片添加文字
  5. python3中expected an indented block(缩进问题)
  6. 图灵接口 php,图灵机器人API接口
  7. 苹果手机投影_家用无线投影解决方案
  8. 计算快递费系统(java版)
  9. 一文搞懂 Flink如何移动计算
  10. 清明节黑白效果=来聊聊色彩矩阵算法