package org.redcross.openmapkit.server; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; public class MBTiles { private SQLiteDatabase tilesDB; public MBTiles(String fileName) throws Exception { try { tilesDB = SQLiteDatabase.openDatabase(fileName, null, SQLiteDatabase.OPEN_READONLY); } catch(Exception ex) { Log.e("HTTPMBTiles", ex.toString()); throw (ex); } } private double[] getBoundsFromMetadata() { double[] bounds = null; String query = "SELECT value FROM metadata WHERE name = 'bounds'"; Cursor cursor = tilesDB.rawQuery(query, null); if (cursor.moveToFirst()) { // Use the bounds provided in the metadata String[] boundsStr = cursor.getString(0).split(",", 4); bounds = new double[4]; if (bounds.length == 4) { bounds[0] = Double.parseDouble(boundsStr[0]); // left bounds[1] = Double.parseDouble(boundsStr[1]); // bottom bounds[2] = Double.parseDouble(boundsStr[2]); // top bounds[3] = Double.parseDouble(boundsStr[3]); // right } } cursor.close(); return bounds; } private double[] calculateBounds() { double[] bounds = null; String query = "SELECT MIN(tile_column), " + "MAX(tile_column), " + "MIN(tile_row), " + "MAX(tile_row), " + "zoom_level " + "FROM tiles " + "WHERE zoom_level = (SELECT MIN(zoom_level) FROM tiles)"; Cursor cursor = tilesDB.rawQuery(query, null); if (cursor.moveToFirst()) { int zoomLevel = cursor.getInt(4); bounds = new double[4]; double[] southwest; double[] northeast; // The mbtiles as stored as TMS, flip y axis to do calculations int numRows = (1 << zoomLevel); southwest = GeoUtils.tile2deg(cursor.getInt(0), numRows - 1 - cursor.getInt(1), zoomLevel); northeast = GeoUtils.tile2deg(cursor.getInt(2), numRows - 1 - cursor.getInt(3), zoomLevel); bounds[0] = southwest[0]; bounds[1] = southwest[1]; bounds[2] = northeast[0]; bounds[3] = northeast[1]; } cursor.close(); return bounds; } public double[] getBounds() { double[] bounds = null; bounds = getBoundsFromMetadata(); if (bounds == null) { bounds = calculateBounds(); } return bounds; } public byte[] getTile(int z, int x, int y) throws Exception { // Most maps want Google tile schema, but MBTiles stores as TMS. // We have to flip the Y axis and ask for Y in TMS tile schema. int tmsY = (1 << z) - 1 - y; // (1 << z) is the same as Math.pow(2, z), but faster. String query = String.format( "SELECT tile_data " + "FROM tiles " + "WHERE zoom_level = %d AND tile_column = %d AND tile_row = %d", z, x, tmsY); Cursor imageCur = tilesDB.rawQuery(query, null); byte[] blob = null; if (imageCur.moveToFirst()) { blob = imageCur.getBlob(0); } imageCur.close(); return blob; } }