让OpenLayers添加百度地图(未完版)

来自:http://www.cnblogs.com/laoyu/archive/2012/06/10/2544379.html

让OpenLayers添加百度地图(未完版)

KoalaGIS的在线地图系统,打算采用国内外主要的几个地图服务:google地图、百度地图、OpenStreetMap、天地图。google、百度、openstreet的服务器性能好,速度快,但google由于政策原因,不确定因素太多,OpenstreetMap个人感觉配图不怎么好看,添加天地图完全就是为了顾忌下咱们这个GIS专业的脸面,毕竟总要搞点专业的东西吧,虽然他很垃圾,但胜于无!

为此,需要在OpenLayers上扩展一个百度地图图层出来,让其能在Openlayers中显示出来。为了叠加百度地图,首先必须了解其瓦片的组织规则,通过对百度api的js文件解析和网上相关资料的收集,经过程序测试,推论正确,现讲解下其基本的参数,以及编写的KoalaGIS.Layer.WMTS.Baidu图层。

百度地图也是采用的魔卡托投影,个人感觉和google的web墨卡托投影是一样的,但据网友测试,两者计算结果有点出入,我猜测可能是百度或者google地图有偏移参数的影响吧,该文暂不分析此原因,且该问题本人还没正式测试过,有待考证!

利用百度提供的API进行坐标转换

varprojection=newBMap.MercatorProjection();

varpoint=projection.lngLatToPoint(newBMap.Point(116.404,39.915));

得出的结果是12958175,4825923.77

用Openlayers提供的web墨卡托投影对该经纬度投影得出的结果为:????

百度地图的分辨率问题

对百度地图api的js脚本进行解析,可以看到该函数:

可以看到两个获取分辨率相关的函数如下:

getZoomUnits:function(T){

returnMath.pow(2,(18-T))//从这里可以看出,百度地图的分辨率几乎就是固定的2的N次幂来计算的

},

详细请见该文《百度地图的瓦片参数解析》http://blog.sina.com.cn/s/blog_4c8b1bdd0100xij4.html

百度地图的坐标系统:平面坐标系的原点与经纬度的原点一致,即赤道与0度经线相交的位置

百度地图瓦片编号方式:

百度地图API在展示地图时是将整个地图图片切割成若干图块来显示的,当地图初始化或是地图级别、中心点位置发生变化时,地图API会根据当前像素坐标计算出视野内需要的图块坐标(也叫图块编号),从而加载对应的图块用以显示地图。

百度地图的图块坐标原点与平面坐标一致,从原点向右上方开始编号为0,0:

如何通过一个坐标和缩放级别计算出百度瓦片所在的行列号呢?

百度瓦片的计算方式很简单,大致如下:

1.计算出坐标的平面坐标位置,瓦片的切割起止点就是0,0

2.用平面坐标除以分辨率就能得到坐标到起点的像素大小,然后除以每张瓦片的大小取整就是瓦片的行列号了

cx=[((x-0)/res)/tileWidth]

 cy=[((y-0)/res)/tileHeight]

分辨率前面已经讲过,res=Math.Pow(2,level-18);

3.举例来说吧,第18级下,选取经纬度为(116.404,39.915)的坐标点,该点大致在北京天,安,门那,经过投影得出其平面位置为(12958175,4825923.77)采用百度的api计算出来的,用openlayers计算的不是该坐标。利用上面的行列号计算公式推算出瓦片行列号为:50617,18851。利用百度地图提供的瓦片服务器地址,根据行列号和缩放级别,可以调用该瓦片地址:

OpenLayers中添加百度地图

遇到的问题:

1,坐标系不一致。

Openlayers中采用的坐标系并非百度地图的数学坐标系

2,行列号的计算方式不一样

百度地图是从左到右,从下到上;但Openlayers和google以及通常的wmts服务都是从左到右,从上到下的!

解决办法:坐标系还是按照Openlayers的思路,所有的方式都不动,只是把他计算瓦片的方式改变就OK了。

KoalaGIS.Layer.WMTS.Baidu.js文件

代码如下:

(function(){

window.KoalaGIS={

VERSION:'1.0.0',

Author:'KolaGISStudio'

};

KoalaGIS.Layer={};

KoalaGIS.Layer.WMTS={};

})();

