tft每日頭條

 > 圖文

 > 導航坐标系與大地坐标系轉化

導航坐标系與大地坐标系轉化

圖文 更新时间:2024-11-28 18:40:26

導航坐标系與大地坐标系轉化?經常有客戶反饋這樣的問題,為什麼接收到GPS設備(手機定位)點疊加到地圖裡會有很大的偏移呢?這個問題本身不複雜,但是對于非gis專業的客戶來說,可能就有點暈了其實産生偏移,無非就是定位點基于的坐标系與底圖的坐标系不一緻導緻簡單介紹下互聯網地圖所采用的坐标系(僅讨論地理坐标系,也就是常說的經緯度坐标系)目前常用的地理坐标系主要有國際标準坐标系WGS-84,火星坐标系GCJ-02,百度坐标系BD-09,下面我們就來說一說關于導航坐标系與大地坐标系轉化?我們一起去了解并探讨一下這個問題吧!

導航坐标系與大地坐标系轉化(互聯網地圖坐标系簡介及轉換)1

導航坐标系與大地坐标系轉化

經常有客戶反饋這樣的問題,為什麼接收到GPS設備(手機定位)點疊加到地圖裡會有很大的偏移呢?這個問題本身不複雜,但是對于非gis專業的客戶來說,可能就有點暈了。其實産生偏移,無非就是定位點基于的坐标系與底圖的坐标系不一緻導緻。簡單介紹下互聯網地圖所采用的坐标系(僅讨論地理坐标系,也就是常說的經緯度坐标系)。目前常用的地理坐标系主要有國際标準坐标系WGS-84,火星坐标系GCJ-02,百度坐标系BD-09。

WGS-84坐标系
  • 為一種國際标準的大地坐标線,是目前Gps全球衛星定位系統使用廣泛的坐标系。
  • 國際地圖提供商使用的坐标系,如open street map。
  • 天地圖的在線地圖是WGS-84坐标系,Google Earth采用的也是WGS-84坐标系。
GCJ-02坐标系
  • 火星坐标系GCJ-02也叫國家測繪局坐标系,國家規定國内出版的各種地圖系統(包括電子形式),必須至少采用GCJ-02對地理位置進行首次加密。
  • 國行移動設備中定位獲取的坐标數據使用的是GCJ-02坐标系。
  • 超圖雲在線地圖,谷歌國内在線地圖,高德地圖,騰訊地圖采用的都是GCJ-02坐标系。
BD-09坐标系
  • 百度地圖标準的坐标系,其實是百度地圖在火星坐标系上進行了二次加密。
  • 百度地圖針對海外地區提供的WGS-84坐标系。
GPS定位點坐标
  • 原生ios或android庫獲取的定位點坐标為WGS-84。
  • 百度移動sdk獲取的定位點坐标可以是BD-09或GCJ-02,默認BD-09。
  • 高德移動sdk,騰訊移動sdk等獲取的定位點坐标為GCJ-02。
  • 現在我們基本搞清楚了為什麼會産生偏移,要解決偏移,隻需要對坐标點進行坐标系轉換。舉例:我用SuperMap iMobile for Android組件産品開發了一個地圖app,其底圖的坐标系是WGS-84,而定位點的獲取采用的是高德地圖sdk,要保證定位點能在底圖上正常顯示出來,那麼隻需對定位點進行GCJ-02到WGS-84坐标系的轉換。坐标轉換,有很多在線服務,例如超圖公網服務的坐标轉換,提供了這三種常用坐标系之間的相互轉換。有了在線服務坐标轉換,那麼定位點就可以完美的在移動端或前端地圖上疊加顯示了。
離線坐标系轉換
  • 對于Gis地圖軟件開發,經常會接觸到除了點之外的矢量線和矢量面等數據,這些數據在與底圖疊加時也需要坐标系轉換,但在線服務無法轉換線,面。這時我們可以離線轉換,自己擴展轉換算法,因為線,面本身也是由點構造的,故将線面的點取到後進行坐标系轉換,然後将由結果點構造為線,面。附上離線轉換代碼:

public class CoordinateConvertTool {public static double pi = 3.1415926535897932384626;public static double a = 6378140.0;//1975年國際橢球體長半軸public static double ee = 0.0033528131778969143;//1975年國際橢球體扁率//百度坐标系轉換有0.001級别的誤差,若對精度要求高,可采用百度官方接口//gps實體類可自行構造,其屬性字段為經緯度。public static Gps GPS84ToBD09(double lon, double lat) {if (outOfChina(lon, lat)) {return null;}double dLat = transformLat(lon - 105.0, lat - 35.0);double dLon = transformLon(lon - 105.0, lat - 35.0);double radLat = lat / 180.0 * Math.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) * Math.PI);dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);double mgLon = lon dLon;double mgLat = lat dLat;double z = Math.sqrt(mgLon * mgLon mgLat * mgLat) 0.00002 * Math.sin(mgLat * Math.PI);double theta = Math.atan2(mgLat, mgLon) 0.000003 * Math.cos(mgLon * Math.PI);double longitude = z * Math.cos(theta) 0.0065;double latitude = z * Math.sin(theta) 0.006;return new Gps(longitude, latitude);}public static Gps GPS84ToGCJ02(double lon, double lat) {if (outOfChina(lon, lat)) {return null;}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 Gps(mgLon, mgLat);}public static Gps GCJ02ToGPS84(double lon, double lat) {Gps gps = transform(lon, lat);double lontitude = lon * 2 - gps.getLongitude();double latitude = lat * 2 - gps.getLatitude();return new Gps(lontitude, latitude);}public static Gps GCJ02ToBD09(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);}public static Gps BD09ToGCJ02(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);}public static Gps BD09ToGPS84(double bd_lon, double bd_lat) {Gps gcj02 = BD09ToGCJ02(bd_lon, bd_lat);Gps map84 = GCJ02ToGPS84(gcj02.getLongitude(), gcj02.getLatitude());return map84;}private static boolean outOfChina(double lon, double lat) {if (lon < 72.004 || lon > 137.8347)return true;return lat < 0.8293 || lat > 55.8271;}private static Gps transform(double lon, double lat) {if (outOfChina(lon, lat)) {return new Gps(lon, lat);}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 Gps(mgLon, mgLat);}private 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;}private 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;}}

由于偏移不是線性的,所以該離線轉換代碼不能保證百分百的精确度。經測試,與百度坐标系之間的轉換有誤差。影響誤差的因素很多,比如選取的橢球體,轉換算法等,精确度不在本文讨論範圍。如需高精度轉換,請使用百度地圖官方轉換接口。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved