不同地圖定位偏移以及坐標系轉換

眾所周知地球是一個不規(guī)則橢圓體,GPS中的坐標系定義由基準面地圖投影兩組參數(shù)確定,而基準面的定義則由特定橢球體及其對應的轉換參數(shù)確定。

基準面是利用特定橢球體對特定地區(qū)地球表面的逼近,因此每個國家或地區(qū)均有各自的基準面。

基準面是在橢球體基礎上建立的,橢球體可以對應多個基準面,而基準面只能對應一個橢球體。

意思就是無論是谷歌地圖、搜搜地圖還是高德地圖、百度地圖區(qū)別只是針對不同的大地地理坐標系標準制作的經緯度,不存在準不準的問題,大家都是準的只是參照物或者說是標準不一樣。

谷歌地圖采用的是WGS84地理坐標系(中國范圍除外),谷歌中國地圖和搜搜中國地圖采用的是GCJ02地理坐標系百度采用的是BD09坐標系,而設備一般包含GPS芯片或者北斗芯片獲取的經緯度為WGS84地理坐標系。

這樣就存在不同坐標系的坐標之間轉換的問題了,高德地圖和百度地圖的開發(fā)者開放平臺中都提供了坐標轉換的API。

有哪些不同的地圖坐標系?

在使用地圖組件開發(fā)過程中,我們一般能接觸到以下三種類型的地圖坐標系:

1.原始坐標系(WGS-84)

WGS-84原始坐標系,一般用國際GPS紀錄儀記錄下來的經緯度,通過GPS定位拿到的原始經緯度,Google和高德地圖定位的的經緯度(國外)都是基于WGS-84坐標系的;但是在國內是不允許直接用WGS84坐標系標注的,必須經過加密后才能使用;據(jù)說是為了保密。

GPS坐標形式如圖,度分秒形式的經緯度:

2.火星坐標系(GCJ-02)

GCJ-02坐標系,又名“火星坐標系”,是我國國測局獨創(chuàng)的坐標體系,由WGS-84加密而成,在國內,必須至少使用GCJ-02坐標系,或者使用在GCJ-02加密后再進行加密的坐標系,如百度坐標系。高德和Google在國內都是使用GCJ-02坐標系,GCJ-02也是國內最廣泛使用的坐標體系。

3.百度坐標系(bd-09)

百度坐標系是在GCJ-02坐標系的基礎上再次加密偏移后形成的坐標系,只適用于百度地圖。(目前百度API提供了從其它坐標系轉換為百度坐標系的API,但卻沒有從百度坐標系轉為其他坐標系的API)

為什么會發(fā)生偏移?

1.坐標系不兼容

由于坐標系之間不兼容,如在百度地圖上定位的經緯度拿到高德地圖上直接描點就肯定會發(fā)生偏移;只考慮國內的情況,高德地圖和Google地圖是可以不經過轉換也能夠準確顯示的(在國內用的都是GCJ-02坐標系);下面是收錄了網上的WGS-84,GCJ-02,百度坐標系(bd-09)之間的相互轉換的方法,經測試,是轉換后相對準確可用的:

2.國內外網速不同

在國內定位的經緯度,然后在國外網絡下顯示也會發(fā)生偏移(谷歌和高德會依據(jù)網絡的情況選擇使用WGS-84坐標還是GCJ-02坐標,百度地圖則一直使用bd-02坐標系)

3.定位方式

在iOS定位的經緯度是通過GPS獲取的,在android則可以通過網絡或GPS獲取經緯度。通過地圖SDK定位獲取的經緯度,地圖SDK會自動選擇加密的方式(如Google地圖會根據(jù)國內國外選擇不同的坐標系)然后再將點顯示在地圖上,這個時候是沒有偏移的;如果直接將經緯度在地圖上顯示,可能就會因為地域或網絡的問題導致使用的坐標系不同,進而發(fā)生來偏移。

有哪幾種坐標?

首先明白,所有坐標體系的原點,都是非洲。

1.經緯度

這個是球面坐標,對于北京來說,就是(116.38817139.935961)這樣的坐標。比如騰訊、高德、百度都是這樣的經緯度坐標。谷歌是經緯度順序寫反的經緯度坐標。

