一:在進行地圖開發過程當中,咱們通常能接觸到如下三種類型的地圖座標系:算法
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)加密
二:爲何會發生偏移?spa
1.因爲座標系之間不兼容,如在百度地圖上定位的經緯度拿到高德地圖上直接描點就確定會發生偏移;只考慮國內的狀況,高德地圖和Google地圖是能夠不通過轉換也可以準確顯示的(在國內用的都是GCJ-02座標系);下面是收錄了網上的WGS-84,GCJ-02,百度座標系(bd-09)之間的相互轉換的方法,經測試,是轉換後相對準確可用的:.net
工具類:code
package com.topinfo.gps; /** * 火星座標系 (GCJ-02) 與百度座標系 (BD-09) 的互轉 * */ public class GPSUtil { public static double pi = 3.1415926535897932384626; public static double x_pi = 3.14159265358979324 * 3000.0 / 180.0; public static double a = 6378245.0; public static double ee = 0.00669342162296594323; 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 double[] transform(double lat,double lon){ if (outOfChina (lat, lon)) { return new double[] { lat, lon }; } double dLat = transformLat (lon - 105.0, lat - 35.0); double dLon = transformLon (lon - 105.0, lat - 35.0); double radLat = lat / 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); double mgLat = lat + dLat; double mgLon = lon + dLon; return new double[] { mgLat, mgLon }; } 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; } /** * 84 to 火星座標系 (GCJ-02) World Geodetic System ==> Mars Geodetic System * * @param lat * @param lon * @return */ public static double[] gps84_To_Gcj02(double lat,double lon){ if (outOfChina (lat, lon)) { return new double[] { lat, lon }; } double dLat = transformLat (lon - 105.0, lat - 35.0); double dLon = transformLon (lon - 105.0, lat - 35.0); double radLat = lat / 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); double mgLat = lat + dLat; double mgLon = lon + dLon; return new double[] { mgLat, mgLon }; } /** * * 火星座標系 (GCJ-02) to 84 * * @param lon * @param lat * @return * */ public static double[] gcj02_To_Gps84(double lat,double lon){ double[] gps = transform (lat, lon); double lontitude = lon * 2 - gps[1]; double latitude = lat * 2 - gps[0]; return new double[] { latitude, lontitude }; } /** * 火星座標系 (GCJ-02) 與百度座標系 (BD-09) 的轉換算法 將 GCJ-02 座標轉換成 BD-09 座標 * * @param lat * @param lon */ public static double[] gcj02_To_Bd09(double lat,double lon){ double x = lon, y = lat; double z = Math.sqrt (x * x + y * y) + 0.00002 * Math.sin (y * x_pi); double theta = Math.atan2 (y, x) + 0.000003 * Math.cos (x * x_pi); double tempLon = z * Math.cos (theta) + 0.0065; double tempLat = z * Math.sin (theta) + 0.006; double[] gps = { tempLat, tempLon }; return gps; } /** * * 火星座標系 (GCJ-02) 與百度座標系 (BD-09) 的轉換算法 * * 將 BD-09 座標轉換成GCJ-02 座標 * * @param * bd_lat * @param bd_lon * @return */ public static double[] bd09_To_Gcj02(double lat,double lon){ double x = lon - 0.0065, y = lat - 0.006; double z = Math.sqrt (x * x + y * y) - 0.00002 * Math.sin (y * x_pi); double theta = Math.atan2 (y, x) - 0.000003 * Math.cos (x * x_pi); double tempLon = z * Math.cos (theta); double tempLat = z * Math.sin (theta); double[] gps = { tempLat, tempLon }; return gps; } /**將gps84轉爲bd09 * @param lat * @param lon * @return */ public static double[] gps84_To_bd09(double lat,double lon){ double[] gcj02 = gps84_To_Gcj02 (lat, lon); double[] bd09 = gcj02_To_Bd09 (gcj02[0], gcj02[1]); return bd09; } public static double[] bd09_To_gps84(double lat,double lon){ double[] gcj02 = bd09_To_Gcj02 (lat, lon); double[] gps84 = gcj02_To_Gps84 (gcj02[0], gcj02[1]); // 保留小數點後六位 gps84[0] = retain6 (gps84[0]); gps84[1] = retain6 (gps84[1]); return gps84; } /**保留小數點後六位 * @param num * @return */ private static double retain6(double num){ String result = String.format ("%.6f", num); return Double.valueOf (result); } }
測試類:orm
package com.topinfo.gps; public class Test2 { /** //GPS座標 116.32715863448607 39.990912172420714 //百度 116.33993794567915 39.99790821949972 */ public static void main(String[] args){ double[] gps = GPSUtil.gps84_To_bd09 (39.990912172420714, 116.32715863448607); System.out.println (gps[0]); System.out.println (gps[1]); } }
輸出:
39.997903976430734
116.33993249456921blog
通過比對:
39.997903976430734
39.99790821949972ip
116.33993249456921
116.33993794567915
而後在百度官網API測試;也幾乎是重疊的,若是:
工具類我是在 https://blog.csdn.net/a135703... 找到的。