計算MKMapView的zoomLevel(地圖縮放等級)

背景及問題分析

在一些第三方的地圖 SDK 中,每每會有 zoomLevel 這樣一個屬性,經常使用於設置地圖的縮放等級。git

可是在 iOS 自帶的地圖控件 MKMapView 是沒有這樣一個屬性的。取而代之的是利用 MKCoordinateRegionMKCoordinateSpan 來配置地圖顯示的中心和區域縮放的大小。web

MKCoordinateRegion 和 MKCoordinateSpan

咱們先來看看 MKCoordinateRegionMKCoordinateSpan 的這兩個初始化方法:算法

MKCoordinateRegion(center: CLLocationCoordinate2D, span: MKCoordinateSpan)
MKCoordinateSpan(latitudeDelta: CLLocationDegrees, longitudeDelta: CLLocationDegrees)
複製代碼

結合 文檔 ,咱們能夠將 MKCoordinateRegion 理解爲地圖上一塊方形區域, center 是這塊方形區域的中心地理座標,而 MKCoordinateSpan 是這塊區域的 經緯度範圍,那麼它的兩個參數的取值範圍是:bash

  • latitudeDelta:[0, 180]
  • longitudeDelta: [0, 360]

Tiled web map

瞭解了 MKCoordinateRegionMKCoordinateSpan 後,咱們該如何利用它們來計算出 zoomLevel 呢?這裏咱們須要先了解一下 Tiled web map 這個概念。Tiled web map 的設計初衷是爲了能在網絡上更好的傳輸和展現地圖,其中最先應用起來的是 Google Maps, 而後慢慢地成爲了地圖工具中一個不成文的標準。它把地圖以圖片的形式切割成不少個小塊: Tile,當用戶在地圖上滑動或者縮放時,就會加載更多的 Tile,對比之前直接加載一大塊圖片的方式效率更高,用戶體驗更好。網絡

大部分的 Tiled web map 會依據 Google Maps 的一些實現標準:app

  • 一個 Tile 是 256x256 像素。
  • zoom Level 爲 0 時,整個世界地圖能夠顯示在單個 Tile 上。
  • 每增長一個地圖縮放等級,一個 Tile 的像素會加倍。也就是說一個 Tile 會被四個 Tile 替換掉。

上面原圖片來自 troybrant.net,由原圖拼接而成。ide

根據上面的標準,咱們能夠得出這樣一個公式:工具

W=256 \times 2^{zoomlevel}

W 表示地圖一邊長的像素。ui

zoomLevel 算法解析

咱們知道地球經度一週360度,那麼一個經度範圍佔 Tiled web map 的多少像素呢?簡單的除法能夠得知:spa

\frac{360}{256 \times 2^{zoomlevel}}

上面說到 MKCoordinateSpan 它表示地圖顯示區域的 經緯度範圍,假設咱們把 MKMapView 的寬度設置爲 width, 而 MKCoordinateSpan.longitudeDelta 是當前 MKMapView 顯示區域的經度範圍。那麼咱們能夠獲得這樣一個等式:

\frac{360}{256 \times 2^{zoomlevel}} = \frac{longitudeDelta}{width}

一個簡單的轉換,便可得出 zoomLevel 的計算公式:

zoomLevel = log_2{\frac{360 \times width}{longitudeDelta \times 256}}

示例代碼

用代碼形式展現:

let mapWidth = mapView.frame.size.width
let zoomLevel = log2(360 * Double(mapWidth) / 256.0 / mapView.region.span.longitudeDelta)
複製代碼

咱們還能夠給 MKMapView 擴展一下:

extension MKMapView {
    var zoomLevel: Double {
        return log2(360 * Double(frame.size.width) / 256.0 / region.span.longitudeDelta)
    }
}
複製代碼

參考資料

相關文章
相關標籤/搜索