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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)