KoalaGIS.Layer.WMTS.Baidu=OpenLayers.Class(OpenLayers.Layer.XYZ,{

url:null,

tileOrigin:newOpenLayers.LonLat(-20037508.34,20037508.34),

tileSize:newOpenLayers.Size(256,256),

type:'png',

useScales:false,

overrideDPI:false,

initialize:function(options){

this.resolutions=[];

for(vari=0;i<19;i++){

this.resolutions[i]=Math.pow(2,18-i);

}

OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);

if(this.resolutions){

this.serverResolutions=this.resolutions;

this.maxExtent=this.getMaxExtentForResolution(this.resolutions[0]);

}

//thisblockstepsthroughtranslatingthevaluesfromtheserverlayerJSON

//capabilitiesobjectintovaluesthatwecanuse.Thisisalsoahelpful

//referencewhenconfiguringthislayerdirectly.

if(this.layerInfo){

//aliastheobject

varinfo=this.layerInfo;

//buildourextents

varstartingTileExtent=newOpenLayers.Bounds(

info.fullExtent.xmin,

info.fullExtent.ymin,

info.fullExtent.xmax,

info.fullExtent.ymax

);

//setourprojectionbasedonthegivenspatialreference.

//esriusesslightlydifferentIDs,sothismaynotbecomprehensive

this.projection='EPSG:'+info.spatialReference.wkid;

this.sphericalMercator=(info.spatialReference.wkid==102100);

//convertesriunitsintoopenlayersunits(basicfeetormetersonly)

this.units=(info.units=="esriFeet")?'ft':'m';

//optionalextendedsectionbasedonwhetherornottheserverreturned

//specifictileinformation

if(!!info.tileInfo){

//eithersetthetilesbasedonrows/columns,orspecificwidth/height

this.tileSize=newOpenLayers.Size(

info.tileInfo.width||info.tileInfo.cols,

info.tileInfo.height||info.tileInfo.rows

);

//thismustbesetwhenmanuallyconfiguringthislayer

this.tileOrigin=newOpenLayers.LonLat(

info.tileInfo.origin.x,

info.tileInfo.origin.y

);

varupperLeft=newOpenLayers.Geometry.Point(

startingTileExtent.left,

startingTileExtent.top

);

varbottomRight=newOpenLayers.Geometry.Point(

startingTileExtent.right,

startingTileExtent.bottom

);

if(this.useScales){

this.scales=[];

}else{

this.resolutions=[];

}

this.lods=[];

for(varkeyininfo.tileInfo.lods){

if(info.tileInfo.lods.hasOwnProperty(key)){

varlod=info.tileInfo.lods[key];

if(this.useScales){

this.scales.push(lod.scale);

}else{

this.resolutions.push(lod.resolution);

}

varstart=this.getContainingTileCoords(upperLeft,lod.resolution);

lod.startTileCol=start.x;

lod.startTileRow=start.y;

varend=this.getContainingTileCoords(bottomRight,lod.resolution);

lod.endTileCol=end.x;

lod.endTileRow=end.y;

this.lods.push(lod);

}

}

this.maxExtent=this.calculateMaxExtentWithLOD(this.lods[0]);

this.serverResolutions=this.resolutions;

if(this.overrideDPI&&info.tileInfo.dpi){

//seecommentabovefor'overrideDPI'

OpenLayers.DOTS_PER_INCH=info.tileInfo.dpi;

}

}

}

},

getContainingTileCoords:function(point,res){

//returnnewOpenLayers.Pixel(

//Math.max(Math.floor((point.x-this.tileOrigin.lon)/(this.tileSize.w*res)),0),

//Math.max(Math.floor((this.tileOrigin.lat-point.y)/(this.tileSize.h*res)),0)

//);

returnnewOpenLayers.Pixel(

Math.floor((point.x-this.tileOrigin.lon)/(this.tileSize.w*res)),

Math.floor((point.y-this.tileOrigin.lat)/(this.tileSize.h*res))

);

},

calculateMaxExtentWithLOD:function(lod){

//themaxextentwe'reprovidedwithjustoverlapssometiles

//ourrealextentistheboundsofallthetileswetouch

varnumTileCols=(lod.endTileCol-lod.startTileCol)+1;

varnumTileRows=(lod.endTileRow-lod.startTileRow)+1;

varminX=this.tileOrigin.lon+(lod.startTileCol*this.tileSize.w*lod.resolution);

varmaxX=minX+(numTileCols*this.tileSize.w*lod.resolution);

varmaxY=this.tileOrigin.lat-(lod.startTileRow*this.tileSize.h*lod.resolution);

varminY=maxY-(numTileRows*this.tileSize.h*lod.resolution);

returnnewOpenLayers.Bounds(minX,minY,maxX,maxY);

},

calculateMaxExtentWithExtent:function(extent,res){

varupperLeft=newOpenLayers.Geometry.Point(extent.left,extent.top);

varbottomRight=newOpenLayers.Geometry.Point(extent.right,extent.bottom);

varstart=this.getContainingTileCoords(upperLeft,res);

varend=this.getContainingTileCoords(bottomRight,res);

varlod={

resolution:res,

startTileCol:start.x,

startTileRow:start.y,

endTileCol:end.x,

endTileRow:end.y

};

returnthis.calculateMaxExtentWithLOD(lod);

},

getUpperLeftTileCoord:function(res){

varupperLeft=newOpenLayers.Geometry.Point(

this.maxExtent.left,

this.maxExtent.top);

returnthis.getContainingTileCoords(upperLeft,res);

},

getLowerRightTileCoord:function(res){

varbottomRight=newOpenLayers.Geometry.Point(

this.maxExtent.right,

this.maxExtent.bottom);

returnthis.getContainingTileCoords(bottomRight,res);

},

getMaxExtentForResolution:function(res){

varstart=this.getUpperLeftTileCoord(res);

varend=this.getLowerRightTileCoord(res);

varnumTileCols=(end.x-start.x)+1;

//varnumTileRows=(end.y-start.y)+1;

varnumTileRows=(start.y-end.y)+1;

varminX=this.tileOrigin.lon+(start.x*this.tileSize.w*res);

varmaxX=minX+(numTileCols*this.tileSize.w*res);

//varmaxY=this.tileOrigin.lat-(start.y*this.tileSize.h*res);

varmaxY=this.tileOrigin.lat+(start.y*this.tileSize.h*res);

varminY=maxY-(numTileRows*this.tileSize.h*res);

returnnewOpenLayers.Bounds(minX,minY,maxX,maxY);

},

clone:function(obj){

if(obj==null){

obj=newOpenLayers.Layer.ArcGISCache(this.name,this.url,this.options);

}

returnOpenLayers.Layer.XYZ.prototype.clone.apply(this,[obj]);

},

getMaxExtent:function(){

varresolution=this.map.getResolution();

returnthis.maxExtent=this.getMaxExtentForResolution(resolution);

},

getTileOrigin:function(){

//debugger;

varextent=this.getMaxExtent();

returnnewOpenLayers.LonLat(extent.left,extent.bottom);

},

getURL:function(bounds){

//debugger;

varz=this.map.getZoom();

varres=this.getResolution();

//z=18-z;

//varres=Math.pow(2,z-18);

//tilecenter

varoriginTileX=(this.tileOrigin.lon+(res*this.tileSize.w/2));

//varoriginTileY=(this.tileOrigin.lat-(res*this.tileSize.h/2));

varoriginTileY=(this.tileOrigin.lat+(res*this.tileSize.h/2));

originTileX=0;

originTileY=0;

varcenter=bounds.getCenterLonLat();

//center.lat=4825923.77;

//center.lon=12958175;

varpoint={x:center.lon,y:center.lat};

//varx=(Math.round(Math.abs((center.lon-originTileX)/(res*this.tileSize.w))));

////vary=(Math.round(Math.abs((originTileY-center.lat)/(res*this.tileSize.h))));

//vary=(Math.round(Math.abs((center.lat-originTileY)/(res*this.tileSize.h))));

varx=(Math.round((center.lon-originTileX)/(res*this.tileSize.w)));

//vary=(Math.round(Math.abs((originTileY-center.lat)/(res*this.tileSize.h))));

vary=(Math.round((center.lat-originTileY)/(res*this.tileSize.h)));

//x=Math.round(center.lon*1/this.tileSize.w);

//y=Math.round(center.lat*1/this.tileSize.h);

//varx=Math.floor(Math.abs((center.lon)*res/this.tileSize.w));

//vary=(Math.round(Math.abs((originTileY-center.lat)/(res*this.tileSize.h))));

//vary=Math.floor(Math.abs((center.lat)*res/this.tileSize.h));

//x=Math.round(Math.abs(x)/256);

//y=Math.round(Math.abs(y)/256);

//thispreventsusfromgettingpinktiles(non-existanttiles)

if(this.lods){

varlod=this.lods[this.map.getZoom()];

if((x<lod.startTileCol||x>lod.endTileCol)

||(y<lod.startTileRow||y>lod.endTileRow)){

returnnull;

}

}

else{

varstart=this.getUpperLeftTileCoord(res);

varend=this.getLowerRightTileCoord(res);

//if((x<start.x||x>=end.x)

//||(y<start.y||y>=end.y)){

//returnnull;

//}

if((x<start.x||x>=end.x)

||(y>=start.y||y<end.y)){

//returnnull;

}

}

//Constructtheurlstring

varurl=this.url;

vars=''+x+y+z;

if(OpenLayers.Util.isArray(url)){

url=this.selectUrl(s,url);

}

//AccessingtilesthroughArcGISServerusesadifferentpath

//structurethandirectaccessviathefolderstructure.

if(this.useArcGISServer){

//AGSMapServershaveprettyurlaccesstotiles

url=url+'/tile/z/{y}/{x}';}else{//Thetileimagesarestoredusinghexvaluesondisk.//x='C'+this.zeroPad(x,8,16);//y='R'+this.zeroPad(y,8,16);//z='L'+this.zeroPad(z,2,16);//url=url+'/{z}/y/{x}.'+this.type;

varx_str='x′;varystr=′{y}';

if(x<0)

x_str='Mx′;if(y<0)ystr=′M{y}';

url=url+'/u=x='+x_str+';y='+y_str+';z=${z};v=011;type=web&fm=44';

}

//Writethevaluesintoourformattedurl

url=OpenLayers.String.format(url,{'x':Math.abs(x),'y':Math.abs(y),'z':z});

returnurl;

},

zeroPad:function(num,len,radix){

varstr=num.toString(radix||10);

while(str.length<len){

str="0"+str;

}

returnstr;

},

CLASS_NAME:'KoalaGIS.Layer.WMTS.Baidu'

});

相关推荐