MBTiles vector tile source (#740)
Support offline vector maps (MBTiles, MVT, gzipped pbf)
This commit is contained in:
committed by
Emux
parent
83aed13683
commit
a9e18a2add
2
vtm-android-mvt/AndroidManifest.xml
Normal file
2
vtm-android-mvt/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<manifest package="org.oscim.android.mvt" />
|
||||
55
vtm-android-mvt/build.gradle
Normal file
55
vtm-android-mvt/build.gradle
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<String> 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<MvtTileDecoder> mThreadLocalDecoders = new ThreadLocal<MvtTileDecoder>() {
|
||||
@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<String> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user