iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
Mobile Development

Google Maps SDK for Android 與 GIS App 開發筆記系列 第 11

Day 11: Google Maps SDK for Android–離線圖層套疊 MBTiles

  • 分享至 

  • xImage
  •  

前言

昨天看完 WMTS 的圖層套疊,今天我們要來看離線 GIS 系統常用的 MBTiles 離線圖資。

MBtiles 格式說明

就如同第二天在介紹 GIS 資料格式的文章中所說過的,MBTiles 其實是一個 SQLite 中包含圖磚檔案(Blob),與該圖磚對應的階層資訊。

不同圖台廠商發行的 MBTiles 規格略有不同,但基本上一定會有一張 tiles 的資料表,並包含以下欄位:

  1. zoom_level: 該圖磚的所屬層級。
  2. tile_column: 圖磚於網格系統上的 x 軸位置
  3. tile_row: 圖磚於網格系統上的 y 軸位置
  4. tile_data: 圖磚 Blob

參考資料

  1. MapBox: MBtiles spec 1.3
  2. 國土測繪離線地圖mbtiles

範例用 Mbtiles

今天我們使用的範例檔案--臺灣通用電子地圖(不含等高線)MBTiles 檔,一樣是由國土測繪服務雲所提供的,檔名是 TaiwanEMap6.mbtiles,請到這個連結下載。

https://ithelp.ithome.com.tw/upload/images/20230925/20160271GBp5TttMG4.png

使用 DB Browser for SQLite 檢視格式內容

為了讓各位看看他的格式,比較簡單的方法是下載這個專門讀取 SQLite 檔案的 DB Browser for SQLite

安裝完畢並開啟檔案,就會發現裡面的 tiles 資料表,真的就如上面的格式說明,擁有那四個欄位。

https://ithelp.ithome.com.tw/upload/images/20230925/201602718cIIvu1dJ0.png

使用 QGIS 檢視套疊效果

如果想實際看看套疊出來的效果,也可以使用 QGIS 這套開源的 GIS 軟體來開啟 MBTiles。

https://ithelp.ithome.com.tw/upload/images/20230925/20160271v8g4N3Yz3p.png

實作

跟 WMTS 套疊一樣,因為都是圖磚形式的呈現,所以使用的都是 TileProvider 這個類別。所以整體實作邏輯大同小異,差別在於原本從網路讀取的圖片,改由 Local MBTiles 讀出。而又因為 MBTiles 屬於 SQLite 格式,所以整個邏輯會是:

  1. 將 MBTiles 讀入至 App 的資料夾內。
  2. SQLiteDatabase 開啟 MBTiles
  3. 實作 TileProvider,並在 getTile() 中執行 SQL Query 讀取出正確的檔案。

將 MBTiles 讀入至 App 內屬於基本的檔案 IO,在範例中就不贅述,以下範例將重點放在取得檔案 SQLite 連線後,如何轉換為 Tile

SQLiteDatabase 讀取 MBTiles

class MBTileSQLiteDatabase(private val dbFilePath: String) {

    private val database: SQLiteDatabase by lazy {
        SQLiteDatabase.openDatabase(dbFilePath, null, SQLiteDatabase.OPEN_READONLY)
    }

    fun getTileBlob(x: Int, y: Int, zoom: Int): ByteArray? {
        val sql =
            "SELECT tile_data FROM tiles WHERE zoom_level = $zoom AND tile_column = $x AND tile_row = $y"
        Log.d("TAG", "getTileBlob: $sql")
        database.rawQuery(sql, null).use { cursor ->
            if (cursor != null && cursor.count > 0) {
                cursor.moveToFirst()
                return cursor.getBlob(0)
            }
        }

        return null
    }
}

建立 OfflineTileProvider

class OfflineTileProvider(private val database: MBTileSQLiteDatabase): TileProvider {
    private val TAG: String = OfflineTileProvider::class.java.simpleName
    override fun getTile(x: Int, y: Int, zoom: Int): Tile? {
        // 國土測繪的圖資需要做這個 Y 軸的轉換才能正常顯示 不確定原因
        val yMax = 1 shl zoom
        val convertY = yMax - y - 1

        val blob = try {
            database.getTileBlob(x, convertY, zoom)
        } catch (e: Exception) {
            Log.e(TAG, "getTile: ", e)
            null
        }
        return if (blob != null) {
            Tile(256, 256, blob)
        } else {
            null
        }
    }
}

有關 Y 軸的轉換,查了 Google Maps 的 Sample 雖然有實作成功。但沒有很清楚其背後的原理,礙於文章長度與時間,先將以下幾篇查到的資料整理在下方,待有空再回來消化。

導入至地圖上

private fun setMbtilesTileOverlay(map: GoogleMap): TileOverlay? {
    // 建立 MBTiles 來源
    val database = MBTileSQLiteDatabase(application.filesDir.absolutePath + "/TaiwanEMap6.mbtiles")
    val provider = OfflineTileProvider(database)

    // 建立 MBTiles 圖層設定
    val tileOverlayOptions =
        TileOverlayOptions().tileProvider(provider)

    // 將圖層加入到圖台上
    return map.addTileOverlay(tileOverlayOptions)
}

https://ithelp.ithome.com.tw/upload/images/20230925/201602712XdrVMgaV2.png

小結

以上就是 MBTiles 在 Google Maps SDK 上的基本套疊方式。因為都是圖磚的形式,實作的大方向上跟昨天的 WMTS 大同小異。

那就一樣明天見啦 /images/emoticon/emoticon08.gif


上一篇
Day 10: Google Maps SDK for Android–線上圖層套疊 WMTS
下一篇
Day 12: Google Maps SDK for Android –Marker 標記與互動事件
系列文
Google Maps SDK for Android 與 GIS App 開發筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言