? ?在上一篇文章中,細致介紹了瓦片數(shù)據(jù)在webgis中的組織結構,得知了瓦片數(shù)據(jù)文件的組織其實是按照瓦片的級別、行、列號來組織的。如果給定一個坐標(一般為經緯度坐標),我們該怎樣計算出所需瓦片的行列號呢?我們在這一節(jié)中就來探討瓦片行列號的換算關系。在繼續(xù)下文之前,我們需要搞清楚幾個webgis中的基礎概念,且看下文詳述。
“?地圖中的比例尺(Scale)和分辨率(Resolution)??”
? ? ? 在用arcgis切完圖之后,打開發(fā)布的服務或者打開config.xml配置文件,即可看到切圖的相關配置,如下圖所示:
? ? ??在上圖中,levels表示該套切圖共有7個層級,每一個層級中又有Resolution和Scale兩個參數(shù),它們分別代表該層級下的分辨率和比例尺。比例尺即為地圖上的一厘米代表實際上的多少厘米。分辨率即為在當前地圖范圍內,1個像素代表多少地圖單位,地圖單位取決于當前的空間參考??梢姺直媛矢鷇pi(dpi代表每英寸的像素數(shù))有關系,也跟地圖的單位有關系。
“?屏幕上1像素代表的實際距離(分辨率)??”
? ? ? ?現(xiàn)在來看下分辨率計算的原理,假設地圖的坐標單位是米,dpi為96,即1英寸=96像素。1英寸=2.54厘米,也就是說96個像素=2.54厘米,換算成米后,即1個像素=0.0254 / 96米。如果當前層級下的地圖比例尺為1:125000000,則代表圖上1米等于實地125000000米,那么1個像素代表的實際距離為125000000*0.0254/96 = 33072.9166666667米。
“?瓦片行列號換算原理??”
在計算地圖上某點所對應的瓦片行數(shù)時,有如下計算步驟:首先已知一個瓦片的實際長度是lrealTileSize(注意這里的單位不是像素,而是實際距離單位),再計算出當前屏幕某點距離瓦片原點的實際距離lreal,然后用實際距離lreal除以一個瓦片的實際長度lrealTileSize就可以得到瓦片的列數(shù),即col=floor(lreal/lrealTileSize)。
?????? 假設,地圖切圖的原點坐標為(x0,y0),瓦片的大小是tileSize,地圖分辨率為res,則計算地圖上點(x,y)所在的瓦片行列號公式為:
????? col? = Math.floor((x – x0)/( tileSize*res))
? ? ? ?row = Math.floor((y – y0)/( tileSize*res))
? ? ? ?注,Math.floor(number)函數(shù)返回小于number的最大整數(shù)。即浮點數(shù)向下取整。
? ? ? ?在實際webgis系統(tǒng)中,我們需要得到畫布的高度和寬度以及此時需要顯示的地圖的幾何范圍,還要知道當前需要顯示的地圖層級,在確定了這些需求后,既可以計算需要加載的瓦片行列號范圍。
? ? ? ?假設畫布寬為cvWidth,高為cvHeight,當前地圖坐標系下的地圖左下角坐標為extentX_min,extentY_min,右上角坐標為extentX_max,extentY_max。
具體計算流程如下所示:
計算請求地理范圍的中心點坐標(centerGeoPt)
? ? ? ?比如當前要加載經緯度為(lng,lat),需要將其轉為平面坐標值,計算過程在本文附帶源碼中,不在此處做詳細論述。
計算出畫布范圍內所對應的地理范圍(min_x,min_y,max_x,max_y)
? ? ? ?根據(jù)當前地圖層級,得到分辨率res(即1個像素代表的實際距離大?。?,用上步中得到的centerGeoPt的x坐標加上或者減去半個畫布的寬度就可以得到max_x和min_x的值,即min_x = centerGeoPt.x – cvWidth*res/2;max_x = centerGeoPt.x + cvWidth*res /2。同理可得min_y與max_y的值。示意圖如下所示:
計算瓦片起始行列號
? ? ? ?在得到上步的地理范圍后,再計算起始瓦片的行列號就會容易很多。起始瓦片的行列號計算公式分別如下所示:
列號:tileLeftTopX =Math.floor((Math.abs(min_x-extentX_min))/res* tileSize);
行號:tileLeftTopY =Math.floor((Math.abs(max_y-extentY_max))/res* tileSize);
計算實際地理范圍
? ? ? ?此前得到的地理范圍只是畫布對應的地理范圍,當計算出這個范圍所需的瓦片后,這些瓦片所覆蓋的地理范圍不一定就是畫布對應的地理范圍,如下圖所示。這時,就需要再計算出瓦片覆蓋的實際地理范圍。
實際地理范圍計算公式:
realmin_x = tileLeftTopX * res* tileSize + extentX_min;
realmax_y= extentY_max- tileLeftTopY * res* tileSize;
計算左上角偏移像素
? ? ? ?如上圖所示,左上角瓦片與畫布左上角是存在offset_x與offset_y這兩個偏移值的,所以我們需要計算出這兩個值(注意,這里是像素值哦),以便在畫布加載瓦片的時候使用。計算公式如下所示:
offset_x= ((realmin_x- min_x )/res);
offset_y = ((realmax_y – max_y )/res);
計算瓦片個數(shù)(x,y軸上的瓦片個數(shù))
計算公式如下所示:
tileNum_x = Math.ceil((cvWidth + Math.abs(offset_x))/tileSize);
tileNum_y = Math.ceil((cvHeight + Math.abs(offset_y))/tileSize);
注,Math.ceil(number)函數(shù)返回大于number的最小整數(shù)。即浮點數(shù)向上取整。
“?繪制瓦片”
? ? ? ?我們在前面用了不少篇幅來討論了瓦片換算的整個計算原理,現(xiàn)在終于可以來實現(xiàn)算法繪制瓦片了!
繪制代碼這里需要說明下使用方法,在main.js中就是整個瓦片換算的算法實現(xiàn),而config.js是有關于當前坐標系下(EPSG:3857,就是webgis中常用的墨卡托投影坐標系)的各個層級的比例尺及分辨率的設置參數(shù)。在MapTiles目錄中存放了0至5,6個層級的地圖瓦片數(shù)據(jù)。
? ? ? ?感興趣的讀者可以在main.js中修改地圖中心經緯度與地圖顯示層級的參數(shù)值,可以觀察地圖變化,如下圖所示:
“?本期文章附帶源碼下載地址”
鏈接:http://pan.baidu.com/s/1i526MXn??
密碼:ahda
本文轉自微信公眾號:OpenGiser的文章