GCJ-02火星坐标系
2015年7月7日
1 目标:将准确的坐标信息加入随机误差,从而隐藏真实坐标。
参考:http://kongxz.com/2013/10/wgs-cgj/
2 原理:利用各种数学计算方法,将坐标进行映射。
3 方法:GCJ-02火星坐标系。
国家测绘局发布的GCJ-02加密算法,加密真实坐标,称为火星坐标系。
规定所有发布的地图系统,必须至少使用GCJ-02进行一次加密。
国内偏移量并不一致,一般在几百米范围。
谷歌地图的ditu域名进行了一次加密,其它(如卫星图,map域名)是真实数据。
国内地图厂商一般会进入二次加密(如百度),偏移量在100m左右(少量测试)。
高德使用GCJ-02(参见:http://lbs.amap.com/home/faq/%E5%9D%90%E6%A0%87%E4%BD%93%E7%B3%BB/)。
4 方法:火星坐标与真实坐标转换,GCJ-02与WGS84互转
所有的地图厂商都提供将真实坐标转换为其使用的地图坐标系统的方法,但没有反向转换功能。
4.1 通用方法:eviltransform(推荐)
来源:https://github.com/googollee/eviltransform
开源项目,提供GCJ-02与WGS84的相互转换功能。提供C,JavaScript,Java,go,php等各种语言版本。
(看名字就知道了,这转换真是挺……)
4.1.1真实坐标转换为火星坐标:WGS84-》GCJ-02
eviltransform.wgs2gcj(wgsLat,wgsLng) // javascript
4.1.2火星坐标转换为真实坐标:GCJ-02-》WGS84
快速转换:精度1m~2m。
eviltransform.gcj2wgs(gcjLat,gcjLng) // javascript
准确转换:精度<0.5m。
eviltransform.gcj2wgs_exact(gcjLat,gcjLng) // javascript
4.1.3转换源代码:c
//transform.h
#ifndefTRANSFORM_HEADER
#define TRANSFORM_HEADER
voidwgs2gcj(double wgsLat, double wgsLng, double *gcjLat, double *gcjLng);
voidgcj2wgs(double gcjLat, double gcjLng, double *wgsLat, double *wgsLnt);
voidgcj2wgs_exact(double gcjLat, double gcjLng, double *wgsLat, double *wgsLnt);
doubledistance(double latA, double lngA, double latB, double lngB);
#endif
//transform.c
#include<math.h>
#include<stdlib.h>
#include"transform.h"
intoutOfChina(double lat, double lng) {
if (lng < 72.004 || lng > 137.8347){
return 1;
}
if (lat < 0.8293 || lat > 55.8271) {
return 1;
}
return 0;
}
voidtransform(double x, double y, double *lat, double *lng) {
double xy = x * y;
double absX = sqrt(fabs(x));
double d = (20.0*sin(6.0*x*M_PI) +20.0*sin(2.0*x*M_PI)) * 2.0 / 3.0;
*lat = -100.0 + 2.0*x + 3.0*y + 0.2*y*y +0.1*xy + 0.2*absX;
*lng = 300.0 + x + 2.0*y + 0.1*x*x +0.1*xy + 0.1*absX;
*lat += d;
*lng += d;
*lat += (20.0*sin(y*M_PI) +40.0*sin(y/3.0*M_PI)) * 2.0 / 3.0;
*lng += (20.0*sin(x*M_PI) +40.0*sin(x/3.0*M_PI)) * 2.0 / 3.0;
*lat += (160.0*sin(y/12.0*M_PI) +320*sin(y/30.0*M_PI)) * 2.0 / 3.0;
*lng += (150.0*sin(x/12.0*M_PI) +300.0*sin(x/30.0*M_PI)) * 2.0 / 3.0;
}
void delta(doublelat, double lng, double *dLat, double *dLng) {
if ((dLat == NULL) || (dLng == NULL)) {
return;
}
const double a = 6378245.0;
const double ee = 0.00669342162296594323;
transform(lng-105.0, lat-35.0, dLat,dLng);
double radLat = lat / 180.0 * M_PI;
double magic = sin(radLat);
magic = 1 - ee*magic*magic;
double sqrtMagic = sqrt(magic);
*dLat = (*dLat * 180.0) / ((a * (1 - ee))/ (magic * sqrtMagic) * M_PI);
*dLng = (*dLng * 180.0) / (a / sqrtMagic *cos(radLat) * M_PI);
}
voidwgs2gcj(double wgsLat, double wgsLng, double *gcjLat, double *gcjLng) {
if ((gcjLat == NULL) || (gcjLng == NULL)){
return;
}
if (outOfChina(wgsLat, wgsLng)) {
*gcjLat = wgsLat;
*gcjLng = wgsLng;
return;
}
double dLat, dLng;
delta(wgsLat, wgsLng, &dLat,&dLng);
*gcjLat = wgsLat + dLat;
*gcjLng = wgsLng + dLng;
}
voidgcj2wgs(double gcjLat, double gcjLng, double *wgsLat, double *wgsLng) {
if ((wgsLat == NULL) || (wgsLng == NULL)){
return;
}
if (outOfChina(gcjLat, gcjLng)) {
*wgsLat = gcjLat;
*wgsLng = gcjLng;
return;
}
double dLat, dLng;
delta(gcjLat, gcjLng, &dLat,&dLng);
*wgsLat = gcjLat - dLat;
*wgsLng = gcjLng - dLng;
}
voidgcj2wgs_exact(double gcjLat, double gcjLng, double *wgsLat, double *wgsLng) {
double dLat, dLng;
// n_iter=2: centimeter precision,n_iter=5: double precision
const int n_iter = 2;
int i;
if ((wgsLat == NULL) || (wgsLng == NULL)){
return;
}
*wgsLat = gcjLat;
*wgsLng = gcjLng;