火星座標系 (GCJ-02) 與百度座標系 (BD-09ll) 簡介及轉換演算法
首先向轉換演算法的作者 @coolypf 致敬!轉換演算法文章:http://blog.csdn.net/coolypf/article/details/8569813
1、美國GPS使用的是WGS84座標系統,以經緯度的形式來表示地球平面上的某一個位置。但在我國,出於國家安全考慮,國內所有導航電子地圖必須使用國家測繪局制定的加密座標系統,即將一個真實的經緯度座標(WGS84座標系)通過中國國家測繪局制訂的加密演算法加密成一個不正確的經緯度座標(GCJ-02座標系),我們在業內將前者稱之為地球座標,後者稱之為火星座標。
2、百度官方對百度座標為何有偏移的解釋:
國際經緯度座標標準為WGS-84,國內必須至少使用國測局制定的GCJ-02,對地理位置進行首次加密。百度座標在此基礎上,進行了BD-09ll
3、國內各地圖座標系統比較:
地圖廠商 |
座標系 |
百度地圖 |
百度座標 |
騰訊地圖 |
火星座標 |
高德地圖 |
火星座標 |
谷歌地圖(中國) |
火星座標 |
搜狐搜狗地圖 |
搜狗座標 |
4、 座標系轉換方案1:網上的火星座標系 (GCJ-02) 與百度座標系 (BD-09ll) 的轉換演算法:
C++:
#include <math.h> 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); }
Java:
public class GCJ02_BD09 { public static double pi = 3.141592653589793 * 3000.0 / 180.0; public static void main(String[] args) { // GCJ02 ——> BD09 gcj02_To_Bd09(116.422954, 40.010749).print(); // BD09 ——> GCJ02 bd09_To_Gcj02(121.481085, 31.236173).print(); } /** * 火星座標系 (GCJ-02) 與百度座標系 (BD-09) 的轉換演算法 將 GCJ-02 座標轉換成 BD-09 座標 * * @param gg_lat * @param gg_lon * @return */ public static Gps 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 Gps(bd_lon, bd_lat); } /** * 火星座標系 (GCJ-02) 與百度座標系 (BD-09) 的轉換演算法 將 BD-09 座標轉換成GCJ-02 座標 * * @param bd_lon * @param bd_lat * @return */ public static Gps 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 Gps(gg_lon, gg_lat); } //Gps類 public static class Gps { public double lat; public double lon; public Gps(double lon, double lat) { this.lat = lat; this.lon = lon; } public void print() { System.out.println(this.lon + "," + this.lat); } } }
程式碼效果測試:
北京地區:GCJ02 ——>BD09ll
北京地區:BD-09ll ——> GCJ02
結論:北京地區座標轉換誤差基本在10米左右
東北地區(漠河縣):GCJ02 ——> BD09ll
東北地區(漠河縣):BD-09ll ——> GCJ02
結論:漠河地區座標轉換誤差在10米左右
西北地區(新疆烏魯木齊)GCJ02 ——> BD09ll
西北地區(新疆烏魯木齊)BD-09ll ——> GCJ02
結論:烏魯木齊地區座標轉換誤差10米以內
中部地區(陝西西安)GCJ02 ——> BD09ll
中部地區(陝西西安)BD-09ll ——> GCJ02
結論:西安地區座標轉換誤差10米以內
東部地區(上海)GCJ02 ——> BD09ll
東部地區(上海)BD-09ll ——> GCJ02
結論:上海地區座標轉換誤差10米以內
南方地區(海南三亞)GCJ02 ——> BD09ll
南方地區(海南三亞)BD-09ll ——> GCJ02
結論:海南三亞地區座標轉換誤差10米以內
5、 座標系轉換方案2:百度座標轉換API(只能進行GCJ-02 ——> BD-09ll)
百度地圖座標轉換API是一套以HTTP形式提供的座標轉換介面,用於將常用的非百度座標(目前支援GPS裝置獲取的座標、google地圖座標、soso地圖座標、amap地圖座標、mapbar地圖座標)轉換成百度地圖中使用的座標。
該方法侷限性:只能進行GCJ-02 ——> BD-09ll的轉換,無法將百度座標(BD-09ll)轉為火星座標(GCJ-02),且呼叫一次最多隻能轉換100個座標,無法支援大規模的轉換需求。
總結:最簡單的方式:統一客戶端、服務端的SDK,避免座標轉換;
較簡單的方式:使用本文最上面的演算法,進行火星——百度座標轉換;
較麻煩的方式:呼叫百度的API,使用Http形式轉換,具體放大見上方連結中的說明。