百度地图的瓦片参数解析

来自:http://blog.sina.com.cn/s/blog_4c8b1bdd0100xij4.html


百度地图的瓦片参数解析 (2012-03-12 23:23:47)
标签: 百度地图 瓦片参数 切片 纠偏参数 杂谈 分类: 编程技术
最近想在自己的Android手机上开发一个小工具可以实时查看附近周围的自行车还车点的可借车辆和可还车辆的空位,因为哥好几次屁颠屁颠骑到还车点的时候发现车位满了或者没车可借了,有次还因此损失接近百元,或者去一个新地方都不知道附近的还车点藏在什么地方!同时为了学习一下Android开发,因此想做这么一个小工具。
考虑到以后专业需要,选择ArcGIS For Android工具进行开发,考虑google地图可能被国家给封掉,而百度地图越来越不错,因此选择百度地图作为地图,杭州市的自行车还车点分布图和实时数据可以调用杭州市地理信息公共服务平台提供的数据,因此基本上数据应该不成问题了!ArcGIS for Android提供了Compact型的本地离线瓦片地图的图层功能,但对于其他的瓦片地图图层需要自己去扩展,因此本人上一个星期下班时间趁兴趣爱好,稍微学习了下Eclipse 和Java的基本语法,终于走通了自定义瓦片图层的功能,但现在有个问题来了!本以为百度地图应该很多人用,肯定有相关的资料,但翻遍网络居然找不到关于百度地图的瓦片切片参数,只知道是用的高德提供的数据。百度、Google、论坛发帖都没有效果,只能自己硬着头皮去解析其参数了!哥向来不喜欢自己去研究比较简单的东西,但这次确实么有办法,只能自己去搞了.
好在百度提供了其二次开发接口API,有Javascript、Flex、Android等版本,可以随便拿一个版本的来进行反编译然后解析一下,但考虑到Javascript不需要进行反编译,javascript是个解释型语句,顶多只是混淆而已,用个js调整工具,再加上VS强大的调试功能,也可以大致猜出其思路。SO,本人就从百度地图的Javascript接口开始推导其瓦片参数!
首先就从CenterAndZoom函数开始吧
centerAndZoom: function(T, cC) {
var cB = this;
if (bU(T)) {
var cF = cB._getLocal();
cF.setSearchCompleteCallback(function(cG) {
if (cF.getStatus() == 0 && cF._json.result.type == 2) {
var cI = cG.getPoi(0).point;
var cH = cC || O.getBestLevel(cF._json.content.level, cB);
cB.centerAndZoom(cI, cH);
if (BMAP_PERSPECTIVE_MAP.getCityName(T)) {
cB.setCurrentCity(T)
}
}
});
cF.search(T);
return
}
if (!(T instanceof b3) || !cC) {
return
}
cC = cB._getProperZoom(cC).zoom;
cB.lastLevel = cB.zoomLevel || cC;
cB.zoomLevel = cC;
cB.centerPoint = new b3(T.lng, T.lat);
cB.mercatorCenter = cB.projection.lngLatToMercator(cB.centerPoint, cB.currentCity);
cB.defaultZoomLevel = cB.defaultZoomLevel || cB.zoomLevel;
cB.defaultCenter = cB.defaultCenter || cB.centerPoint;
var cE = new a8("onload");
var cD = new a8("onloadcode");
cE.point = new b3(T.lng, T.lat);
cE.pixel = cB.pointToPixel(cB.centerPoint, cB.zoomLevel);
cE.zoom = cC;
if (!cB.loaded) {
cB.loaded = true;
cB.dispatchEvent(cE)
}
cB.dispatchEvent(cD);
cB.dispatchEvent(new a8("onmoveend"));
if (cB.lastLevel != cB.zoomLevel) {
cB.dispatchEvent(new a8("onzoomend"))
}
}
调试进去,可以看到会调用
moveGridTiles: function() {
debugger;
var c0 = this.mapTypeLayers;
var cM = c0.concat(this.tileLayers);
var cS = cM.length;
for (var cU = 0; cU < cS; cU++) {
var cF = cM[cU];
if (cF.baseLayer) {
this.tilesDiv = cF.tilesDiv
}
var c6 = this.map;
var c2 = c6.getMapType();
var c7 = c2.getProjection();
var cT = c6.zoomLevel;
var cW = c6.mercatorCenter; //百度地图的瓦片行列号计算是先将经纬度换算成墨卡托投影来计算的,因为经纬度是个球面坐标,而瓦片切割的时候肯定是平面的,因此都会有个投影过程。这个墨卡托的投影公式后面再去研究,可以看看百度地图到底采用的什么投影!
this.mapCenterPoint = cW;
var cK = c2.getZoomUnits(cT);
var cN = c2.getZoomFactor(cT);
//上面的ck和cn就是获取类似瓦片地图分辨率的东东,同时可以看到百度地图是通过地图的中心点来计算整个地图需要调用的瓦片的行列号的,然后后面可能采用将瓦片进行螺旋排列的吧,后面的没细看(我看过有个开源的瓦片下载工具就是螺旋排列的,以增强可是效果!)
var cL = Math.ceil(cW.lng / cN);
var cG = Math.ceil(cW.lat / cN);
var cR = c2.getTileSize();
var cE = [cL, cG, (cW.lng - cL * cN) / cN * cR, (cW.lat - cG * cN) / cN * cR];
var c1 = cE[0] - Math.ceil((c6.width / 2 - cE[2]) / cR);
var cD = cE[1] - Math.ceil((c6.height / 2 - cE[3]) / cR);
var cX = cE[0] + Math.ceil((c6.width / 2 + cE[2]) / cR);
var cP = 0;
if (c2 === BMAP_PERSPECTIVE_MAP && c6.getZoom() == 15) {
cP = 1
}
var cO = cE[1] + Math.ceil((c6.height / 2 + cE[3]) / cR) + cP;
this.areaCenter = new b3(cW.lng, cW.lat);
var cC = this.mapTiles;
var cJ = -this.areaCenter.lng / cK;
var cI = this.areaCenter.lat / cK;
var c4 = [Math.round(cJ), Math.round(cI)];
var cB = c6.getZoom();
for (var c5 in cC) {
var c8 = cC[c5];
var c3 = c8.info;
if (c3[2] != cB || (c3[2] == cB && (c1 > c3[0] || cX <= c3[0] || cD > c3[1] || cO <= c3[1]))) {
this.hideTile(c8)
}
}
var cH = -c6.offsetX + c6.width / 2;
var cQ = -c6.offsetY + c6.height / 2;
cF.tilesDiv.style.left = Math.round(cJ + cH) - c4[0] + "px";
cF.tilesDiv.style.top = Math.round(cI + cQ) - c4[1] + "px";
var T = [];
for (var cZ = c1; cZ < cX; cZ++) {
for (var cY = cD; cY < cO; cY++) {
T.push([cZ, cY])
}
}
T.sort((function(c9) {
return function(da, db) {
return ((0.4 * Math.abs(da[0] - c9[0]) + 0.6 * Math.abs(da[1] - c9[1])) - (0.4 * Math.abs(db[0] - c9[0]) + 0.6 * Math.abs(db[1] - c9[1])))
}
})([cE[0] - 1, cE[1] - 1]));
this.numLoading += T.length;
for (var cZ = 0, cV = T.length; cZ < cV; cZ++) {
this.showTile([T[cZ][0], T[cZ][1], cB], c4, cF)
}
}
return
}

