前幾篇介紹了一些國內地圖的案例,
我們以Google地圖為例,這章介紹下地圖加載的原理。
投影(Projection)
谷歌地圖采用的是墨卡托投影法,這里轉載(http://www.cnblogs.com/willwayer/archive/2010/06/11/1756446.html)下墨卡托投影的定義:墨卡托(Mercator)投影,又名“等角正軸圓柱投影”,荷蘭地圖學家墨卡托(Mercator)在1569年擬定,假設地球被圍在一個中空的圓柱里,其赤道與圓柱相接觸,然后再假想地球中心有一盞燈,把球面上的圖形投影到圓柱體上,再把圓柱體展開,這就是一幅標准緯線為零度(即赤道)的“墨卡托投影”繪制出的世界地圖。從球到平面,有個轉換公式,這里就不再羅列。
可以看到, 谷歌將整個地圖被鋪成了一張偌大的正方形,所以只要將這個偌大的正方形按照圖層分成若干的小圖就可以了。
圖層(Zoom)和圖片(Tile)
在墨卡托投影法的基礎上,整個谷歌地圖被分為18層(Zoom):0~17。每次操作(縮放)谷歌地圖的時候,都會將可見區域的圖層的圖片加載進來,所以,每個圖層都是由一張張圖片組成的,
下面Chrome瀏覽器的開發工具就可以看到:
每張圖片稱為Tile, 代碼中經常可以看到這個變量,每一圖層的圖片數量Tiles = 2 pow (2*Zoom)。
那么第一個圖層的圖片數量為: 2 pow (2*0) = 1
第2個圖層的圖片數量為 2 pow(2*1) = 4
.....
第17個圖層的圖片數量為 2 pow (2 * 17) = 17179869184
經緯度(Lat,Lng)和網格(Grid)
那么,谷歌是如何根據當前的視圖來獲取圖片的呢?谷歌的做法(其他地圖也一樣)是將地圖根據墨托卡投射法分成若干的網格,每個網格都是一張圖片。
那么只要將當前的經緯度轉換成網格就可以。具體的公式就不列了,懶得看,這里有段代碼,
TileCoordinate locationCoord(double lat, double lon, int zoom) ,lat,lon就是當前經緯度,zoom就是圖層,最后就只要知道row和colum就可以了。
public class TileCoordinate { public TileCoordinate(double row, double column, int zoom) { this.row = row; this.column = column; this.zoom = zoom; } public double row; public double column; public int zoom; } static TileCoordinate locationCoord(double lat, double lon, int zoom) { if (System.Math.Abs(lat) > 85.0511287798066) return null; double sin_phi = System.Math.Sin(lat * System.Math.PI / 180); double norm_x = lon / 180; double norm_y = (0.5 * System.Math.Log((1 + sin_phi) / (1 - sin_phi))) / System.Math.PI; double tileRow = System.Math.Pow(2, zoom) * ((1 - norm_y) / 2); double tileColumn = System.Math.Pow(2, zoom) * ((norm_x + 1) / 2); return new TileCoordinate(tileRow, tileColumn, zoom); }
好的,拿到這個row和column有什么用呢,我們看一個例子:
http://mt2.google.cn/vt/lyrs=m@205000000&hl=zh-CN&gl=CN&src=app&x=22&y=12&z=5&s=Galile,返回的圖片如下:
其中x=22, y=12就是前面提到的row和col,而z=5就是當前的縮放級別(圖層),其他的參數都是表示版本和狀態的,相對固定。
上面的原理講完了,國內的地圖或許稍有不同,但大致思路都是一致的。