diff --git a/settings.gradle b/settings.gradle
index 013d71c0..ddc74185 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,6 +3,7 @@ include ':vtm'
include ':vtm-android'
include ':vtm-android-example'
include ':vtm-android-gdx'
+include ':vtm-android-mvt'
include ':vtm-app'
include ':vtm-desktop'
include ':vtm-desktop-lwjgl'
diff --git a/vtm-android-example/AndroidManifest.xml b/vtm-android-example/AndroidManifest.xml
index 544e9a42..933ceab5 100644
--- a/vtm-android-example/AndroidManifest.xml
+++ b/vtm-android-example/AndroidManifest.xml
@@ -79,7 +79,10 @@
android:name=".MarkerOverlayActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
+
void or value
Now
Warning
- To run this sample activity, you need any MBTiles with filename test.mbtiles installed on storage.\n\nadb push file.mbtiles /sdcard/test.mbtiles
+ To run this sample activity, you need an MBTiles database installed on storage.\n\nadb push %s %s
Exit
diff --git a/vtm-android-example/src/org/oscim/android/test/MBTilesBitmapTileActivity.java b/vtm-android-example/src/org/oscim/android/test/MBTilesBitmapActivity.java
similarity index 78%
rename from vtm-android-example/src/org/oscim/android/test/MBTilesBitmapTileActivity.java
rename to vtm-android-example/src/org/oscim/android/test/MBTilesBitmapActivity.java
index 63057626..e49b0abf 100644
--- a/vtm-android-example/src/org/oscim/android/test/MBTilesBitmapTileActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/MBTilesBitmapActivity.java
@@ -1,6 +1,7 @@
/*
* Copyright 2019 Andrea Antonello
* Copyright 2019 devemux86
+ * Copyright 2019 Kostas Tzounopoulos
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -19,6 +20,7 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import org.oscim.android.tiling.source.mbtiles.MBTilesBitmapTileSource;
+import org.oscim.android.tiling.source.mbtiles.MBTilesTileSource;
import org.oscim.core.BoundingBox;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
@@ -27,19 +29,19 @@ import org.oscim.layers.tile.bitmap.BitmapTileLayer;
import java.io.File;
/**
- * An example activity making use of MBTiles.
+ * An example activity making use of raster MBTiles.
*/
-public class MBTilesBitmapTileActivity extends BitmapTileActivity {
+public class MBTilesBitmapActivity extends BitmapTileActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- File file = new File(getExternalFilesDir(null), "test.mbtiles");
+ File file = new File(getExternalFilesDir(null), "raster.mbtiles");
if (!file.exists()) {
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle(R.string.warning)
- .setMessage(R.string.startup_message_mbtiles)
+ .setMessage(getResources().getString(R.string.startup_message_mbtiles, file.getName(), file.getAbsolutePath()))
.setPositiveButton(R.string.exit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@@ -50,7 +52,8 @@ public class MBTilesBitmapTileActivity extends BitmapTileActivity {
return;
}
- MBTilesBitmapTileSource tileSource = new MBTilesBitmapTileSource(file.getAbsolutePath(), 128, null);
+ MBTilesTileSource tileSource = new MBTilesBitmapTileSource(file.getAbsolutePath(), 128, null);
+
BitmapTileLayer bitmapLayer = new BitmapTileLayer(mMap, tileSource);
mMap.layers().add(bitmapLayer);
@@ -58,7 +61,7 @@ public class MBTilesBitmapTileActivity extends BitmapTileActivity {
MapPosition pos = new MapPosition();
mMap.getMapPosition(pos);
if (pos.x == 0.5 && pos.y == 0.5) {
- BoundingBox bbox = tileSource.getBounds();
+ BoundingBox bbox = tileSource.getDataSource().getBounds();
if (bbox != null) {
pos.setByBoundingBox(bbox, Tile.SIZE * 4, Tile.SIZE * 4);
mMap.setMapPosition(pos);
diff --git a/vtm-android-example/src/org/oscim/android/test/MBTilesMvtActivity.java b/vtm-android-example/src/org/oscim/android/test/MBTilesMvtActivity.java
new file mode 100644
index 00000000..c5b4a31b
--- /dev/null
+++ b/vtm-android-example/src/org/oscim/android/test/MBTilesMvtActivity.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019 Andrea Antonello
+ * Copyright 2019 devemux86
+ * Copyright 2019 Kostas Tzounopoulos
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.test;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import org.oscim.android.mvt.tiling.source.mbtiles.MBTilesMvtTileSource;
+import org.oscim.android.tiling.source.mbtiles.MBTilesTileSource;
+import org.oscim.android.tiling.source.mbtiles.MBTilesUnsupportedException;
+import org.oscim.core.BoundingBox;
+import org.oscim.core.MapPosition;
+import org.oscim.core.Tile;
+import org.oscim.layers.tile.buildings.BuildingLayer;
+import org.oscim.layers.tile.vector.VectorTileLayer;
+import org.oscim.layers.tile.vector.labeling.LabelLayer;
+import org.oscim.theme.VtmThemes;
+
+import java.io.File;
+
+/**
+ * An example activity making use of vector MBTiles.
+ */
+public class MBTilesMvtActivity extends MapActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ File file = new File(getExternalFilesDir(null), "vector.mbtiles");
+ if (!file.exists()) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.warning)
+ .setMessage(getResources().getString(R.string.startup_message_mbtiles, file.getName(), file.getAbsolutePath()))
+ .setPositiveButton(R.string.exit, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ builder.show();
+ return;
+ }
+
+ MBTilesTileSource tileSource;
+ try {
+ tileSource = new MBTilesMvtTileSource(file.getAbsolutePath(), "en");
+ } catch (MBTilesUnsupportedException e) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.warning)
+ .setMessage(e.getMessage())
+ .setPositiveButton(R.string.exit, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ builder.show();
+ return;
+ }
+
+ VectorTileLayer l = mMap.setBaseMap(tileSource);
+ mMap.setTheme(VtmThemes.OPENMAPTILES);
+
+ mMap.layers().add(new BuildingLayer(mMap, l));
+ mMap.layers().add(new LabelLayer(mMap, l));
+
+ /* set initial position on first run */
+ MapPosition pos = new MapPosition();
+ mMap.getMapPosition(pos);
+ if (pos.x == 0.5 && pos.y == 0.5) {
+ BoundingBox bbox = tileSource.getDataSource().getBounds();
+ if (bbox != null) {
+ pos.setByBoundingBox(bbox, Tile.SIZE * 4, Tile.SIZE * 4);
+ mMap.setMapPosition(pos);
+ }
+ }
+ }
+}
diff --git a/vtm-android-example/src/org/oscim/android/test/Samples.java b/vtm-android-example/src/org/oscim/android/test/Samples.java
index 49112bbe..79fdd26b 100644
--- a/vtm-android-example/src/org/oscim/android/test/Samples.java
+++ b/vtm-android-example/src/org/oscim/android/test/Samples.java
@@ -9,6 +9,7 @@
* Copyright 2018 boldtrn
* Copyright 2018-2019 Gustl22
* Copyright 2019 Andrea Antonello
+ * Copyright 2019 Kostas Tzounopoulos
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
@@ -88,6 +89,7 @@ public class Samples extends Activity {
linearLayout.addView(createLabel(null));
linearLayout.addView(createButton(SimpleMapActivity.class));
linearLayout.addView(createButton(MapsforgeActivity.class));
+ linearLayout.addView(createButton(MBTilesMvtActivity.class));
linearLayout.addView(createButton(MapilionMvtActivity.class));
/*linearLayout.addView(createButton(MapzenMvtActivity.class));
linearLayout.addView(createButton(MapzenGeojsonActivity.class));
@@ -114,7 +116,7 @@ public class Samples extends Activity {
linearLayout.addView(createLabel("Raster Maps"));
linearLayout.addView(createButton(BitmapTileActivity.class));
- linearLayout.addView(createButton(MBTilesBitmapTileActivity.class));
+ linearLayout.addView(createButton(MBTilesBitmapActivity.class));
linearLayout.addView(createLabel("Overlays"));
linearLayout.addView(createButton(MarkerOverlayActivity.class));
diff --git a/vtm-android-mvt/AndroidManifest.xml b/vtm-android-mvt/AndroidManifest.xml
new file mode 100644
index 00000000..6a915c8c
--- /dev/null
+++ b/vtm-android-mvt/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/vtm-android-mvt/build.gradle b/vtm-android-mvt/build.gradle
new file mode 100644
index 00000000..b40c36b2
--- /dev/null
+++ b/vtm-android-mvt/build.gradle
@@ -0,0 +1,55 @@
+apply plugin: 'com.android.library'
+apply plugin: 'com.github.dcendents.android-maven'
+
+dependencies {
+ api project(':vtm-android')
+ api project(':vtm-mvt')
+}
+
+android {
+ compileSdkVersion androidCompileSdk()
+ buildToolsVersion "$androidBuildVersionTools"
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ defaultConfig {
+ versionCode project.versionCode()
+ versionName project.versionName()
+ minSdkVersion androidMinSdk()
+ targetSdkVersion androidTargetSdk()
+ }
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ }
+ debug.setRoot('build-types/debug')
+ release.setRoot('build-types/release')
+ }
+
+ lintOptions { abortOnError false }
+}
+
+android.libraryVariants.all { variant ->
+ def name = variant.buildType.name
+ if (name == "debug")
+ return
+
+ def jar = project.tasks.create "jar${name.capitalize()}", Jar
+ jar.dependsOn variant.javaCompileProvider
+ jar.exclude '**/BuildConfig.class'
+ jar.exclude '**/R.class'
+ jar.exclude '**/R$*.class'
+ jar.from variant.javaCompileProvider.get().destinationDir
+ artifacts.add('archives', jar)
+}
+
+if (project.hasProperty("SONATYPE_USERNAME")) {
+ afterEvaluate {
+ project.apply from: "${rootProject.projectDir}/deploy.gradle"
+ }
+}
diff --git a/vtm-android-mvt/src/org/oscim/android/mvt/tiling/source/mbtiles/MBTilesMvtTileDataSource.java b/vtm-android-mvt/src/org/oscim/android/mvt/tiling/source/mbtiles/MBTilesMvtTileDataSource.java
new file mode 100644
index 00000000..b6ed4f52
--- /dev/null
+++ b/vtm-android-mvt/src/org/oscim/android/mvt/tiling/source/mbtiles/MBTilesMvtTileDataSource.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2019 Kostas Tzounopoulos
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.mvt.tiling.source.mbtiles;
+
+import android.database.Cursor;
+import org.oscim.android.tiling.source.mbtiles.MBTilesTileDataSource;
+import org.oscim.android.tiling.source.mbtiles.MBTilesUnsupportedException;
+import org.oscim.core.MercatorProjection;
+import org.oscim.layers.tile.MapTile;
+import org.oscim.tiling.ITileDataSink;
+import org.oscim.tiling.OverzoomDataSink;
+import org.oscim.tiling.QueryResult;
+import org.oscim.tiling.source.mvt.MvtTileDecoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * A tile data source for MBTiles vector databases.
+ */
+public class MBTilesMvtTileDataSource extends MBTilesTileDataSource {
+
+ private static final Logger log = LoggerFactory.getLogger(MBTilesMvtTileDataSource.class);
+
+ private static final List SUPPORTED_FORMATS = Collections.singletonList("pbf");
+ private static final String WHERE_FORMAT = "zoom_level=%d AND tile_column=%d AND tile_row=%d";
+
+ private final String mLanguage;
+
+ private final ThreadLocal mThreadLocalDecoders = new ThreadLocal() {
+ @Override
+ protected MvtTileDecoder initialValue() {
+ return new MvtTileDecoder(mLanguage);
+ }
+ };
+
+ /**
+ * Create a tile data source for MBTiles vector databases.
+ *
+ * @param path the path to the MBTiles database.
+ * @param language the language to use when rendering the MBTiles.
+ */
+ public MBTilesMvtTileDataSource(String path, String language) {
+ super(path);
+ mLanguage = language != null ? language : "en";
+
+ try {
+ assertDatabaseFormat();
+ } catch (MBTilesUnsupportedException e) {
+ log.error("Invalid MBTiles database", e);
+ }
+ }
+
+ @Override
+ public void cancel() {
+ // do nothing
+ }
+
+ @Override
+ public void dispose() {
+ if (mDatabase != null && mDatabase.isOpen())
+ mDatabase.close();
+ }
+
+ @Override
+ public List getSupportedFormats() {
+ return SUPPORTED_FORMATS;
+ }
+
+ private MapTile mapTile(Cursor cursor) {
+ int tileX = cursor.getInt(cursor.getColumnIndexOrThrow("tile_column"));
+ int tileY = cursor.getInt(cursor.getColumnIndexOrThrow("tile_row"));
+ int zoomLevel = cursor.getInt(cursor.getColumnIndexOrThrow("zoom_level"));
+ long tmsTileY = MercatorProjection.tileYToTMS(tileY, (byte) zoomLevel);
+ return new MapTile(tileX, (int) tmsTileY, zoomLevel);
+ }
+
+ /**
+ * Overzoom on the DB layer: generate a query for all tiles with lower zoomLevel than the one requested.
+ */
+ private String overzoomQuery(MapTile tile) {
+ long tmsTileY = MercatorProjection.tileYToTMS(tile.tileY, tile.zoomLevel);
+ StringBuilder sb = new StringBuilder();
+ sb.append("(");
+ for (int zoomLevel = tile.zoomLevel - 1; zoomLevel > 0; zoomLevel--) {
+ int diff = tile.zoomLevel - zoomLevel;
+ sb.append(String.format(Locale.US, WHERE_FORMAT, zoomLevel, tile.tileX >> diff, tmsTileY >> diff));
+ if (zoomLevel > 1) // Not the last iteration
+ sb.append(") OR (");
+ }
+ sb.append(")");
+ return String.format(SELECT_TILES_FORMAT, sb.toString());
+ }
+
+ @Override
+ public void query(MapTile requestTile, ITileDataSink requestDataSink) {
+ Cursor cursor = null;
+ ITileDataSink responseDataSink = requestDataSink;
+ try {
+ long tmsTileY = MercatorProjection.tileYToTMS(requestTile.tileY, requestTile.zoomLevel);
+ cursor = mDatabase.rawQuery(String.format(SELECT_TILES_FORMAT, String.format(Locale.US, WHERE_FORMAT, requestTile.zoomLevel, requestTile.tileX, tmsTileY)), null);
+
+ if (cursor.getCount() == 0) {
+ cursor.close();
+ cursor = mDatabase.rawQuery(overzoomQuery(requestTile), null);
+ }
+
+ if (cursor.moveToFirst()) {
+ byte[] bytes = cursor.getBlob(cursor.getColumnIndexOrThrow("tile_data"));
+
+ MapTile responseTile = mapTile(cursor);
+ if (requestTile.zoomLevel != responseTile.zoomLevel)
+ responseDataSink = new OverzoomDataSink(requestDataSink, responseTile, requestTile);
+
+ boolean success = mThreadLocalDecoders.get().decode(responseTile, responseDataSink, new GZIPInputStream(new ByteArrayInputStream(bytes)));
+ responseDataSink.completed(success ? QueryResult.SUCCESS : QueryResult.FAILED);
+ } else
+ responseDataSink.completed(QueryResult.TILE_NOT_FOUND);
+ } catch (IOException e) {
+ responseDataSink.completed(QueryResult.FAILED);
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ }
+}
diff --git a/vtm-android-mvt/src/org/oscim/android/mvt/tiling/source/mbtiles/MBTilesMvtTileSource.java b/vtm-android-mvt/src/org/oscim/android/mvt/tiling/source/mbtiles/MBTilesMvtTileSource.java
new file mode 100644
index 00000000..9a66a9f4
--- /dev/null
+++ b/vtm-android-mvt/src/org/oscim/android/mvt/tiling/source/mbtiles/MBTilesMvtTileSource.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 Kostas Tzounopoulos
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.mvt.tiling.source.mbtiles;
+
+import org.oscim.android.tiling.source.mbtiles.MBTilesTileSource;
+
+/**
+ * A tile source for MBTiles vector databases.
+ */
+public class MBTilesMvtTileSource extends MBTilesTileSource {
+
+ /**
+ * Create a tile source for MBTiles vector databases.
+ *
+ * @param path the path to the MBTiles database.
+ */
+ public MBTilesMvtTileSource(String path) {
+ this(path, null);
+ }
+
+ /**
+ * Create a tile source for MBTiles vector databases.
+ *
+ * @param path the path to the MBTiles database.
+ * @param language the language to use when rendering the MBTiles.
+ */
+ public MBTilesMvtTileSource(String path, String language) {
+ super(new MBTilesMvtTileDataSource(path, language));
+ }
+}
diff --git a/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileDataSource.java b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileDataSource.java
index 8138c85f..7f12f4a3 100644
--- a/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileDataSource.java
+++ b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileDataSource.java
@@ -1,6 +1,7 @@
/*
* Copyright 2019 Andrea Antonello
* Copyright 2019 devemux86
+ * Copyright 2019 Kostas Tzounopoulos
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -16,144 +17,70 @@
package org.oscim.android.tiling.source.mbtiles;
import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.canvas.Bitmap;
-import org.oscim.core.BoundingBox;
import org.oscim.core.MercatorProjection;
import org.oscim.layers.tile.MapTile;
-import org.oscim.map.Viewport;
import org.oscim.tiling.ITileDataSink;
-import org.oscim.tiling.ITileDataSource;
import org.oscim.tiling.QueryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Arrays;
+import java.util.List;
/**
* A tile data source for MBTiles raster databases.
*/
-public class MBTilesBitmapTileDataSource implements ITileDataSource {
+public class MBTilesBitmapTileDataSource extends MBTilesTileDataSource {
private static final Logger log = LoggerFactory.getLogger(MBTilesBitmapTileDataSource.class);
- private static final String TABLE_TILES = "tiles";
- private static final String COL_TILES_ZOOM_LEVEL = "zoom_level";
- private static final String COL_TILES_TILE_COLUMN = "tile_column";
- private static final String COL_TILES_TILE_ROW = "tile_row";
- private static final String COL_TILES_TILE_DATA = "tile_data";
- private static final String SELECT_TILES = "SELECT " + COL_TILES_TILE_DATA + " from " + TABLE_TILES + " where "
- + COL_TILES_ZOOM_LEVEL + "=? AND " + COL_TILES_TILE_COLUMN + "=? AND " + COL_TILES_TILE_ROW + "=?";
-
- private static final String TABLE_METADATA = "metadata";
- private static final String COL_METADATA_NAME = "name";
- private static final String COL_METADATA_VALUE = "value";
- private static final String SELECT_METADATA = "select " + COL_METADATA_NAME + "," + COL_METADATA_VALUE + " from "
- + TABLE_METADATA;
+ private static final List SUPPORTED_FORMATS = Arrays.asList("png", "jpg", "jpeg");
private final Integer mAlpha;
- private final SQLiteDatabase mDatabase;
- private Map mMetadata;
private final Integer mTransparentColor;
/**
- * Create a MBTiles tile data source.
+ * Create a tile data source for MBTiles raster databases.
*
* @param path the path to the MBTiles database.
* @param alpha an optional alpha value [0-255] to make the tiles transparent.
* @param transparentColor an optional color that will be made transparent in the bitmap.
*/
- MBTilesBitmapTileDataSource(String path, Integer alpha, Integer transparentColor) {
- mDatabase = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
+ public MBTilesBitmapTileDataSource(String path, Integer alpha, Integer transparentColor) {
+ super(path);
mAlpha = alpha;
mTransparentColor = transparentColor;
+
+ try {
+ assertDatabaseFormat();
+ } catch (MBTilesUnsupportedException e) {
+ log.error("Invalid MBTiles database", e);
+ }
}
@Override
public void cancel() {
- mDatabase.close();
+ if (mDatabase != null && mDatabase.isOpen())
+ mDatabase.close();
}
@Override
public void dispose() {
- mDatabase.close();
+ if (mDatabase != null && mDatabase.isOpen())
+ mDatabase.close();
}
- String getAttribution() {
- return getMetadata().get("attribution");
- }
-
- BoundingBox getBounds() {
- String bounds = getMetadata().get("bounds");
- if (bounds != null) {
- String[] split = bounds.split(",");
- double w = Double.parseDouble(split[0]);
- double s = Double.parseDouble(split[1]);
- double e = Double.parseDouble(split[2]);
- double n = Double.parseDouble(split[3]);
- return new BoundingBox(s, w, n, e);
- }
- return null;
- }
-
- public String getDescription() {
- return getMetadata().get("description");
- }
-
- /**
- * @return the image format (jpg, png)
- */
- public String getFormat() {
- return getMetadata().get("format");
- }
-
- int getMaxZoom() {
- String maxZoom = getMetadata().get("maxzoom");
- if (maxZoom != null)
- return Integer.parseInt(maxZoom);
- return Viewport.MAX_ZOOM_LEVEL;
- }
-
- private Map getMetadata() {
- if (mMetadata == null) {
- mMetadata = new HashMap<>();
- Cursor cursor = null;
- try {
- cursor = mDatabase.rawQuery(SELECT_METADATA, null);
- while (cursor.moveToNext()) {
- String key = cursor.getString(0);
- String value = cursor.getString(1);
- mMetadata.put(key, value);
- }
- } finally {
- if (cursor != null)
- cursor.close();
- }
- }
- return mMetadata;
- }
-
- int getMinZoom() {
- String minZoom = getMetadata().get("minzoom");
- if (minZoom != null)
- return Integer.parseInt(minZoom);
- return Viewport.MIN_ZOOM_LEVEL;
- }
-
- String getName() {
- return getMetadata().get("name");
- }
-
- public String getVersion() {
- return getMetadata().get("version");
+ @Override
+ public List getSupportedFormats() {
+ return SUPPORTED_FORMATS;
}
private static android.graphics.Bitmap processAlpha(android.graphics.Bitmap bitmap, int alpha) {
@@ -216,9 +143,9 @@ public class MBTilesBitmapTileDataSource implements ITileDataSource {
Cursor cursor = null;
try {
long tmsTileY = MercatorProjection.tileYToTMS(tileY, zoomLevel);
- cursor = mDatabase.rawQuery(SELECT_TILES, new String[]{String.valueOf(zoomLevel), String.valueOf(tileX), String.valueOf(tmsTileY)});
+ cursor = mDatabase.rawQuery(String.format(MBTilesTileDataSource.SELECT_TILES_FORMAT, MBTilesTileDataSource.WHERE_FORMAT), new String[]{String.valueOf(zoomLevel), String.valueOf(tileX), String.valueOf(tmsTileY)});
if (cursor.moveToFirst())
- return cursor.getBlob(0);
+ return cursor.getBlob(cursor.getColumnIndexOrThrow("tile_data"));
} finally {
if (cursor != null)
cursor.close();
diff --git a/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileSource.java b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileSource.java
index c37ed377..90c177ec 100644
--- a/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileSource.java
+++ b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesBitmapTileSource.java
@@ -1,6 +1,7 @@
/*
* Copyright 2019 Andrea Antonello
* Copyright 2019 devemux86
+ * Copyright 2019 Kostas Tzounopoulos
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,19 +16,13 @@
*/
package org.oscim.android.tiling.source.mbtiles;
-import org.oscim.core.BoundingBox;
-import org.oscim.tiling.ITileDataSource;
-import org.oscim.tiling.TileSource;
-
/**
* A tile source for MBTiles raster databases.
*/
-public class MBTilesBitmapTileSource extends TileSource {
-
- private final MBTilesBitmapTileDataSource mTileDataSource;
+public class MBTilesBitmapTileSource extends MBTilesTileSource {
/**
- * Create a MBTiles tile source.
+ * Create a tile source for MBTiles raster databases.
*
* @param path the path to the MBTiles database.
*/
@@ -36,64 +31,13 @@ public class MBTilesBitmapTileSource extends TileSource {
}
/**
- * Create a MBTiles tile source.
+ * Create a tile source for MBTiles raster databases.
*
* @param path the path to the MBTiles database.
* @param alpha an optional alpha value [0-255] to make the tiles transparent.
* @param transparentColor an optional color that will be made transparent in the bitmap.
*/
public MBTilesBitmapTileSource(String path, Integer alpha, Integer transparentColor) {
- mTileDataSource = new MBTilesBitmapTileDataSource(path, alpha, transparentColor);
- }
-
- @Override
- public void close() {
- mTileDataSource.dispose();
- }
-
-
- public String getAttribution() {
- return mTileDataSource.getAttribution();
- }
-
- public BoundingBox getBounds() {
- return mTileDataSource.getBounds();
- }
-
- @Override
- public ITileDataSource getDataSource() {
- return mTileDataSource;
- }
-
- public String getDescription() {
- return mTileDataSource.getDescription();
- }
-
- /**
- * @return the image format (jpg, png)
- */
- public String getFormat() {
- return mTileDataSource.getFormat();
- }
-
- public int getMaxZoom() {
- return mTileDataSource.getMaxZoom();
- }
-
- public int getMinZoom() {
- return mTileDataSource.getMinZoom();
- }
-
- public String getName() {
- return mTileDataSource.getName();
- }
-
- public String getVersion() {
- return mTileDataSource.getVersion();
- }
-
- @Override
- public OpenResult open() {
- return OpenResult.SUCCESS;
+ super(new MBTilesBitmapTileDataSource(path, alpha, transparentColor));
}
}
diff --git a/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesTileDataSource.java b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesTileDataSource.java
new file mode 100644
index 00000000..f39b406c
--- /dev/null
+++ b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesTileDataSource.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2019 Andrea Antonello
+ * Copyright 2019 devemux86
+ * Copyright 2019 Kostas Tzounopoulos
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.tiling.source.mbtiles;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.text.TextUtils;
+import org.oscim.core.BoundingBox;
+import org.oscim.core.MapPosition;
+import org.oscim.map.Viewport;
+import org.oscim.tiling.ITileDataSource;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A tile data source for MBTiles databases.
+ */
+public abstract class MBTilesTileDataSource implements ITileDataSource {
+
+ private static final String SELECT_METADATA = "SELECT name, value FROM metadata";
+ protected static final String SELECT_TILES_FORMAT =
+ "SELECT zoom_level, tile_column, tile_row, tile_data " +
+ "FROM tiles " +
+ "WHERE %s " +
+ "ORDER BY zoom_level DESC " +
+ "LIMIT 1";
+ static final String WHERE_FORMAT = "zoom_level=? AND tile_column=? AND tile_row=?";
+
+ protected final SQLiteDatabase mDatabase;
+ private Map mMetadata;
+
+ public MBTilesTileDataSource(String path) {
+ mDatabase = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
+ }
+
+ protected void assertDatabaseFormat() {
+ String format = getFormat();
+
+ if (format == null)
+ throw new RuntimeException("'metadata.format' field was not found. Is this an MBTiles database?");
+
+ List supportedFormats = getSupportedFormats();
+ if (!supportedFormats.contains(format))
+ throw new MBTilesUnsupportedException(String.format("Unsupported MBTiles 'metadata.format: %s'. Supported format(s) are: %s", format, TextUtils.join(", ", supportedFormats)));
+ }
+
+ public String getAttribution() {
+ return getMetadata().get("attribution");
+ }
+
+ public BoundingBox getBounds() {
+ String bounds = getMetadata().get("bounds");
+ if (bounds == null)
+ return null;
+ String[] split = bounds.split(",");
+ double w = Double.parseDouble(split[0]);
+ double s = Double.parseDouble(split[1]);
+ double e = Double.parseDouble(split[2]);
+ double n = Double.parseDouble(split[3]);
+ return new BoundingBox(s, w, n, e);
+ }
+
+ public MapPosition getCenter() {
+ String center = getMetadata().get("center");
+ if (center == null)
+ return null;
+ String[] split = center.split(",");
+ double latitude = Double.parseDouble(split[1]);
+ double longitude = Double.parseDouble(split[0]);
+ int zoomLevel = Integer.parseInt(split[2]);
+ return new MapPosition(latitude, longitude, 1 << zoomLevel);
+ }
+
+ public String getDescription() {
+ return getMetadata().get("description");
+ }
+
+ public String getFormat() {
+ return getMetadata().get("format");
+ }
+
+ public String getId() {
+ return getMetadata().get("id");
+ }
+
+ public String getJson() {
+ return getMetadata().get("json");
+ }
+
+ public int getMaxZoom() {
+ String maxZoom = getMetadata().get("maxzoom");
+ return maxZoom != null ? Integer.parseInt(maxZoom) : Viewport.MAX_ZOOM_LEVEL;
+ }
+
+ private Map getMetadata() {
+ if (mMetadata == null) {
+ mMetadata = new HashMap<>();
+ Cursor cursor = null;
+ try {
+ cursor = mDatabase.rawQuery(SELECT_METADATA, null);
+ while (cursor.moveToNext()) {
+ String key = cursor.getString(0);
+ String value = cursor.getString(1);
+ mMetadata.put(key, value);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ }
+ return mMetadata;
+ }
+
+ public int getMinZoom() {
+ String minZoom = getMetadata().get("minzoom");
+ return minZoom != null ? Integer.parseInt(minZoom) : Viewport.MIN_ZOOM_LEVEL;
+ }
+
+ public Long getMTime() {
+ String mTime = getMetadata().get("mtime");
+ return mTime != null ? Long.parseLong(mTime) : null;
+ }
+
+ public String getName() {
+ return getMetadata().get("name");
+ }
+
+ public Integer getPixelScale() {
+ String pixelScale = getMetadata().get("pixel_scale");
+ return pixelScale != null ? Integer.parseInt(pixelScale) : null;
+ }
+
+ abstract public List getSupportedFormats();
+
+ public String getVersion() {
+ return getMetadata().get("version");
+ }
+}
diff --git a/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesTileSource.java b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesTileSource.java
new file mode 100644
index 00000000..828f45d7
--- /dev/null
+++ b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesTileSource.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 Andrea Antonello
+ * Copyright 2019 devemux86
+ * Copyright 2019 Kostas Tzounopoulos
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.tiling.source.mbtiles;
+
+import org.oscim.tiling.TileSource;
+
+/**
+ * A tile source for MBTiles databases.
+ */
+public abstract class MBTilesTileSource extends TileSource {
+
+ private final MBTilesTileDataSource mTileDataSource;
+
+ public MBTilesTileSource(MBTilesTileDataSource tileDataSource) {
+ mTileDataSource = tileDataSource;
+ }
+
+ @Override
+ public void close() {
+ getDataSource().dispose();
+ }
+
+ @Override
+ public MBTilesTileDataSource getDataSource() {
+ return mTileDataSource;
+ }
+
+ @Override
+ public OpenResult open() {
+ return OpenResult.SUCCESS;
+ }
+}
diff --git a/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesUnsupportedException.java b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesUnsupportedException.java
new file mode 100644
index 00000000..f63c2b3f
--- /dev/null
+++ b/vtm-android/src/org/oscim/android/tiling/source/mbtiles/MBTilesUnsupportedException.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2019 Kostas Tzounopoulos
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.tiling.source.mbtiles;
+
+public class MBTilesUnsupportedException extends RuntimeException {
+ public MBTilesUnsupportedException(String message) {
+ super(message);
+ }
+}
diff --git a/vtm/src/org/oscim/tiling/OverzoomDataSink.java b/vtm/src/org/oscim/tiling/OverzoomDataSink.java
index 99748d6b..f72b26dc 100644
--- a/vtm/src/org/oscim/tiling/OverzoomDataSink.java
+++ b/vtm/src/org/oscim/tiling/OverzoomDataSink.java
@@ -22,7 +22,7 @@ import org.oscim.core.Tile;
import org.oscim.utils.geom.TileClipper;
import org.oscim.utils.geom.TileSeparator;
-class OverzoomDataSink implements ITileDataSink {
+public class OverzoomDataSink implements ITileDataSink {
private final ITileDataSink sink;
@@ -30,7 +30,7 @@ class OverzoomDataSink implements ITileDataSink {
private final TileSeparator separator;
private final float dx, dy, scale;
- OverzoomDataSink(ITileDataSink sink, Tile overzoomTile, Tile tile) {
+ public OverzoomDataSink(ITileDataSink sink, Tile overzoomTile, Tile tile) {
this.sink = sink;
int diff = tile.zoomLevel - overzoomTile.zoomLevel;