如果是度分秒坐標,需要進行轉換,才能得到這樣的經緯度坐標。詳見坐標轉換。

2.墨卡托坐標

平面坐標,相當于是直線距離,數(shù)字一般都比較大,像這樣的。

(215362.0002133333599526.00034912192)

墨卡托坐標,主要用于程序的后臺計算。直線距離嘛,加加減減幾乎計算方便。搜狗地圖API就是直接使用的墨卡托坐標。

不同地圖坐標怎么轉換?

在各種web端平臺,或者高德、騰訊、百度上取到的坐標,都不是GPS坐標,都是GCJ-02坐標,或者自己的偏移坐標系。

比如,你在谷歌地圖API,高德地圖API,騰訊地圖API上取到的,都是GCJ-02坐標,他們三家都是通用的,也適用于大部分地圖API產品,以及他們的地圖產品。

例外,百度API上取到的,是BD-09坐標,只適用于百度地圖相關產品。

例外,搜狗API上取到的,是搜狗坐標,只適用于搜狗地圖相關產品。

例外,谷歌地球,googleearth上取到的,是GPS坐標,而且是度分秒形式的經緯度坐標。在國內不允許使用。必須轉換為GCJ-02坐標。

一.經驗轉換

根據(jù)經驗得到的:

(1)百度地圖的差別是(0.01185,-0.00328)

如果百度地圖的經緯度是(x,y)實際的應該是(x,y)+(-0.01185,-0.00328)=(x-0.01185,y-0.00328)

 /**
     * @param $gg_lon 百度經度
     * @param $gg_lat 百度緯度
     * @return mixed
     *
     * GCJ-02(火星,高德) 坐標轉換成 BD-09(百度) 坐標
     */
    public function bd_encrypt($gg_lon, $gg_lat)

    {

        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;

        $x = $gg_lon;

        $y = $gg_lat;

        $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);

        $theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi);

        $data['bd_lon'] = $z * cos($theta) + 0.0065;

        $data['bd_lat'] = $z * sin($theta) + 0.006;

        return $data;

    }

(2)google Map的差別是(0.0143,-0.014)

如果用getscreen截圖,如果要截的范圍為(x,y),輸入getscreen的為(x-0.0143,y+0.014).

 /**
     * @param $bd_lon 百度經度
     * @param $bd_lat 百度緯度
     * @return mixed
     *
     * BD-09(百度) 坐標轉換成  GCJ-02(火星,高德) 坐標
     */
    public function bd_decrypt($bd_lon, $bd_lat)
    {

        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;

        $x = $bd_lon - 0.0065;

        $y = $bd_lat - 0.006;

        $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);

        $theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi);

        $data['gg_lon'] = $z * cos($theta);

        $data['gg_lat'] = $z * sin($theta);

        return $data;

    }
二.度分秒坐標轉換為經緯度

比如,在GPS記錄儀,或者googleearth上采集到的是39°31'20.51,那么應該這樣換算,31分就是31/60度,20.51秒就是20.51/3600度,結果就是39+ 31/60 + 20.51/3600 度。

三.GPS轉換為GCJ-02坐標

谷歌,高德,騰訊的地圖API官網上,都不直接提供這樣的坐標轉換。如果要得到GCJ-02坐標,最好在他們的地圖上直接取點,或者通過地址解析得到。(這個工具我后續(xù)會貼出來的。我就愛干這樣的事情,哈哈。)

不過,在網上搜到了這樣的接口,該接口的type=1就是GPS轉到GCJ-02的墨卡托坐標。請大家對接口保密,哈哈。詳見:

http://map.sogou.com/api/documentation/javascript/api2.5/interface_translate.html#late_intro

四.GCJ-02與BD-09之間互轉

國測局GCJ-02坐標體系(谷歌、高德、騰訊),與百度坐標BD-09體系的轉換

轉換算法如下:

#include   
const double x_pi = 3.14159265358979324 * 3000.0 / 180.0;  
void bd_encrypt(double gg_lat, double gg_lon, double &bd_lat, double &bd_lon)  
{  

?    double x = gg_lon, y = gg_lat;  
?    double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);  
?    double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);  
?    bd_lon = z * cos(theta) + 0.0065;  
?    bd_lat = z * sin(theta) + 0.006;  
}  


