GPS各坐标系间的坐标值转换

为什么80%的码农都做不了架构师?>>>   hot3.png

1、地球坐标系:是国际上通用的地理坐标系wgs84,也就是我们常说的经度纬度多少多少。比如08年汶川大地震报的经纬度就是基于这个坐标系。而我们常见的一些设备比如gps也是以这个坐标系为参考的。

2、火星坐标系:主要是因为国家安全的原因为了保护一些比较敏感的坐标位置,在大天朝所有获取地图数据的第一个关卡就是国家测绘局,在他们出产的所有地图在wgs84的基础上进行一次加密,也就是所谓的按照一定的坐标偏移算法到另外一个坐标系gcj-02,这个坐标系是特有的且是变化的,大家习惯性的把他称为火星坐标系。正是因为火星坐标系的存在我们直接拿gps采集的数据在地图上显示始终都有偏差,原因就是因为两个坐标系都不一样造成的。

3、百度坐标系:百度坐标在火星坐标系gcj-02基础上,进行了BD-09二次加密措施,更加保护了个人隐私。百度对外接口的坐标系bd-09并不是GPS采集的真实经纬度,需要通过坐标转换接口进行转换。

package com.cdthgk.utils;

import java.util.List;

import com.cdthgk.utils.vo.ZuoBiao;

/**
 * 

* MyGPSUtil類主要用於-GPS相关数据处理. *

    * 经纬度坐标系 *
  • WGS84坐标系:即地球坐标系,是为GPS全球定位系统使用而建立的坐标系统,国际上通用的坐标系。如Google Earth(不含中国)
  • *
  • GCJ02坐标系:又称火星坐标系,中国国家测绘局制订的地理信息系统的坐标系统,WGS84坐标系经加密(加入随机的偏差)后的坐标系。如Gogole中国、搜搜、阿里云、高德
  • *
  • BD09坐标系:即百度坐标系,在GCJ02坐标系再次加密后的坐标系。如百度
  • *
  • CGCS2000坐标系:国家大地坐标系,是我国当前最新的国家大地坐标系,之前有北京54、西安80,同WGS84的原点、尺度、定向及定向演变的定义都是相同的,参考椭球也非常相近,仅扁率f有微小差异。如天地图
  • *
  • 国内其他坐标系:应国家要求均是在GCJ02坐标系上加密后的坐标系。如搜狗、图吧
  • *
*

*

* 創建時間 2016-11-21 - 下午5:59:47 *

*

* copyright cdthgk 2010-2018, all rights reserved. *

* @author 城邑耕夫 * @since 1.0 * @version 1.0 */ public class MyGPSUtil { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MyGPSUtil.class); /**地球半径6378.137,单位为千米 */ private static double EARTH_RADIUS = 6378.137; /**圆周率PI */ private static double PI = Math.PI; /**卫星椭球坐标投影到平面地图坐标系的投影因子*/ private static double AXIS = 6378245.0; /**椭球的偏心率(a^2 - b^2) / a^2 */ private static double OFFSET = 0.00669342162296594323; /**圆周率转换量*/ private static double X_PI = PI * 3000.0 / 180.0; /** *

* getMiles方法主要用于-从一系列坐标轨迹中计算行驶距离. *

*

* 城邑耕夫 2016-11-21 - 下午6:00:16 *

* @param zbList 坐标集合(至少两个坐标,且为有效坐标点) * @return double 单位 KM */ public static double getMiles(List zbList) { double miles = 0; if (zbList != null && zbList.size() > 1) { log.debug("计算开始,坐标量:" + zbList.size()); ZuoBiao zb1 = zbList.get(0); for (int i = 1, len = zbList.size(); i < len; i++) { ZuoBiao zb2 = zbList.get(i); miles += getDistance1(zb1.getLat(), zb1.getLng(), zb2.getLat(), zb2.getLng()); zb1 = zb2; } log.debug("计算完毕"); } return miles; } /** * 计算两坐标点间的距离 * @param lat1 坐标1维度 * @param lng1 坐标1经度 * @param lat2 坐标2维度 * @param lng2 坐标2经度 * @return double 单位 KM */ public static double getDistance1(double lat1, double lng1, double lat2, double lng2) { double radLat1 = rad(lat1); double radLat2 = rad(lat2); double a = radLat1 - radLat2; double b = rad(lng1) - rad(lng2); double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2))); s = s * EARTH_RADIUS; // s = Math.round(s * 10000) / 10000; // s = Math.round(s * 10000d) / 10000d; return s; } /** *

* distance方法主要用于-计算两坐标点间的距离. *

*

* 城邑耕夫 2016-11-21 - 下午6:35:16 *

