Android 定位地理坐标体系
参考:
地球坐标系 (WGS-84) 到火星坐标系 (GCJ-02)百度坐标系 (BD-09) 的转换算法
火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法
1. 中国国测局地理坐标(GCJ-02)<即火星坐标>
谷歌中国地图、搜搜中国地图、高德地图采用的是GCJ02(其中苹果地图在大陆的数据源是高德)地理坐标系
2. 世界标准地理坐标(WGS-84)
谷歌地图采用的是WGS84地理坐标系(中国范围除外)。
3. 百度地理坐标(BD-09)
百度定位SDK可以返回三种坐标系,分别是bd09, bd09ll(默认)和gcj02,其中bd09ll能无偏差地显示在百度地图上。
而设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系,所以我们要根据得到的经纬度的坐标类型和地图厂商类型在地图上标点,否则会出现获取的位置误差。
注意:
后缀ll=经纬度球面坐标,mc=墨卡托平面坐标。当定位SDK中输入gcj02时,默认为经纬度坐标,输入bd09时,默认为墨卡托平面坐标。
百度地图api中采用两种坐标体系,经纬度坐标系和墨卡托投影坐标系。前者单位是度,后者单位是米,具体定义可以参见百科词条解释: http://baike.baidu.com/view/61394.htm和http://baike.baidu.com/view/301981.htm 。
以百度地图为例
百度地图采用的是自己的BD09坐标。如果我们通过GPS获取的坐标,也就是WGS84坐标,那么我们首先要将WGS坐标转换成BD09坐标。
转换成百度坐标下的经纬度即可有在地图上标点,当然,百度获取的文字详情不如高德,有时想要获取位置详情,需要调用高德的接口,而高德采用的标准是 GCJ02,因此,如果拿到百度地图的经纬度或是GPS经纬度,则要转成国测局的标准,以获取位置详细信息。
相互间的单位转换如下:
(1)世界标准地理坐标(WGS-84) 转换成 中国国测局地理坐标(GCJ-02)<火星坐标>
1 static double jzA = 6378245.0; 2 static double jzEE = 0.00669342162296594323; 3 static double pi = 3.14159265358979324;
1 static double transformLat(double x, double y) 2 { 3 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)); 4 ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; 5 ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; 6 ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; 7 return ret; 8 } 9 10 static double transformLon(double x, double y) 11 { 12 double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); 13 ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; 14 ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; 15 ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0; 16 return ret; 17 }
1 public static float[] gcj02Encrypt(double ggLat, double ggLon) { 2 float[] resPoint = new float[2]; 3 double mgLat; 4 double mgLon; 5 double dLat = transformLat(ggLon - 105.0, ggLat - 35.0); 6 double dLon = transformLon(ggLon - 105.0, ggLat - 35.0); 7 double radLat = ggLat / 180.0 * Math.PI; 8 double magic = Math.sin(radLat); 9 magic = 1 - jzEE * magic * magic; 10 double sqrtMagic = Math.sqrt(magic); 11 dLat = (dLat * 180.0) / ((jzA * (1 - jzEE)) / (magic * sqrtMagic) * Math.PI); 12 dLon = (dLon * 180.0) / (jzA / sqrtMagic * Math.cos(radLat) * Math.PI); 13 mgLat = ggLat + dLat; 14 mgLon = ggLon + dLon; 15 16 resPoint[0] = (float) mgLat; 17 resPoint[1] = (float) mgLon; 18 return resPoint; 19 }
(2)中国国测局地理坐标(GCJ-02) 转换成 世界标准地理坐标(WGS-84)
*******接口有1-2米左右的误差,需要精确定位情景慎用*****
1 public static float[] gcj02Decrypt(double gjLat, double gjLon) { 2 float[] gPt = gcj02Encrypt(gjLat, gjLon); 3 double dLon = gPt[1] - gjLon; 4 double dLat = gPt[0] - gjLat; 5 float[] pt = new float[2]; 6 pt[0] = (float) (gjLat - dLat); 7 pt[1] = (float) (gjLon - dLon); 8 return pt; 9 }
(3)世界标准地理坐标(WGS-84) 转换成 百度地理坐标(BD-09)
1 // 首先转换获取到GCJ-02的坐标 2 float[] gcj02Pt = gcj02Encrypt(latitude,longitude);
1 // 传入中国国测局地理的坐标 2 public static float[] bd09Encrypt(double ggLat, double ggLon) { 3 float[] bdPt = new float[2]; 4 double x = ggLon, y = ggLat; 5 double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * Math.PI); 6 double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * Math.PI); 7 bdPt[1] = (float) (z * Math.cos(theta) + 0.0065); 8 bdPt[0] = (float) (z * Math.sin(theta) + 0.006); 9 return bdPt; 10 }
(4)中国国测局地理坐标(GCJ-02)<火星坐标> 转换成 百度地理坐标(BD-09)
1 // 用以上办法 2 public static float[] bd09Encrypt(double ggLat, double ggLon)
(5)百度地理坐标(BD-09) 转换成 中国国测局地理坐标(GCJ-02)<火星坐标>
1 public static float[] bd09Decrypt(double bdLat, double bdLon) { 2 float[] gcjPt = new float[2]; 3 double x = bdLon - 0.0065, y = bdLat - 0.006; 4 double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI); 5 double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI); 6 gcjPt[1] = (float) (z * Math.cos(theta)); 7 gcjPt[0] = (float) (z * Math.sin(theta)); 8 return gcjPt; 9 }
(6)百度地理坐标(BD-09) 转换成 世界标准地理坐标(WGS-84)
*******接口有1-2米左右的误差,需要精确定位情景慎用*****
1 // 先将百度坐标 转换成 中国国测局坐标 2 float[] gcj02 = bd09ToGcj02(latitude,longitude);
1 // 再传入 中国国测局坐标 返回 世界标准地理坐标 2 gcj02Decrypt(gcj02[0], gcj02[1]);