void bd_decrypt(double bd_lat, double bd_lon, double &gg_lat, double &gg_lon)  
{  

?    double x = bd_lon - 0.0065, y = bd_lat - 0.006;  
?    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);  
?    double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);  
?    gg_lon = z * cos(theta);  
?    gg_lat = z * sin(theta);  
}  

不過也有更簡單的算法,線性算法(lat和lng是經緯度,球面坐標):

To_B是轉到百度,To_G是轉到GCJ-02。

var TO_BLNG =function(lng){return lng+0.0065;};

var TO_BLAT =function(lat){return lat+0.0060;};

var TO_GLNG =function(lng){return lng-0.0065;};

var TO_GLAT =function(lat){return lat-0.0060;};
五.經緯緯度轉成墨卡托

在WebGIS的開發(fā)中經常用到的地圖投影為Web墨卡托和WGS84,Google地圖,bingmaps,百度地圖,mapabc,mapbar,以及ArcGISonline上的大部分地圖為Web墨卡托地圖,ArcGIS online上最開始發(fā)布的地圖投影為WGS84。
在開發(fā)過程中很多時候會遇到不同坐標系之間互轉的問題,特別是底圖使用Web墨卡托,定位(GPS,wifi等)信號坐標為WGS84坐標的時候,那么通用解決方案就是寫一個坐標參考系的轉換庫,類似于proj4,但一般情況下很少用到那么多的參考系之間的互轉,并且在客戶端實現(xiàn)或者調用proj4都是一件很困難或者麻煩的事情,大多數(shù)情況下我們實現(xiàn)Web墨卡托坐標與WGS84坐標互轉就可以了。

下面是使用objective-c實現(xiàn)的Web墨卡托坐標與WGS84坐標互轉程序,當然也可以使用其他語言來實現(xiàn),使用起來比較簡單和方便。

//經緯度轉墨卡托
-(CGPoint )lonLat2Mercator:(CGPoint ) lonLat
{
  CGPoint  mercator;
   double x =lonLat.x *20037508.34/180;
   double y =log(tan((90+lonLat.y)*M_PI/360))/(M_PI/180);
   y = y*20037508.34/180;
   mercator.x =x;
   mercator.y =y;
   returnmercator ;
}
//墨卡托轉經緯度
-(CGPoint )Mercator2lonLat:(CGPoint ) mercator
{
   CGPointlonLat;
   double x =mercator.x/20037508.34*180;
   double y =mercator.y/20037508.34*180;
   y=180/M_PI*(2*atan(exp(y*M_PI/180))-M_PI/2);
   lonLat.x =x;
   lonLat.y =y;
   returnlonLat;
}

坐標轉換之后為什么會出現(xiàn)偏移?

如果您的坐標在轉換之后,還有偏移,那么考慮以下幾個方面:

A.原始坐標系弄錯

比如以為自己是GPS坐標,但其實已經是GCJ-02坐標。
解決方案:請確保采集到的數(shù)據(jù)是哪個坐標體系,需要轉換到哪個坐標系,再進行坐標轉換。

B.原始坐標準確度不夠
解決方案:如果您是GPS坐標,請確保采集GPS數(shù)據(jù)時,搜到至少4顆以上的衛(wèi)星。并且GPS數(shù)據(jù)準不準,還取決于周圍建筑物的高度,越高越不準,因為有遮擋。
如果本來就是GCJ-02坐標,在不同地圖放大級別的時候,看到的地方可能不一樣。比如你在地圖級別4(國家)取到的坐標,放大到地圖12級(街道)時,坐標就偏了。請確保在地圖最大放大級別時,拾取坐標。

C.度分秒的概念混淆
比如,在googleearth上采集到的是39°31'20.51,那么應該這樣換算,31分就是31/60度,20.51秒就是20.51/3600度,結果就是39+ 31/60 + 20.51/3600 度。

D.經緯度順序寫反了
有些公司(比如高德,百度,騰訊)是先經度,再緯度,即Point(lng lat)。但谷歌坐標的順序恰好相反,是(latlng)。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內容