* @param latA A点维度 * @param logA A点经度 * @param latB B点维度 * @param logB B点经度 * @return double 单位?? */ public static double getDistance2(double latA, double logA, double latB, double logB) { int earthR = 6371000; double x = Math.cos(latA * Math.PI / 180) * Math.cos(latB * Math.PI / 180) * Math.cos((logA - logB) * Math.PI / 180); double y = Math.sin(latA * Math.PI / 180) * Math.sin(latB * Math.PI / 180); double s = x + y; if (s > 1) { s = 1; } if (s < -1) { s = -1; } double alpha = Math.acos(s); double distance = alpha * earthR; return distance; } private static double rad(double d) { return d * PI / 180.0; } /** *

* gcj02_bd09方法主要用于-GCJ02坐标转换为百度09坐标. *

*

* 城邑耕夫 2016-11-21 - 下午6:06:44 *

* @param lat gcj02维度 * @param lng gcj02经度 * @return latlng[] 经纬数组(bd09) */ public static double[] gcj02_bd09(double lat, double lng) { double x = lng; double y = lat; double[] latlng = new double[2]; 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); latlng[0] = z * Math.sin(theta) + 0.006; latlng[1] = z * Math.cos(theta) + 0.0065; return latlng; } /** *

* bd09_gcj02方法主要用于-百度09坐标转转换为GCJ02坐标. *

*

* 城邑耕夫 2016-11-21 - 下午6:19:02 *

* @param lat bd09维度 * @param lng bd09经度 * @return latlng[] 维经数组(gcj02) */ public static double[] bd09_gcj02(double lat, double lng) { double x = lng - 0.0065; double y = lat - 0.006; double[] latlng = new double[2]; 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); latlng[0] = z * Math.sin(theta); latlng[1] = z * Math.cos(theta); return latlng; } /** *

* bd09_wgs84方法主要用于-BD09坐标转为WGS84(地球坐标系). *
转换过程:bd09->gcj02->wgs84. *

*

* 城邑耕夫 2016-11-21 - 下午6:23:15 *

* @param lat 维度 (bd09) * @param lng 经度(bd09) * @return latlng[] 维经数组(wgs84) */ public static double[] bd09_wgs84(double lat, double lng) { double[] latlng = bd09_gcj02(lat, lng); return gcj02_wgs84_1(latlng[0], latlng[1]); } /** *

* wgs84_bd09方法主要用于-wgs84地球坐标换转为百度09坐标. *
转换过程:wgs84->gcj02->bd09. *

*

* 城邑耕夫 2016-11-21 - 下午6:29:08 *

* @param lat 维度(wgs84) * @param lng 经度(wgs84) * @return latlng[] 维经数组(bd09) */ public static double[] wgs84_bd09(double lat, double lng) { double[] latlon = wgs84_gcj02(lat, lng); return gcj02_bd09(latlon[0], latlon[1]); } /** *

* wgs84_gcj02方法主要用于-wgs84地球坐标转换为gcj02. *

*

* 城邑耕夫 2016-11-21 - 下午6:29:45 *

* @param lat 维度(wgs84) * @param lng 经度(wgs84) * @return latlng[] 维经数组(gcj-02) */ public static double[] wgs84_gcj02(double lat, double lng) { double[] latlon = new double[2]; if (outOfChina(lat, lng)) { latlon[0] = lat; latlon[1] = lng; return latlon; } double[] deltaD = transform(lat, lng); latlon[0] = lat + deltaD[0]; latlon[1] = lng + deltaD[1]; return latlon; } /** *

* gcj02_wgs84_1方法主要用于-gcj02坐标转为地球坐标wgs84(粗放). *

*

* 城邑耕夫 2016-11-21 - 下午6:30:20 *

* @param lat 维度(gcj02) * @param lng 经度(gcj02) * @return latlng[] 维经数组(wgs84) */ public static double[] gcj02_wgs84_1(double lat, double lng) { double[] latlon = new double[2]; if (outOfChina(lat, lng)) { latlon[0] = lat; latlon[1] = lng; return latlon; } double[] deltaD = transform(lat, lng); latlon[0] = lat - deltaD[0]; latlon[1] = lng - deltaD[1]; return latlon; } /** *

* gcj02_wgs84_2方法主要用于-gcj02坐标转为地球坐标wgs84(精确). *

*

* 城邑耕夫 2016-11-21 - 下午6:30:51 *

* @param lat 维度(gcj02) * @param lng 经度(gcj02) * @return latlng[] 维经数组(wgs84) */ public static double[] gcj02_wgs84_2(double lat, double lng) { double initDelta = 0.01; double threshold = 0.000000001; double dLat = initDelta, dLon = initDelta; double mLat = lat - dLat, mLon = lng - dLon; double pLat = lat + dLat, pLon = lng + dLon; double wgsLat, wgsLon, i = 0; while (true) { wgsLat = (mLat + pLat) / 2; wgsLon = (mLon + pLon) / 2; double[] tmp = wgs84_gcj02(wgsLat, wgsLon); dLat = tmp[0] - lat; dLon = tmp[1] - lng; if ((Math.abs(dLat) < threshold) && (Math.abs(dLon) < threshold)) { break; } if (dLat > 0) { pLat = wgsLat; } else { mLat = wgsLat; } if (dLon > 0) { pLon = wgsLon; } else { mLon = wgsLon; } if (++i > 10000) { break; } } double[] latlon = new double[2]; latlon[0] = wgsLat; latlon[1] = wgsLon; return latlon; } /** *

* transform方法主要用于-wgs84与gcj02的坐标转换. *

*

* 山河戀夢 2016-11-21 - 下午8:06:56 *

* @param lat 维度 * @param lng 经度 * @return double[] 两坐标系间的偏移 */ public static double[] transform(double lat, double lng) { double[] latlng = new double[2]; double dLat = transformLat(lng - 105.0, lat - 35.0); double dLon = transformLng(lng - 105.0, lat - 35.0); double radLat = lat / 180.0 * PI; double magic = Math.sin(radLat); magic = 1 - OFFSET * magic * magic; double sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((AXIS * (1 - OFFSET)) / (magic * sqrtMagic) * PI); dLon = (dLon * 180.0) / (AXIS / sqrtMagic * Math.cos(radLat) * PI); latlng[0] = dLat; latlng[1] = dLon; return latlng; } public 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; } public static double transformLng(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; } public static boolean outOfChina(double lat, double lon) { if (lon < 72.004 || lon > 137.8347) { return true; } if (lat < 0.8293 || lat > 55.8271) { return true; } return false; } public static void main(String[] args) { double dis = getDistance1(31.868278, 106.757043, 31.868245, 106.757106); System.out.println(dis); } }

 

转载于:https://my.oschina.net/chwencong/blog/791689

你可能感兴趣的:(GPS各坐标系间的坐标值转换)