Conversion between Baidu coordinates, Mars coordinates and WGS-84
In the process of map development, we usually come into contact the 3 types of map coordinate systems.
Different coordinate systems are incompatible. e.g. the longitude and latitude located on Baidu map will be offset when they are directly traced on Gaode map.
3 types of map coordinate systems
In the process of map development, we usually come into contact the following 3 types of map coordinate systems:
1. WGS-84
WGS-84 original coordinate system is generally based on the longitude and latitude recorded by the International GPS recorder, the original longitude and latitude obtained through GPS positioning.
The longitude and latitude (abroad) located by Google and Gaode maps are based on WGS-84 coordinate system, but in China, it is not allowed to mark directly with WGS-84 coordinate system, which can only be used after encryption.
2. Mars coordinates
Gcj-02 coordinate system, also known as "Mars coordinate system", is an original coordinate system created by China's Survey Bureau. It is encrypted by WGS-84.
In China, gcj-02 coordinate system must be used at least, or a coordinate system encrypted after gcj-02 encryption, such as Baidu coordinate system.
Both Gaode and Google use gcj-02 coordinate system in China. It can be said that gcj-02 is the most widely used coordinate system in China
3. Baidu coordinates
Bd-09 is a coordinate system formed by encrypting and offsetting again on the basis of gcj-02 coordinate system, which is only applicable to Baidu map.
By the way, there is another coordinate system called CGCS2000.
In fact, we often directly use WGS-84 coordinates to replace CGCS2000 coordinates. Because the definition of CGCS2000 is essentially the same as WGS-84.
The reference ellipsoid used is very close. The variation of latitude and height on the ellipsoid caused by the difference of oblateness is up to 0.1mm. This difference can be ignored within the current measurement accuracy range.
Why does the offset occur
Because different coordinate systems are incompatible.
For example, the longitude and latitude located on Baidu map will be offset when they are directly traced on Gaode map.
Java code is as follows:
public class LonlatConver {
// public static void main(String[] args) {
// Double lon = 113.262821;
// Double lat = 23.138022;
// double[] doubleArr = bd09_To_Gcj02(lon, lat);
// 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;
}
}