WGS84、GCJ-02、BD-09、圖吧座標簡介及座標轉換實現(java版)

1.定位系統及如何定位

        現在全球有四個衛星定位系統:美國的全球定位系統GPS(Global Positioning System),俄羅斯的格洛納斯GIONASS, 歐盟的伽利略系統,我國的北斗。

       每個系統都有幾個部分:星載部分、控制部分、以及用戶部分。每個衛星在運行中,發送電磁波信息、包含時間、位置等等,用戶部分根據定位裝置接收信號,然後進行方程解算,由於要更多的解因子,所以GPS系統下,一般三顆衛星信號鎖定後才能計算三差解,也就是粗略定位結果了。

2.定位座標系

       地理座標系(GeographicCoordinate System):是使用三維球面來定義地球表面位置,以實現通過經緯度對地球表面點位引用的座標系。一個地理座標系包括角度測量單位、本初子午線和參考橢球體三部分。在球面系統中,水平線是等緯度線或緯線。垂直線是等經度線或經線。是以經緯度來表示地面點的一種球面座標系,用度做單位;

       投影座標系(ProjectedCoordinate System):投影座標系在二維平面中進行定義。與地理座標系不同,在二維空間範圍內,投影座標系的長度、角度和麪積恆定。投影座標系始終基於地理座標系,而後者則是基於球體或旋轉橢球體的。在投影座標系中,通過格網上的 x,y 座標來標識位置,其原點位於格網中心。每個位置均具有兩個值,這兩個值是相對於該中心位置的座標。一個指定其水平位置,另一個指定其垂直位置。這兩個值稱爲 x 座標和 y 座標。採用此標記法,原點座標是 x = 0 和 y = 0,常用m、km做單位;

       地圖投影(Map Projection):無論將地球視爲球體還是旋轉橢球體,都必須變換其三維曲面以創建平面地圖圖幅(即,按照一定的數學法則將地球橢球面上點的經維度座標轉換到平面上的直角座標表示的一個過程,將地理座標系通過地圖投影就可以得到對應的投影座標系)。此數學變換通常稱作地圖投影。理解地圖投影如何改變空間屬性的一種簡便方法就是觀察光穿過地球投射到表面(稱爲投影曲面)上。想像一下,地球表面是透明的,其上繪有經緯網。用一張紙包裹地球。位於地心處的光會將經緯網投影到一張紙上。現在,可以展開這張紙並將其鋪平。紙張上的經緯網形狀與地球上的形狀不同。地圖投影使經緯網發生了變形。地圖投影使用數學公式將地球上的球面座標與平面座標關聯起來。常見的投影方法有:等角投影、等積投影、等距投影以及真方向投影。

 

3.不同地圖服務商的座標系

       出於國家安全考慮不同的國家在規定地圖服務提供商在提供地圖服務的時候需要將地圖數據進行加密。現在比較流行的座標系有WGS84、GCJ-02、BD-09,且各個座標之間存在偏差。

        WGS84:World Geodetic System 1984,是爲GPS全球定位系統使用而建立的座標系統。通過遍佈世界的衛星觀測站觀測到的座標建立,其初次WGS84的精度爲1-2m,在1994年1月2號,通過10個觀測站在GPS測量方法上改正,得到了WGS84(G730),G表示由GPS測量得到,730表示爲GPS時間第730個周。1996年,National Imagery and Mapping Agency (NIMA) 爲美國國防部 (U.S.Departemt of Defense, DoD)做了一個新的座標系統。這樣實現了新的WGS版本:WGS(G873)。其因爲加入了USNO站和北京站的改正,其東部方向加入了31-39cm 的改正。所有的其他座標都有在1分米之內的修正。第三次精化:WGS84(G1150),於2002年1月20日啓用。

        GCJ-02(官方稱地形圖非線性保密處理算法,俗稱火星座標系、國測局座標):是一種基於WGS-84制定的大地測量系統,由中國國家測繪地理信息局制定,國家科學技術進步獎一等獎得主李成名開發。此座標系所採用的混淆算法會在經緯度中加入看似隨機的偏移,號稱可以促進國家安全。使用GCJ-02記錄下的地點在GCJ-02的地圖中會顯示在正確的位置,然而換成WGS-84的地圖或地點記錄就可能造成100-700米不等的偏移。

        BD-09:是百度地圖使用的地理座標系,其在GCJ-02上多增加了一次變換,號稱“有助保護用戶隱私”。

        圖吧座標:圖吧是百度座標乘以10000的結果。

        搜狗座標:在GCJ-02上進行了加密

