经常有客户反馈这样的问题,为什么接收到GPS设备(手机定位)点叠加到地图里会有很大的偏移呢?这个问题本身不复杂,但是对于非gis专业的客户来说,可能就有点晕了其实产生偏移,无非就是定位点基于的坐标系与底图的坐标系不一致导致简单介绍下互联网地图所采用的坐标系(仅讨论地理坐标系,也就是常说的经纬度坐标系)目前常用的地理坐标系主要有国际标准坐标系WGS-84,火星坐标系GCJ-02,百度坐标系BD-09,下面我们就来说一说关于导航坐标系与大地坐标系转化?我们一起去了解并探讨一下这个问题吧!

导航坐标系与大地坐标系转化(互联网地图坐标系简介及转换)

导航坐标系与大地坐标系转化

经常有客户反馈这样的问题,为什么接收到GPS设备(手机定位)点叠加到地图里会有很大的偏移呢?这个问题本身不复杂,但是对于非gis专业的客户来说,可能就有点晕了。其实产生偏移,无非就是定位点基于的坐标系与底图的坐标系不一致导致。简单介绍下互联网地图所采用的坐标系(仅讨论地理坐标系,也就是常说的经纬度坐标系)。目前常用的地理坐标系主要有国际标准坐标系WGS-84,火星坐标系GCJ-02,百度坐标系BD-09。

WGS-84坐标系GCJ-02坐标系BD-09坐标系GPS定位点坐标离线坐标系转换

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;}}

由于偏移不是线性的,所以该离线转换代码不能保证百分百的精确度。经测试,与百度坐标系之间的转换有误差。影响误差的因素很多,比如选取的椭球体,转换算法等,精确度不在本文讨论范围。如需高精度转换,请使用百度地图官方转换接口。

,