By: Igor Ma.
16 FEB 2016
3237
About a year ago we were dealing with a project on data mapping in Chinese maps. In the process of development, we came across the pitfalls described in this article.
Initially, we used
Encryption of geographical position in China
After implementing and testing the two maps, another interesting feature was identified – the coordinates that correspond to specific places in China point to completely different places. The solution was not obvious. In China no international system of coordinates is used.
The international coordinate system is
Due to national security requirements, the use of geographic information in China is limited. In order to access it, one must receive special permission from the Surveying and Mapping Administrative Department under the State Council.
Despite the secrecy of GCJ-02 encryption, there are several open source projects, which convert the coordinates of GCJ-02 to the WGS-84 system. We used one of these in our application.
Difference between Apple Maps and Google Maps
It is worth paying attention to
If one of your potential software users is in China, it is worth using Amap instead of Google Maps and implementing coordinate decryption (sources of implementation and the description are given at the end of the article) to achieve maximum accuracy.
Google Maps
Apple Maps
Java source code has been taken from
class WGStoGCJConverter {
final static double pi = 3.14159265358979324;
//
// Krasovsky 1940
//
// a = 6378245.0, 1/f = 298.3
// b = a * (1 - f)
// ee = (a^2 - b^2) / a^2;
final static double a = 6378245.0;
final static double ee = 0.00669342162296594323;
// World Geodetic System ==> Mars Geodetic System
public static Coordinates transform(double wgLat, double wgLon) {
if (outOfChina(wgLat, wgLon)) {
return new Coordinates(wgLat, wgLon);
}
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);
return new Coordinates(wgLat + dLat, wgLon + dLon);
}
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;
}
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;
}
public static class Coordinates {
private double latitude;
private double longitude;
public Coordinates(double latitude, double longitude){
this.latitude = latitude;
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
}
}