地图坐标系目前包括:
地球坐标 (WGS84)
WGS84:World Geodetic System 1984,是为GPS全球定位系统使用而建立的坐标系统。
国际标准,从 GPS 设备中取出的数据的坐标系
国际地图提供商使用的坐标系
火星坐标 (GCJ-02)也叫国测局坐标系
GCJ-02是由中国国家测绘局(G表示Guojia国家,C表示Cehui测绘,J表示Ju局)制订的地理信息系统的坐标系统。
它是一种对经纬度数据的加密算法,即加入随机的偏差。
国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密。
中国标准,从国行移动设备中定位获取的坐标数据使用这个坐标系
国家规定: 国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密。
百度坐标 (BD-09)
百度标准,百度 SDK,百度地图,Geocoding 使用
(本来就乱了,百度又在火星坐标上来个二次加密)
注意事项
从SDK获取GPS坐标:
百度sdk可获得百度坐标(bd09)或火星坐标(GCJ02),默认是bd09
ios原生定位库,获得WGS84坐标
腾讯、高德sdk,获取GCJ02坐标
链接:https://www.jianshu.com/p/8eaadf3696f9
坐标转换工具
package com.yymt.common.utils;
/**
* 坐标转换工具
*
*/
public class CoordinateUtil {
private static double pi = 3.14159265358979324;
private static double a = 6378245.0;
private static double ee = 0.00669342162296594323;
private static double x_pi = 3.14159265358979324 * 3000.0 / 180.0;
private 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;
}
private 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;
}
private 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;
}
/**
* 地球坐标转换为火星坐标 World Geodetic System ==> Mars Geodetic System
*
* @param wgLat
* 地球坐标
* @param wgLon
*
* mglat,mglon 火星坐标
*/
public static Double[] transform2Mars(double wgLat, double wgLon) {
Double[] gps = new Double[2];
double mgLat, mgLon;
if (outOfChina(wgLat, wgLon)) {
mgLat = wgLat;
mgLon = wgLon;
gps[0] = mgLat;
gps[1] = mgLon;
return gps;
}
double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
double radLat = wgLat / 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);
mgLat = wgLat + dLat;
mgLon = wgLon + dLon;
gps[0] = mgLat;
gps[1] = mgLon;
return gps;
}
/**
* 火星坐标转换为百度坐标
*
* @param gg_lat,gg_lon
* 火星坐标
* @param bd_lat,bd_lon百度坐标
*/
public static Double[] bd_encrypt(double gg_lat, double gg_lon) {
Double[] gps = new Double[2];
double bd_lat, bd_lon;
double x = gg_lon, y = gg_lat;
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);
bd_lon = z * Math.cos(theta) + 0.0065;
bd_lat = z * Math.sin(theta) + 0.006;
gps[0] = bd_lat;
gps[1] = bd_lon;
return gps;
}
/**
* 百度转火星
*
* @param bd_lat,bd_lon百度坐标
* @param gg_lat,gg_lon
* 火星坐标
*/
public static Double[] bd_decrypt(double bd_lat, double bd_lon) {
Double[] gps = new Double[2];
double gg_lat, gg_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 * x_pi);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
gg_lon = z * Math.cos(theta);
gg_lat = z * Math.sin(theta);
gps[0] = gg_lat;
gps[1] = gg_lon;
return gps;
}
public static void main(String[] args) {
double lat = 25.8342771800;
double lon = 114.9300374800;
Double[] g1 = bd_decrypt(lat, lon);
System.out.println(g1[0]+"\t"+g1[1]);
Double[] gps2mars = transform2Mars(lat, lon);
System.out.println(gps2mars[0]+"\t"+gps2mars[1]);
}
}
坐标转换工具类2
package com.yymt.common.utils;
import net.sf.json.JSONObject;
/**
* 坐标转换工具类
* GCJ02: 火星坐标系,中国国家测绘局制定的坐标系统,由WGS84机密后的坐标。Google Map中国和搜搜地图使用,高德
* BD09:百度坐标,GCJ02机密后的坐标系
*
* @author xiezhen
* @date 2019/12/28/02810:12
*/
public class GPSConverterUtils {
public static double pi = 3.1415926535897932384626;
/**
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标
*/
public static JSONObject bd09_To_Gcj02(double bd_lat, double bd_lng) {
double x = bd_lng - 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);
JSONObject json = new JSONObject();
json.put("lng", z * Math.cos(theta));//经度
json.put("lat", z * Math.sin(theta));//纬度
return json;
}
/**
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 GCJ-02 坐标转换成BD-09 坐标
*/
public static JSONObject 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);
JSONObject json = new JSONObject();
json.put("lng", z * Math.cos(theta) + 0.0065);
json.put("lat", z * Math.sin(theta) + 0.006);
return json;
}
public static void main(String[] args) {
System.out.println(bd09_To_Gcj02(39.12, 116.83));
}
}
坐标转换工具类3(完整)
public class LonlatConver {
/* public static void main(String[] args) {
Double lat = 121.368383;
Double lon = 31.236216;
double[] doubleArr1 = wgs84_To_Gcj02(lat, lon);
System.out.println(doubleArr1[0]+"===="+doubleArr1[1]);
double[] doubleArr = gcj02_To_Bd09(doubleArr1[0], doubleArr1[1]);
// double[] doubleArr = gcj02_To_Bd09(lat, lon);
System.out.println(doubleArr[0]+"===="+doubleArr[1]);
}*/
/**
* a
*/
public final static double a = 6378245.0;
/**
* ee
*/
public final static double ee = 0.00669342162296594323;
//圆周率 GCJ_02_To_WGS_84
public final static double pi = 3.14159265358979324;
/**
* @Description WGS84 to 火星坐标系 (GCJ-02)
* @param lon 经度
* @param lat 纬度
* @return
*/
public static double[] wgs84_To_Gcj02(double lon, double lat) {
if (outOfChina(lat, lon)) {
return null;
}
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 double[] { mgLon, mgLat };
}
/**
* @Description 火星坐标系 (GCJ-02) to WGS84
* @param lon
* @param lat
* @return
*/
public static double[] gcj02_To_Wgs84(double lon, double lat) {
double[] gps = transform(lat, lon);
double lontitude = lon * 2 - gps[1];
double latitude = lat * 2 - gps[0];
return new double[] { lontitude, latitude };
}
/**
* @Description 火星坐标系 (GCJ-02) to 百度坐标系 (BD-09)
* @param gg_lon
* @param gg_lat
* @return
*/
public static double[] gcj02_To_Bd09(double gg_lon, double gg_lat) {
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 double[] { bd_lon, bd_lat };
}
/**
* @Description 百度坐标系 (BD-09) to 火星坐标系 (GCJ-02)
* @param bd_lon
* @param bd_lat
* @return
*/
public static double[] bd09_To_Gcj02(double bd_lon, double bd_lat) {
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 double[] { gg_lon, gg_lat };
}
/**
* @Description 百度坐标系 (BD-09) to WGS84
* @param bd_lat
* @param bd_lon
* @return
*/
public static double[] bd09_To_Wgs84(double bd_lon,double bd_lat) {
double[] gcj02 = LonlatConver.bd09_To_Gcj02(bd_lon, bd_lat);
double[] map84 = LonlatConver.gcj02_To_Wgs84(gcj02[0], gcj02[1]);
return map84;
}
/**
* @Description 判断是否在中国范围内
* @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;
}
/**
* @Description transform
* @param lat
* @param lon
* @return
*/
private static double[] transform(double lat, double lon) {
if (outOfChina(lat, lon)) {
return new double[] { 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 double[] { mgLat, mgLon };
}
/**
* @Description transformLat
* @param x
* @param y
* @return
*/
private 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;
}
/**
* @Description transformLon
* @param x
* @param y
* @return
*/
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;
}
/**
* GPS经纬度转换为 度(3114.1717,12122.1067 → 121.37300779,31.23436014)
* @param dms 坐标
* @param type 坐标类型 E/N
* @return String 解析后的经纬度
*/
public static String gpsToWgs84(String dms, String type) {
if (dms == null || dms.equals("")) {
return "0.0";
}
double result = 0.0D;
String temp = "";
if (type.equals("E")) {//经度
String e1 = dms.substring(0, 3);//截取3位数字,经度共3位,最多180度
//经度是一伦敦为点作南北两极的线为0度,所有往西和往东各180度
String e2 = dms.substring(3, dms.length());//需要运算的小数
result = Double.parseDouble(e1);
/* System.out.println("e2===="+e2);
System.out.println("===="+Double.parseDouble(e2) / 60.0D);*/
result += (Double.parseDouble(e2) / 60.0D);
temp = String.valueOf(result);
if (temp.length() > 11) {
temp = e1 + temp.substring(temp.indexOf("."), 11);
}
} else if (type.equals("N")) { //纬度,纬度是以赤道为基准,相当于把地球分两半,两个半球面上的点和平面夹角0~90度
String n1 = dms.substring(0, 2);//截取2位,纬度共2位,最多90度
String n2 = dms.substring(2, dms.length());
result = Double.parseDouble(n1);
/* System.out.println("n2===="+n2);
System.out.println("===="+Double.parseDouble(n2) / 60.0D);*/
result += Double.parseDouble(n2) / 60.0D;
temp = String.valueOf(result);
if (temp.length() > 10) {
temp = n1 + temp.substring(temp.indexOf("."), 10);
}
}
return temp;
}
}
/**
* 计算地球上任意两点(经纬度)距离
*
* @param lat1
* 第一点纬度
* @param lng1
* 第一点经度
* @param lat2
* 第二点纬度
* @param lng2
* 第二点经度
* @return 返回距离 单位:米
*/
public static double distance(double lat1, double lng1, double lat2, double lng2) {
double a, b, R;
R = 6378137; // 地球半径
lat1 = lat1 * Math.PI / 180.0;
lat2 = lat2 * Math.PI / 180.0;
a = lat1 - lat2;
b = (lng1 - lng2) * Math.PI / 180.0;
double d;
double sa2, sb2;
sa2 = Math.sin(a / 2.0);
sb2 = Math.sin(b / 2.0);
d = 2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));
return d;
}