美国GPS使用的是WGS84的坐标系统,但我国,出于国家安全考虑,国内所有导航电子地图必须使用国家测绘局制定的加密坐标系统,即偏移后(或变形后)经纬度坐标,前者称之为地球坐标,后者称之为火星坐标。
国内各地图API坐标系统:
API | 坐标系 |
---|---|
百度地图API | 百度坐标 |
腾讯搜搜地图API | 火星坐标 |
搜狐搜狗地图API | 搜狗坐标* |
高德MapABC地图API | 火星坐标 |
其中,何为百度坐标?国际经纬度坐标标准为WGS-84,国内必须至少使用国测局制定的GCJ-02(火星坐标系),对地理位置进行首次加密。百度坐标在此基础上,进行了BD-09(百度坐标系)二次加密措施。
火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法
void bd_encrypt(double gg_lat, double gg_lon, double &bd_lat, double &bd_lon)
{
double x = gg_lon, y = gg_lat;
double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);
bd_lon = z * cos(theta) + 0.0065;
bd_lat = z * sin(theta) + 0.006;
}
void bd_decrypt(double bd_lat, double bd_lon, double &gg_lat, double &gg_lon)
{
double x = bd_lon - 0.0065, y = bd_lat - 0.006;
double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);
double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);
gg_lon = z * cos(theta);
gg_lat = z * sin(theta);
}
地球坐标系 (WGS-84) 和火星坐标系 (GCJ-02) 的相互转换
WGS-84 到 GCJ-02 的转换(即 GPS 加偏)算法在互联网上是公开的,请使用 Google 搜索 “wgtochina_lb” 。整理后的算法代码请参考 https://on4wp7.codeplex.com/SourceControl/changeset/view/21483#353936 。至于 GCJ-02 到 WGS-84 的转换(即 GPS 纠偏),可以使用二分法。
下面是我写的百度坐标转火星坐标的工具类
public class CoordUtil {
private static final double PI=3.14159265358979324;
/**
* BD-09 坐标转换成 GCJ-02 坐标(火星坐标系)
* 百度坐标 转换为 高德坐标
* 方法1
* @return
*/
public static double[] bdDecrypt(double bd_lon, double bd_lat){
double x_pi = PI * 3000.0 / 180.0;
double x = bd_lon - 0.0065;
double y = bd_lat - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
double gd_lon = z * Math.cos(theta);
double gd_lat = z * Math.sin(theta);
double[] outXY = new double[2];
outXY[0] = gd_lon;
outXY[1] = gd_lat;
return outXY;
}
/**
* BD-09 坐标转换成 GCJ-02 坐标(火星坐标系)
* 百度坐标 转换为 高德坐标
* 方法2
* @param bd_lon
* @param bd_lat
* @return
*/
public static double[] bdDecrypt2(double bd_lon, double bd_lat){
double x=bd_lon;
double y=bd_lat;
double xx =Math.cos(getDeltaT(x) + Math.atan2(y, x))*(getDeltaR(y)+Math.sqrt(x*x+y*y))+0.0065;
double yy = Math.sin(getDeltaT(x)+Math.atan2(y, x))*(getDeltaR(y)+Math.sqrt(x*x +y*y)) + 0.006;
double dx = xx - x;
double dy = yy - y;
double gd_lon = x - dx;
double gd_lat = y - dy;
double[] outXY = new double[2];
outXY[0] = gd_lon;
outXY[1] = gd_lat;
return outXY;
}
public static double getDeltaR(double y){
return Math.sin(y * 3000 * (PI / 180))* 0.00002;
}
public static double getDeltaT(double x){
return Math.cos(x * 3000 * (PI / 180))* 0.000003;
}
}