4.不同地圖服務提供商的座標系

地圖服務

座標系

座標系名稱

百度地圖

百度座標

BD09

騰訊搜搜地圖

火星座標

GCJ02

搜狐搜狗地圖

搜狗座標*

 

阿里雲地圖

火星座標

GCJ02

圖吧MapBar地圖

圖吧座標

圖吧

高德MapABC地圖

火星座標

GCJ02

靈圖51ditu地圖

火星座標

GCJ02

Google中國地圖

火星座標

GCJ02

Google(除中國)

大地座標

WGS84

GPS芯片或者北斗芯片

大地座標

WGS84

5.不同座標之間轉換java實現

具體實現請參考:https://github.com/pengcao/dc.toolkit.loc.jar/blob/master/src/main/java/dc/toolkit/lbs/util/CoorUtil.java

package dc.toolkit.lbs.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import dc.toolkit.lbs.base.entity.Point;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class CoorUtil {
	// radius --- 地球赤道半徑
	// x_pi   --- 百度與gcj座標系之間進行轉換的參數
	// a      --- 克拉索夫斯基橢球參數長半軸  
	// ee     --- 克拉索夫斯基橢球參數第一偏心率平方  (a^2 - b^2) / a^2
	private static double radius = 6378.137, x_pi = Math.PI * 3000.0 / 180.0,
			a = 6378245.0, ee = 0.00669342162296594323;
	
	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 * Math.PI) + 20.0 * Math.sin(2.0 * x
				* Math.PI)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0
				* Math.PI)) * 2.0 / 3.0;
		ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y
				* Math.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 * Math.PI) + 20.0 * Math.sin(2.0 * x
				* Math.PI)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0
				* Math.PI)) * 2.0 / 3.0;
		ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x
				/ 30.0 * Math.PI)) * 2.0 / 3.0;
		return ret;
	}



	public static JSONObject delta(double lat, double lng) {
		JSONObject jsonObject = new JSONObject();
		double dLat = transformLat(lng - 105.0, lat - 35.0);
		double dLng = transformLon(lng - 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);
		dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);
		jsonObject.put("lat", dLat);
		jsonObject.put("lng", dLng);
		return jsonObject;
	}	
	
	/**
	 * 
	 * Description: 將google(除中國)座標轉換爲高德座標
	 * Creation time: 2016年8月2日 上午12:08:18
	 *
	 * @param wgsLat
	 * @param wgsLng
	 * @return
	 */
	public static JSONObject wgs2gcj(double wgsLat, double wgsLng) {
		JSONObject jsonObject = new JSONObject();
		JSONObject d = delta(wgsLat, wgsLng);
		jsonObject.put("lat", wgsLat + d.getDouble("lat"));
		jsonObject.put("lng", wgsLng + d.getDouble("lng"));
		return jsonObject;
	}

	/**
	 * 
	 * Description: 將高德座標轉換爲google(除中國)座標
	 * Creation time: 2016年8月2日 上午12:09:11
	 *
	 * @param gcjLat
	 * @param gcjLng
	 * @return
	 */
	public static JSONObject gcj2wgs(double gcjLat, double gcjLng) {
		JSONObject jsonObject = new JSONObject();
		JSONObject d = delta(gcjLat, gcjLng);

		jsonObject.put("lat", gcjLat - d.getDouble("lat"));
		jsonObject.put("lng", gcjLng - d.getDouble("lng"));
		return jsonObject;
	}

	/**
	 * 
	 * Description: 將高德座標轉換爲百度座標
	 * Creation time: 2016年8月2日 上午12:10:18
	 *
	 * @param lat
	 * @param lng
	 * @return
	 */
	public static JSONObject gcj2bd(double lat, double lng) {
		JSONObject jsonObject = new JSONObject();
		double z = Math.sqrt(lng * lng + lat * lat) + 0.00002
				* Math.sin(lat * x_pi);
		double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_pi);
		double bd_lon = z * Math.cos(theta) + 0.0065;
		double bd_lat = z * Math.sin(theta) + 0.006;
		jsonObject.put("lat", bd_lat);
		jsonObject.put("lng", bd_lon);
		return jsonObject;
	}

	/**
	 * 
	 * Description: 將百度座標轉換爲高德座標
	 * Creation time: 2016年8月2日 上午12:10:40
	 *
	 * @param bd_lat
	 * @param bd_lon
	 * @return
	 */
	public static JSONObject bd2gcj(double bd_lat, double bd_lon) {
		JSONObject jsonObject = new JSONObject();
		double x = bd_lon - 0.0065, y = bd_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 gg_lon = z * Math.cos(theta);
		double gg_lat = z * Math.sin(theta);

		jsonObject.put("lat", gg_lat);
		jsonObject.put("lng", gg_lon);
		return jsonObject;
	}

	// 圖吧座標轉換成wgs座標
	public static JSONObject mapBar2WGS84(double sbar_lng, double sbar_lat) {
		JSONObject jsonObject = new JSONObject();
		
		float bar_lng = ((float)sbar_lng) * 100000 % 36000000;
		float bar_lat = (float)sbar_lat * 100000 % 36000000;
		int lng1 = (int) (-(((Math.cos(bar_lat / 100000)) * (bar_lng / 18000)) + ((Math.sin(bar_lng / 100000)) * (bar_lat / 9000))) + bar_lng);
		int lat1 = (int) (-(((Math.sin(bar_lat / 100000)) * (bar_lng / 18000)) + ((Math.cos(bar_lng / 100000)) * (bar_lat / 9000))) + bar_lat);
		int lng2 = (int) (-(((Math.cos(lat1 / 100000)) * (lng1 / 18000)) + ((Math.sin(lng1 / 100000)) * (lat1 / 9000))) + bar_lng + ((bar_lng > 0) ? 1: -1));
		int lat2 = (int) (-(((Math.sin(lat1 / 100000)) * (lng1 / 18000)) + ((Math.cos(lng1 / 100000)) * (lat1 / 9000))) + bar_lat + ((bar_lat > 0) ? 1: -1));
		double endLat=lat2/100000.0;
		double endLng=lng2/100000.0;
		jsonObject.put("lat", endLat);
		jsonObject.put("lng", endLng);
		return jsonObject;
	}

	// 圖吧座標轉換成gcj座標
	public static JSONObject mapBar2gcj(double bar_lng, double bar_lat) {
		JSONObject wgs = mapBar2WGS84(bar_lng, bar_lat);
		return wgs2gcj(wgs.getDouble("lat"), wgs.getDouble("lng"));
	}

	// 圖吧座標轉換成gcj座標
	public static JSONObject mapBar2bd(double bar_lng, double bar_lat) {
		JSONObject wgs = mapBar2WGS84(bar_lng, bar_lat);
		return wgs2bd(wgs.getDouble("lat"), wgs.getDouble("lng"));
	}
}

6.座標系座標轉換開源api

1.https://tool.lu/coordinate/

2.http://lbsyun.baidu.com/index.php?title=webapi/guide/changeposition

3.https://lbs.amap.com/api/webservice/guide/api/convert

7.參考

1.http://desktop.arcgis.com/zh-cn/arcmap/10.3/guide-books/map-projections/about-map-projections.htm

2.https://www.biaodianfu.com/coordinate-system.html

3.https://www.zhihu.com/question/277520588

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章