百度地图经纬度纠偏
我們把從GPS設備接收的經緯度坐標標記到電子地圖上時,會發現地圖上的位置和實際位置相差甚遠,除GPS設備本身加偏外,電子地圖上的坐標也不是真實的,要想正確顯示到地圖上,還必須將收到的加偏坐標(俗稱火星坐標)換算到地圖對應的坐標,也就是我們常說的糾偏。
1.使用控件
如果和谷歌地圖一樣,有一個控件,直接傳入GPS坐標得到地圖坐標,那就省事了,通過正常途徑獲取控件的話,但是不是任何人都可以獲取控件。因此,本方法基本放棄。
2.百度地圖接口
百度網站提供了接口,只要通過http傳入GPS坐標參數就可以獲得對應的地圖坐標,該方法優點是方便準確,不足也很明顯,受網速、百度服務器等影響,處理大量并發業務時力不從心。
API地址
http://api.map.baidu.com/ag/coord/convert?from=0&to=4&x=113.240324&y=23.817349
參數解釋
from=0:代表傳入的是真實經緯度
to=4:代表返回是百度糾偏后,能在百度地圖上正確顯示出該地址的經緯度
x:經度
y:緯度
返回數據
{"error":0,"x":"MTEzLjI1MjIyMjUxOTg1","y":"MjMuODIwNjM5MTEyNDgy"}
返回的數據經過Base64加密,在網上找個在線Base64解密的網站就可以了。
3.本地數據庫
所謂的加偏,就是將gps上傳的坐標加上一定的偏移量。這個偏移不是線性的,不同地區偏移不一樣,但同一地區偏移量卻差不多,因此,有人就使用了個暴力破解的方法,將全國按GPS坐標分成很多小塊,然后查出每個小塊的偏移量,并保存到數據庫里面,需要糾偏時,先根據GPS坐標取出對應區域的偏移量,反算出地圖坐標。
如何構建自己的百度地圖本地糾偏庫?
中國大陸(含海南島)的經緯度大概范圍在經度73.5~135度和緯度18~53.6之間,如果按1度一條記錄,那么記錄數為(53.6-18)*(135-73.5)=2189.4條,顯然,1度的跨度太大了,如果0.1度,則需要2189.4*100(10的平方)約22萬條記錄,如果是0.01度,則需要2189.4萬條,已經很龐大了,再精確到0.001,那么,就是21.894億條了,根據實測,這么高精度沒必要,精確到0.01度足矣,也就是說,中國大陸1/100度的偏移庫有2189.4萬條記錄,還是比較大的,我們的車輛并不是在中國大陸任何地方都可以開的,比如車輛是不會開到居民樓頂的,我們實際用到的并不多,你可以參照我的另外一篇博客(點擊打開鏈接)構建一個精簡的數據庫,這里,我們使用百度地圖接口,自己創建一個完整的偏移數據庫。結果如下(經緯度、偏移均使用百萬分之一度表示):
我們需要先看看上面的百度糾偏接口,需要注意的是,該接口每次返回的結果可能都不一樣,也就是我們永遠都是接近真實值,但永遠都無法得到真實值。
有了這個接口,我們可以通過二次循環,經度從73.5到135循環,每次增加0.01度,緯度亦然,這樣就可以自動生成自己的偏移庫了。
我們知道,整數的運輸速度遠遠快于浮點數,因此,我們參照部標GPS規定,用百萬分之一度來描述經緯度,也就是把經緯度都乘以一百萬保存到數據庫里面。顯然,數據庫表至少應該有經度(int)、緯度(int),經度偏移(smallint)、緯度偏移(smallint)幾列,由于網絡的不穩定性,并不能保證一次性每條都解析成功,因此,還需要增加一列,當解析失敗時,做個標記,以便下次重新解析。這里給出我用C#寫的調用百度接口進行解析的代碼供參考,參數均是百萬分之一度:
#region 查詢百度糾偏坐標
///<summary>
///計算百度地圖坐標
///</summary>
///<paramname="Lng">原始經度</param>
///<paramname="Lat">原始緯度</param>
///<returns>百度地圖糾偏后的坐標</returns>
public Point GetBaiduPosOff(intLng, int Lat)
{
Pointpos = new Point(0,0);
//還原到度供接口使用
doublelng = 0.000001 * Lng, lat = 0.000001 * Lat;
try
{
stringurl = string.Format("http://api.map.baidu.com/ag/coord/convert?from=0&to=4&x={0}&y={1}",
lng, lat);
HttpWebRequestrequest = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 5000;
HttpWebResponseresponse = (HttpWebResponse)request.GetResponse();
Streamstream = response.GetResponseStream();
byte[]bytes = new byte[1024];
intn = stream.Read(bytes, 0, 1024);
response.Close();
if(n < 2)
{
ShowLog(string.Format("返回長度不正確經度:{0},緯3度:{1}", lng, lat));
}
else
{
strings = System.Text.Encoding.UTF8.GetString(bytes).Substring(1,n - 2).Replace(""","");
foreach(string teamins.Split(','))
{
string[] infos = team.Split(':');
if (infos.Length < 2)
{
ShowLog(string.Format("格式不正確,經度:{0},緯度:{1}", lng, lat));
break;
}
string strValue = infos[1];
switch (infos[0])
{
case "error":
if (strValue !="0")
ShowLog(string.Format("返回了錯誤號,經度:{0},緯度:{1},錯誤號:{2}", lng, lat,strValue));
break;
case "x":
{
byte[] outputb =Convert.FromBase64String(strValue);
strValue = Encoding.Default.GetString(outputb);
pos.X = (int)(double.Parse(strValue)* 1000000);
}
break;
case"y":
{
byte[] outputb =Convert.FromBase64String(strValue);
strValue = Encoding.Default.GetString(outputb);
pos.Y = (int)(double.Parse(strValue) * 1000000);
}
break;
}
}
}
}
catch(Exception ee)
{
ShowLog(string.Format("錯誤,經度:{0},緯3度:{1},錯誤信息:{2}", lng, lat,ee.Message));
}
returnpos;
}
#endregion
View Code
傳入經緯度(百萬分之一度),得到一個Point數據結構,x代表糾偏后的經度(百萬分之一度),y代表緯度,如果x或y為0,表示解析失敗,需要記錄下來下次重新解析。用糾偏后的坐標減去原始坐標,就得到了偏移值,存到數據庫就可以了。
例如:
intnLng = 85000000, nLat = 28000000,nLngOffset=0,nLatOffset=0;
Pointpt = GetBaiduPosOff(nLng, nLat);
boolbSuccess = false;
if(pt.X > 0 && pt.Y > 0)
{
nLngOffset = pt.X - nLng;
nLatOffset = pt.Y - nLat;
bSuccess = true;
}
View Code
這樣,我們就可以把原始坐標、偏移值、是否成功存到數據庫了。
有了這個數據庫,使用相對比較簡單,首先將GPS坐標(百萬分之一度)轉換到0.01度的經度(GPS坐標/10000*10000),并從數據庫取得偏移值,然后將原始GPS和坐標偏移相加即可,參考代碼如下:
int nLng = 85123456,nLat = 28123456;
//從數據庫讀取偏移
Pointpt = GetDBOff(nLng / 10000 * 10000, nLat / 10000 * 10000);
//加上偏移
nLng += pt.X;
nLat += nLat;
View Code
應該說,整個原理非常簡單,真正的困難在于時間,實測了一下,一秒鐘大約能解析4~5條,兩千多萬條記錄大概需要兩個多月連續工作,恐怕大多數人都是等不及的,要解決也很簡單,多線程+多電腦操作,每個線程負責一段,我調用電腦資源比較方便,用了6臺服務器,每臺開兩個程序,一個星期不到全部解析完畢。如果有需要的朋友,我上傳到了CSDN下載中心了,具體鏈接等出來后,我在評論里給出,我自己使用的是sql server 2008 R2,考慮到很多人還是sql server 2005,故我備份為sql server2005的格式,如果你還在使用sql server 2000,那沒辦法了,只能找一臺2005或2008的數據庫還原,然后通過鏈接服務器插入到你的數據庫了,別忘了經度、緯度一定要聚族索引,或者干脆去掉id,直接經度和緯度一起作為主鍵。
經度float,緯度float,偏移經度nvarchar,偏移緯度nvarchar
該方法可能影響了部分人的財路,在此,我表示誠摯的歉意。
優點:本地執行,速度快。
缺點:糾偏庫需要花錢買或者在網上找,免費的可能不全。
總結
- 上一篇: TCAM 与CAM
- 下一篇: 闵可夫斯基距离(LP距离)、曼哈顿距离、