目錄
GPS定位解決偏差
開篇
實踐
1、解決思路以及步驟
2、實踐出真理!
3、上坐標系之間的代碼,
希望大家:點贊,留言,關注咯~ 😘😘😘😘
嘮家常
今日推薦都在文章中了
GPS定位解決偏差
開篇
大家都知道啊,小黑是靠Unity吃飯的,所以覺得Unity就是萬能的,小黑需要什么他就會提供什么,事實證明,Unity確實是很強大,但是他還沒有強大到可以知道小黑心里想什么,所以就遇到問了唄,
事情是這樣的,小黑從前段時間開始,加入了一個專案組,開始是幫著解決一些原生互動啊,或者是另外一些簡單的東西吧,但隨著時間的推進,小黑稀里糊涂的就成了該專案組成員,徹底進入開發了狀態了!!!!開發就開發吧,有一個GPS定位功能之前是另一個專案組同事負責,他告訴我們說是Unity的GPS有問題,和實際位置有6公里的偏差,這這這小黑能忍?好歹一年前也是做過GPS相關功能的,于是小黑拿著1年前的知識和他開始了Battle!!!并且叫囂著:(下方),現在想來,真的想打死我自己,太丟人了😂😂😂😂
出自小黑的嘴:我之前做過Demo,GPS是絕對不可能有這么大偏差的,最多800米的偏差,并且還是看什么地圖的坐標拾取器!!高德、騰訊、谷歌很厲害,偏差在400米左右,百度最垃圾,偏差在800米左右!!
實踐
1、解決思路以及步驟
那廢話也說了好多了, 就開始學習如何解決吧,
- 首先:我們要知道什么是GPS,
GPS從入門到放棄(一) --- GPS基礎原理
GPS從入門到放棄(二) --- GPS時間
GPS從入門到放棄(三) --- GPS坐標系 主要看這個★★★★★
- 第二:知道坐標系后,我們要弄明白為什么會有偏差,
關于GPS坐標系和地圖定位偏差
借用文章中的話:
1):獲取GPS位置后,為什么在地圖上定位不準?
答 :中國地圖采用的坐標系和GPS坐標不是同一個坐標系,所以采用GPS坐標在地圖上定位不準,
2):國外GPS位置和國內GPS位置有差別嗎?
答 :GPS是美國的導航系統,全球通用,手機內置的芯片都是GPS芯片,沒有差別,不同的地方是地圖有著不同的GPS坐標系,
- 最后:我們明白偏差原因后,就需要解決,那代碼在哪呢,正下方咯,
地圖坐標系相互轉換(WGS-84、GCJ-02、BD-09)
2、實踐出真理!
正如第三步驟的文章中所說:我們開發人員一般會用到三種坐標系,
- WGS-84原始坐標系
一般用國際GPS紀錄儀記錄下來的經緯度,通過GPS定位拿到的原始經緯度,Google和高德地圖定位的的經緯度(國外)都是基于WGS-84坐標系的,但是在國內是不允許直接用WGS84坐標系標注的,必須經過加密后才能使用,GCJ-02坐標系,又名"火星坐標系"
是我國(中國)國測局獨創的坐標體系,由WGS-84加密而成,在國內,必須至少使用GCJ-02坐標系,或者使用在GCJ-02加密后再進行加密的坐標系,如百度坐標系,高德和Google在國內都是使用GCJ-02坐標系,可以說,GCJ-02是國內最廣泛使用的坐標系,BD-09,又名"百度坐標系"
百度坐標系是在GCJ-02坐標系的基礎上再次加密偏移后形成的坐標系,只適用于百度地圖,(目前百度API提供了從其它坐標系轉換為百度坐標系的API,但卻沒有從百度坐標系轉為其他坐標系的API),
小黑在不同地圖的坐標拾取器上邊反復測驗后,得到以下結果:
1、Unity通過API (Input.location) 獲取到的正是WGS-84原始坐標系,
2、高德、騰訊、谷歌(中國) 用的都是GCJ - 02坐標系,
3、百度自然用的是自家坐標系咯(百度坐標系),
3、上坐標系之間的代碼,
using System;
public class GPSUtil
{
/// <summary>
/// Π
/// 圓周率
/// </summary>
private const double PI = 3.14159265358979324;
private const double X_PI = 3.14159265358979324 * 3000.0 / 180.0;
private const double A = 6378245.0;
private const double EE = 0.00669342162296594323;
private const double LON_BOUNDARY_MIN = 72.004;
private const double LAT_BOUNDARY_MIN = 0.8293;
private const double LON_BOUNDARY_MAX = 137.8347;
private const double LAT_BOUNDARY_MAX = 55.8271;
/// <summary>
/// 是否中國境內坐標
/// </summary>
/// <param name="gpsLat"></param>
/// <param name="gpsLng"></param>
/// <returns></returns>
private static bool OutOfChina(double gpsLat, double gpsLng)
{
if (gpsLng < LON_BOUNDARY_MIN || gpsLng > LON_BOUNDARY_MAX)
{
return true;
}
if (gpsLat < LAT_BOUNDARY_MIN || gpsLat > LAT_BOUNDARY_MAX)
{
return true;
}
return false;
}
#region WGS坐標系與GCJ02坐標系互轉
/// <summary>
/// WGS84坐標系轉GCJ02坐標系
/// </summary>
/// <param name="wgsLat">WGS坐標,緯度</param>
/// <param name="wgsLng">WGS坐標,經度</param>
/// <param name="gcjLat">GCJ02坐標,緯度</param>
/// <param name="gcjLng">GCJ02坐標,經度</param>
public static void WGS84_to_GCJ02(double wgsLat, double wgsLng, out double gcjLat, out double gcjLng)
{
if (OutOfChina(wgsLat, wgsLng))
{
gcjLat = wgsLat;
gcjLng = wgsLng;
}
else
{
double dLat = TransformLat(wgsLng - 105.0, wgsLat - 35.0);
double dLon = TransformLon(wgsLng - 105.0, wgsLat - 35.0);
double radLat = wgsLat / 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);
gcjLat = wgsLat + dLat;
gcjLng = wgsLng + dLon;
}
}
public static void GCJ02_to_WGS84(double gcjLat, double gcjLng, out double wgsLat, out double wgsLng)
{
WGS84_to_GCJ02(gcjLat, gcjLng, out wgsLat, out wgsLng);
wgsLng = gcjLng * 2 - wgsLng;
wgsLat = gcjLat * 2 - wgsLat;
}
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;
}
#endregion
#region 火星坐標系 (GCJ-02) 與百度坐標系 (BD-09) 的互轉
public static void GCJ02_to_Bd09(double gcjLat, double gcjLng, out double bdLat, out double bdLng)
{
double z = Math.Sqrt(gcjLng * gcjLng + gcjLat * gcjLat) + 0.00002 * Math.Sin(gcjLat * PI);
double theta = Math.Atan2(gcjLat, gcjLng) + 0.000003 * Math.Cos(gcjLng * PI);
bdLng = z * Math.Cos(theta) + 0.0065;
bdLat = z * Math.Sin(theta) + 0.006;
}
public static void BD09_to_GCJ02(double bdLat, double bdLng, out double gcjLat, out double gcjLng)
{
double x = bdLng - 0.0065, y = bdLat - 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);
gcjLng = z * Math.Cos(theta);
gcjLat = z * Math.Sin(theta);
}
#endregion
}
至此,圓滿結束,
好了,知識講了,參考鏈接也上了,代碼更是放出來了,這次相信大家和小黑一樣,會GPS的使用了吧!
希望大家:點贊,留言,關注咯~ 😘😘😘😘
嘮家常
- 小黑的今日分享結束啦,小伙伴們你們get到了么,你們有沒有更好的辦法呢,可以評論區留言分享,也可以加小黑的QQ:841298494,大家一起進步,
今日推薦都在文章中了
- 客官,看完get之后記得點贊喲!
- 小伙伴你還想要別的知識?好的呀,分享給你們😄
- 小黑的雜貨鋪,想要什么都有,客官不進來喝杯茶么?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/310664.html
標籤:其他
