arcgis api for js入门开发系列二十 用HTML5 canvas绘制地图 瓦片以及如何计算

时间:2022-01-12 14:59:50

上一篇也说到瓦片,我们为什么使用瓦片?这一篇主要是关于如何拼接地图?

    下面的一张图,可以一眼明了,地图是如何切割以及拼接的。

arcgis api for js入门开发系列二十 用HTML5 canvas绘制地图 瓦片以及如何计算

瓦片信息

    瓦片信息包括切图原点,瓦片大小,格式,分辨率以及分辨率级别等。

    切图原点,一般是整个坐标系的最左上角,比如说,web墨卡托是[-20037508.3427892, 20037508.3427892]。切图原点右侧列数是正数,左侧的列数是负数,下侧行数是正数,上侧行数是负数。

    瓦片的宽度、高度,目前互联网最常见的瓦片宽度和高度都是256像素。

    瓦片格式,可能是png,jpg等。

    分辨率,这里不是指电脑的分辨率。而这里意思是一像素代表多少米,类似于比例尺。

    分辨率级别,含有若干级别的分辨率,不同的分辨率下面,显示不同的要素信息。例如,低分辨率下面,显示洲名称和海洋名称。中分辨率下面,显示省名。高分辨率下面,就显示POI信息。互联网企业当中分辨率级别数在20上下。

    地图范围,切图的范围,只在这个范围下面才切图,其他的区域都没有相应的瓦片。如果把所有的分辨率都切完的话,是非常耗时间的。仅仅是中国区域,一台8核的机器,也得需要一个月才能切完,更何况全世界了。

Google为例

    谷歌使用的web墨卡托投影,分辨率级别一共22级,他的每一级分辨率大小20037508.3427892*2/(256*(2^i))。20037508.3427892*2代表整个的X轴范围,256代表图片的像素大小,2代表是0级时有两列(有的地图0级只有1列,这个时候就是2^(i-1)),i代表级别。

    这个时候,分辨率集合就是[78271.51696402031, 39135.758482010155, 19567.879241005077, 9783.939620502539, 4891.969810251269, 2445.9849051256347, 1222.9924525628173, 611.4962262814087, 305.74811314070433, 152.87405657035217, 76.43702828517608, 38.21851414258804, 19.10925707129402, 9.55462853564701, 4.777314267823505, 2.3886571339117526, 1.1943285669558763, 0.5971642834779382, 0.2985821417389691, 0.14929107086948454, 0.07464553543474227, 0.037322767717371134]。

    我们现在需要计算两个东东,一个是当前分辨率下面最大的行和列数,第二个某一个坐标在第几行几列。下面会列出好几个公式,一定要理解为什么这么计算,否则移植到其他的切图服务不会自己列出相应的公式了。

最大行数和列数

    计算公式,20037508.3427892*2/(256*scale),20037508.3427892*2代表X轴和Y轴范围,256代表图片的像素大小,scale代表分辨率大小。

    通过这个计算公式,我们知道最大的行数和列数,是[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304],注意的是行列值是从0开始的。

    比如说,1级下面,有两行和两列。这四张图片的地址如下:

    我们把这四张图片合在一起的话,就变成如下的图,这就是一个世界的地图了。

    arcgis api for js入门开发系列二十 用HTML5 canvas绘制地图 瓦片以及如何计算

计算行,列位置

    计算行位置公式:Math.floor((x-(-20037508.3427892))/256/scale))。x-(-20037508.3427892)是最左侧的距离,scale分辨率,256代表宽度。Math.floor小于或等于指定数字的最大整数,这样值是从0开始的。

    计算列位置公式:Math.floor((20037508.3427892-y)/256/scale))。20037508.3427892-y是到最上侧的距离,scale分辨率,256代表宽度。Math.floor小于或等于指定数字的最大整数,这样值是从0开始的。

    左上角是X值最小,Y值最大。屏幕是X和Y值都是最小的。这一点转换关系需要明白,否则Y轴的方向都反了。

    如果切图不是从左上角开始的,就得计算每一个分辨率下面的左上角和右下角所处的行和列,就可以知道行和列的范围。同理,可计算当前可视区域的行和列。

    我们如果知道行列以及分辨率等级,就很容易知道这个瓦片的地址。http://mt2.google.cn/vt/x=0&y=0&z=1,这里的x代表参数行数,y代表列数,z代表分辨率等级。

    Google这种图片地址属于非常好计算,幸好也是非常普遍的。比较难的,算是微软的,行列以及分辨率等级计算都差不多,难的是想x,y,z参数不知道怎么计算的。

    例如,http://ak.dynamic.t2.tiles.virtualearth.net/comp/ch/1232?mkt=en-us&it=G,VE,BX,L,LA&shading=hill&og=31&n=z ,这个图片地址,这个1232不知道怎么来的。不过幸好找到一个论文才弄明白,《利用BingMaps地图切片实现网络地图服务》,地址http://wenku.baidu.com/link?url=7Mh7h8Vn94V2ha8LJLIy3WF2ONjLwcEaRCywujCR-fk4Pa-PGKrmcKL1zBaOmUK5eDmaIrXbO6SyAPdMHCOAXTn6PnhqBsL6yPsenWdMkfK

    我下面列出相关计算代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function  getBingMapsImageNumber(x,y,z){
     //10进制转化为2进制,前面补充0
     _f= function (n,m){
         var  t= n.toString(2)+ "" ;
         for (; t.length<m;){
             t= "0" +t;
         }
         return  t;
     }
     var  _if=_f(x,z);
     var  _jf=_f(y,z);
     var  r= "" ;
     for ( var  k=0;k!=z;++k){
         r+=_jf[k]+_if[k];
     }
     r=parseInt(r,2).toString(4);
     return  _f(r,z);
}