一、地球座標系:是國際上通用的地理座標系wgs84,也就是咱們常說的經度緯度多少多少。好比08年汶川大地震報的經緯度就是基於這個座標系。而咱們常見的一些設備好比gps也是以這個座標系爲參考的。java
二、火星座標系:主要是由於國家安全的緣由爲了保護一些比較敏感的座標位置,在大天朝全部獲取地圖數據的第一個關卡就是國家測繪局,在他們出產的全部地圖在wgs84的基礎上進行一次加密,也就是所謂的按照必定的座標偏移算法到另一個座標系gcj-02,這個座標系是特有的且是變化的,你們習慣性的把他稱爲火星座標系。正是由於火星座標系的存在咱們直接拿gps採集的數據在地圖上顯示始終都有誤差,緣由就是由於兩個座標系都不同形成的。算法
三、百度座標系:百度座標在火星座標系gcj-02基礎上,進行了BD-09二次加密措施,更加保護了我的隱私。百度對外接口的座標系bd-09並非GPS採集的真實經緯度,須要經過座標轉換接口進行轉換。數組
package com.cdthgk.utils; import java.util.List; import com.cdthgk.utils.vo.ZuoBiao; /** * <p> * MyGPSUtil類主要用於-GPS相關數據處理. * <ul> * 經緯度座標系 * <li>WGS84座標系:即地球座標系,是爲GPS全球定位系統使用而創建的座標系統,國際上通用的座標系。如Google Earth(不含中國)</li> * <li>GCJ02座標系:又稱火星座標系,中國國家測繪局制訂的地理信息系統的座標系統,WGS84座標系經加密(加入隨機的誤差)後的座標系。如Gogole中國、搜搜、阿里雲、高德</li> * <li>BD09座標系:即百度座標系,在GCJ02座標系再次加密後的座標系。如百度</li> * <li>CGCS2000座標系:國家大地座標系,是我國當前最新的國家大地座標系,以前有北京5四、西安80,同WGS84的原點、尺度、定向及定向演變的定義都是相同的,參考橢球也很是相近,僅扁率f有微小差別。如天地圖</li> * <li>國內其餘座標系:應國家要求均是在GCJ02座標系上加密後的座標系。如搜狗、圖吧</li> * </ul> * </p> * <p> * 創建時間 2016-11-21 - 下午5:59:47 * </p> * <p> * copyright cdthgk 2010-2018, all rights reserved. * </p> * @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; /** * <p> * getMiles方法主要用於-從一系列座標軌跡中計算行駛距離. * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:00:16 * </p> * @param zbList 座標集合(至少兩個座標,且爲有效座標點) * @return double 單位 KM */ public static double getMiles(List<ZuoBiao> 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; } /** * <p> * distance方法主要用於-計算兩座標點間的距離. * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:35:16 * </p> * @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; } /** * <p> * gcj02_bd09方法主要用於-GCJ02座標轉換爲百度09座標. * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:06:44 * </p> * @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; } /** * <p> * bd09_gcj02方法主要用於-百度09座標轉轉換爲GCJ02座標. * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:19:02 * </p> * @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; } /** * <p> * bd09_wgs84方法主要用於-BD09座標轉爲WGS84(地球座標系). * <br>轉換過程:bd09->gcj02->wgs84. * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:23:15 * </p> * @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]); } /** * <p> * wgs84_bd09方法主要用於-wgs84地球座標換轉爲百度09座標. * <br>轉換過程:wgs84->gcj02->bd09. * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:29:08 * </p> * @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]); } /** * <p> * wgs84_gcj02方法主要用於-wgs84地球座標轉換爲gcj02. * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:29:45 * </p> * @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; } /** * <p> * gcj02_wgs84_1方法主要用於-gcj02座標轉爲地球座標wgs84(粗放). * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:30:20 * </p> * @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; } /** * <p> * gcj02_wgs84_2方法主要用於-gcj02座標轉爲地球座標wgs84(精確). * </p> * <p> * 城邑耕夫 2016-11-21 - 下午6:30:51 * </p> * @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; } /** * <p> * transform方法主要用於-wgs84與gcj02的座標轉換. * </p> * <p> * 山河戀夢 2016-11-21 - 下午8:06:56 * </p> * @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); } }