在Google 地图中国部分,平面地图和卫星图都存则偏移量,而这个偏移量不是线性的,我们在做GPS定位平台的时候,在播放历史轨迹的时候往往发现车辆行驶的路线偏离了地图上的实际道路,这点是很多客户不能接受的,如何解决这个问题呢。
我们首先要解决两个问题,一个是偏移量数据的问题,二是计算实际应该显示经纬度的算法
1. 如何获得偏移量数据。
Google 已经有一个偏移纠正的API,如 http://ditu.google.cn/maps/vp?spn=0.0,0.0&z=18&vp=39.111195,117.148067,通过这个API,返回的是 以下的格式:
39.111195, 117.148067, 18, [9, -2, 18, -4, 37, -8, 74, -16, 149, -33, 298, -67, 596, -135, 1193, -270]
以上的数据的含义是几个放大级别的偏移量:
18级: 1193, -270
17级: 596, -135
16级: 298, -67
15级: 149, -33
14级: 74, -16
13级: 37, -8
12级: 18, -4
11级: 9, -2
一般情况来说,我们为了得到比较高的精度度,会取 18级别的数据1193,-270,1193为x方向上精度的偏移像素,-270为y方向上维度偏移像素。
由这个数据计算39.111195,117.148067在偏移之后的经纬度为39.11231854918217,117.15446412563324,具体的算法源码如下:
2. 算法和源码
首先,我们会建一个表Offset,这个表会存所有经纬度偏移量的数据,格式如下:
53.12 | 120.61 | 1321 | -461 |
53.12 | 120.62 | 1322 | -462 |
53.12 | 120.63 | 1324 | -465 |
53.12 | 120.64 | 1327 | -468 |
53.12 | 120.65 | 1331 | -473 |
53.12 | 120.66 | 1336 | -478 |
在上表中,我们存的都是18级的偏移量数据,而我们在存经纬度的时候精确到0.01, 例如,我们的经纬度是 52.12123213, 120.6123123, 我们会取 52.12,120.61 的偏移量去计算偏移后的经纬度。
源码如下:
public decimal[] GetLatLng(decimal lat, decimal lng)
{
int PX, PY;
int OX = 0;
int OY = 0;
int PX1, PY1;
decimal[] LatLng = new decimal[] { lat, lng };
string oXY = “”;
string Lat = lat.ToString().Substring(0, lat.ToString().IndexOf(‘.’) + 3);
string Lng = lng.ToString().Substring(0, lng.ToString().IndexOf(‘.’) + 3);
if (CacheManager.Get(Lat + “_” + Lng) != null)
{
oXY = CacheManager.Get(Lat + “_” + Lng).ToString();
}
try
{
Database db = DatabaseFactory.CreateDatabase();
string sqlCmd = “SELECT TOP 1 X,Y FROM Offset WHERE Lat=” + Lat + ” AND Lng=” + Lng;
DbCommand dbCmd = db.GetSqlStringCommand(sqlCmd);
using (IDataReader dr = db.ExecuteReader(dbCmd))
{
if (dr.Read())
{
OX = DataReaderHelper.GetInt32(dr, “X”);
OY = DataReaderHelper.GetInt32(dr, “Y”);
oXY = OX.ToString() + “,” + OY.ToString();
CacheManager.Permanent(Lat + “_” + Lng, oXY);
}
}
if (OX != 0 && OY != 0)
{
Map.LatLongToPixelXY(Convert.ToDouble(lat), Convert.ToDouble(lng), 18, out PX, out PY);
PX1 = PX + OX;
PY1 = PY + OY;
LatLng[0] = Convert.ToDecimal(Map.PixelYToLat(PY1, 18));
LatLng[1] = Convert.ToDecimal(Map.PixelXToLng(PX1, 18));
}
}
catch (Exception ex)
{
ExceptionHandler.ExceptionProcess(ex);
}
return LatLng;
}
http://www.lbsgps.org/?p=418