一。在进行地图开发过程中,我们一般能接触到以下三种类型的地图坐标系:
1.WGS-84原始坐标系,一般用国际GPS纪录仪记录下来的经纬度,通过GPS定位拿到的原始经纬度,Google和高德地图定位的的经纬度(国外)都是基于WGS-84坐标系的;但是在国内是不允许直接用WGS84坐标系标注的,必须经过加密后才能使用;
2.GCJ-02坐标系,又名“火星坐标系”,是我国国测局独创的坐标体系,由WGS-84加密而成,在国内,必须至少使用GCJ-02坐标系,或者使用在GCJ-02加密后再进行加密的坐标系,如百度坐标系。高德和Google在国内都是使用GCJ-02坐标系,可以说,GCJ-02是国内最广泛使用的坐标系;
3.百度坐标系:bd-09,百度坐标系是在GCJ-02坐标系的基础上再次加密偏移后形成的坐标系,只适用于百度地图。(目前百度API提供了从其它坐标系转换为百度坐标系的API,但却没有从百度坐标系转为其他坐标系的API)
二。为什么会发生偏移?
1.由于坐标系之间不兼容,如在百度地图上定位的经纬度拿到高德地图上直接描点就肯定会发生偏移;只考虑国内的情况,高德地图和Google地图是可以不经过转换也能够准确显示的(在国内用的都是GCJ-02坐标系);下面是收录了网上的WGS-84,GCJ-02,百度坐标系(bd-09)之间的相互转换的方法,经测试,是转换后相对准确可用的:
作者:青檬可乐_
链接:http://08643.cn/p/d3dd4149bb0b
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
var?GPS?=?{??
????PI:?3.14159265358979324,??
????x_pi:?3.14159265358979324?*?3000.0?/?180.0,??
????delta:function?(lat,?lon)? {??
????//?Krasovsky?1940??
????//?a?=?6378245.0,?1/f?=?298.3??
????//?b?=?a?*?(1?-?f)??
????//?ee?=?(a^2?-?b^2)?/?a^2;??
var?a?=?6378245.0;?//??a:?卫星椭球坐标投影到平面地图坐标系的投影因子。??
var?ee?=?0.00669342162296594323;?//??ee:?椭球的偏心率。??
var?dLat?=?this.transformLat(lon?-?105.0,?lat?-?35.0);??
var?dLon?=?this.transformLon(lon?-?105.0,?lat?-?35.0);??
var?radLat?=?lat?/?180.0?*?this.PI;??
var?magic?=?Math.sin(radLat);??
? ? ? magic?=?1?-?ee?*?magic?*?magic;??
var?sqrtMagic?=?Math.sqrt(magic);??
dLat?=?(dLat?*?180.0)?/?((a?*?(1?-?ee))?/?(magic?*?sqrtMagic)?*this.PI);??
dLon?=?(dLon?*?180.0)?/?(a?/?sqrtMagic?*?Math.cos(radLat)?*this.PI);??
return?{?'lat':?dLat,?'lon':?dLon?};??
?},??
//WGS-84?to?GCJ-02??
gcj_encrypt:function?(wgsLat,?wgsLon)? ?{??
if?(this.outOfChina(wgsLat,?wgsLon))??
return?{?'lat':?wgsLat,?'lon':?wgsLon?};??
var?d?=?this.delta(wgsLat,?wgsLon);??
return?{?'lat':?wgsLat?+?d.lat,?'lon':?wgsLon?+?d.lon?};??
?},??
//GCJ-02?to?WGS-84??
gcj_decrypt:function?(gcjLat,?gcjLon)? {??
if?(this.outOfChina(gcjLat,?gcjLon))??
return?{?'lat':?gcjLat,?'lon':?gcjLon?};??
var?d?=?this.delta(gcjLat,?gcjLon);??
return?{?'lat':?gcjLat?-?d.lat,?'lon':?gcjLon?-?d.lon?};??
},??
//GCJ-02?to?WGS-84?exactly??
gcj_decrypt_exact:function?(gcjLat,?gcjLon)? {??
var?initDelta?=?0.01;??
var?threshold?=?0.000000001;??
var?dLat?=?initDelta,?dLon?=?initDelta;??
var?mLat?=?gcjLat?-?dLat,?mLon?=?gcjLon?-?dLon;??
var?pLat?=?gcjLat?+?dLat,?pLon?=?gcjLon?+?dLon;??
var?wgsLat,?wgsLon,?i?=?0;??
while?(1)? {??
? ? wgsLat?=?(mLat?+?pLat)?/?2;??
? ? wgsLon?=?(mLon?+?pLon)?/?2;??
var?tmp?=?this.gcj_encrypt(wgsLat,?wgsLon)??
????????????dLat?=?tmp.lat?-?gcjLat;??
????????????dLon?=?tmp.lon?-?gcjLon;??
if?((Math.abs(dLat)?<?threshold)?&&?(Math.abs(dLon)?<?threshold))??
break;??
if?(dLat?>?0)?pLat?=?wgsLat;?else?mLat?=?wgsLat;??
if?(dLon?>?0)?pLon?=?wgsLon;?else?mLon?=?wgsLon;??
if?(++i?>?10000)?break;??
}??
//console.log(i);??
return?{?'lat':?wgsLat,?'lon':?wgsLon?};??
},??
//GCJ-02?to?BD-09??
bd_encrypt:function?(gcjLat,?gcjLon)? {??
var?x?=?gcjLon,?y?=?gcjLat;??
var?z?=?Math.sqrt(x?*?x?+?y?*?y)?+?0.00002?*?Math.sin(y?*?this.x_pi);??
var?theta?=?Math.atan2(y,?x)?+?0.000003?*?Math.cos(x?*?this.x_pi);??
????????bdLon?=?z?*?Math.cos(theta)?+?0.0065;??
????????bdLat?=?z?*?Math.sin(theta)?+?0.006;??
return?{?'lat':?bdLat,?'lon':?bdLon?};??
????},??
//BD-09?to?GCJ-02??
bd_decrypt:function?(bdLat,?bdLon){??
var?x?=?bdLon?-?0.0065,?y?=?bdLat?-?0.006;??
var?z?=?Math.sqrt(x?*?x?+?y?*?y)?-?0.00002?*?Math.sin(y?*?this.x_pi);??
var?theta?=?Math.atan2(y,?x)?-?0.000003?*?Math.cos(x?*?this.x_pi);??
var?gcjLon?=?z?*?Math.cos(theta);??
var?gcjLat?=?z?*?Math.sin(theta);??
return?{?'lat':?gcjLat,?'lon':?gcjLon?};??
?},??
//WGS-84?to?Web?mercator??
//mercatorLat?->?y?mercatorLon?->?x??
mercator_encrypt:function?(wgsLat,?wgsLon)? ?{??
var?x?=?wgsLon?*?20037508.34?/?180.;??
var?y?=?Math.log(Math.tan((90.?+?wgsLat)?*?this.PI?/?360.))?/?(this.PI?/?180.);??
????????y?=?y?*?20037508.34?/?180.;??
return?{?'lat':?y,?'lon':?x?};??
/*
????????if?((Math.abs(wgsLon)?>?180?||?Math.abs(wgsLat)?>?90))
????????????return?null;
????????var?x?=?6378137.0?*?wgsLon?*?0.017453292519943295;
????????var?a?=?wgsLat?*?0.017453292519943295;
????????var?y?=?3189068.5?*?Math.log((1.0?+?Math.sin(a))?/?(1.0?-?Math.sin(a)));
????????return?{'lat'?:?y,?'lon'?:?x};
????????//*/??
????},??
//?Web?mercator?to?WGS-84??
//?mercatorLat?->?y?mercatorLon?->?x??
mercator_decrypt:function?(mercatorLat,?mercatorLon)??
????{??
var?x?=?mercatorLon?/?20037508.34?*?180.;??
var?y?=?mercatorLat?/?20037508.34?*?180.;??
y?=?180?/this.PI?*?(2?*?Math.atan(Math.exp(y?*?this.PI?/?180.))?-?this.PI?/?2);??
return?{?'lat':?y,?'lon':?x?};??
/*
????????if?(Math.abs(mercatorLon)?<?180?&&?Math.abs(mercatorLat)?<?90)
????????????return?null;
????????if?((Math.abs(mercatorLon)?>?20037508.3427892)?||?(Math.abs(mercatorLat)?>?20037508.3427892))
????????????return?null;
????????var?a?=?mercatorLon?/?6378137.0?*?57.295779513082323;
????????var?x?=?a?-?(Math.floor(((a?+?180.0)?/?360.0))?*?360.0);
????????var?y?=?(1.5707963267948966?-?(2.0?*?Math.atan(Math.exp((-1.0?*?mercatorLat)?/?6378137.0))))?*?57.295779513082323;
????????return?{'lat'?:?y,?'lon'?:?x};
????????//*/??
????},??
//?two?point's?distance??
distance:function?(latA,?lonA,?latB,?lonB)??
????{??
var?earthR?=?6371000.;??
var?x?=?Math.cos(latA?*?this.PI?/?180.)?*?Math.cos(latB?*?this.PI?/?180.)?*?Math.cos((lonA?-?lonB)?*?this.PI?/?180);??
var?y?=?Math.sin(latA?*?this.PI?/?180.)?*?Math.sin(latB?*?this.PI?/?180.);??
var?s?=?x?+?y;??
if?(s?>?1)?s?=?1;??
if?(s?<?-1)?s?=?-1;??
var?alpha?=?Math.acos(s);??
var?distance?=?alpha?*?earthR;??
return?distance;??
????},??
outOfChina:function?(lat,?lon)??
????{??
if?(lon?<?72.004?||?lon?>?137.8347)??
return?true;??
if?(lat?<?0.8293?||?lat?>?55.8271)??
return?true;??
return?false;??
????},??
transformLat:function?(x,?y)??
????{??
var?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?*this.PI)?+?20.0?*?Math.sin(2.0?*?x?*?this.PI))?*?2.0?/?3.0;??
ret?+=?(20.0?*?Math.sin(y?*this.PI)?+?40.0?*?Math.sin(y?/?3.0?*?this.PI))?*?2.0?/?3.0;??
ret?+=?(160.0?*?Math.sin(y?/?12.0?*this.PI)?+?320?*?Math.sin(y?*?this.PI?/?30.0))?*?2.0?/?3.0;??
return?ret;??
????},??
transformLon:function?(x,?y)??
????{??
var?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?*this.PI)?+?20.0?*?Math.sin(2.0?*?x?*?this.PI))?*?2.0?/?3.0;??
ret?+=?(20.0?*?Math.sin(x?*this.PI)?+?40.0?*?Math.sin(x?/?3.0?*?this.PI))?*?2.0?/?3.0;??
ret?+=?(150.0?*?Math.sin(x?/?12.0?*this.PI)?+?300.0?*?Math.sin(x?/?30.0?*?this.PI))?*?2.0?/?3.0;??
return?ret;??
????}??
};??