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

 

 

 

 

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