可以看到两个获取分辨率相关的函数如下:
getZoomUnits: function(T) {
return Math.pow(2, (18 - T)) //从这里可以看出,百度地图的分辨率几乎就是固定的2的N次幂来计算的
},
getZoomFactor: function(T) {
return this.getZoomUnits(T) * 256
}

以上为本人的大致猜测,后面还需要继续检验,感觉百度好像对各个区域做了处理,这样才能满足全球的范围内的投影精度,这块没有细究!在这次的解析过程中还发现了一个奇怪之处!

//correct_pts:莫非是纠偏参数????貌似投影时会用到些参数,可以的话,后面再研究下它的纠偏参数吧,哎,上班后反而没有在学校那样有过多的时间去深入研究东西,很多东西都只是浅尝辄止,悲哀啊!
correct_pts: {
bj: [{
j: 116.305687,
w: 39.990912,
utm_x: 12947230.73,
utm_y: 4836903.65,
x: 630412,
y: 547340
}, {
j: 116.381837,
w: 40.000198,
utm_x: 12955707.8,
utm_y: 4838247.62,
x: 667412,
y: 561832
}, {
j: 116.430651,
w: 39.995216,
utm_x: 12961141.81,
utm_y: 4837526.55,
x: 686556,
y: 573372
}, {
j: 116.474111,
w: 39.976323,
utm_x: 12965979.81,
utm_y: 4834792.55,
x: 697152,
y: 586816
}, {
j: 116.280328,
w: 39.953159,
utm_x: 12944407.75,
utm_y: 4831441.53,
x: 603272,
y: 549976
}, {
j: 116.316117,
w: 39.952496,
utm_x: 12948391.8,
utm_y: 4831345.64,
x: 618504,
y: 557872
}, {......

欧拉,暂时到此,可能里面会有些错误推导,希望有同道者共同研究,搞不定的话哥也只能去老老实实调用google地图了,毕竟资料多,或者调用那国家测绘局提供的那丑的不行的慢的像蜗牛的“天地图”地图或者直接采用百度的API算了吧。

不知道何时工具能够搞出来啊,每天1小时coding!

你可能感兴趣的:(百度地图)