diff --git a/docs/Changelog.md b/docs/Changelog.md index c009485d..823b29d5 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -4,6 +4,7 @@ - S3DB layer [#475](https://github.com/mapsforge/vtm/pull/475) - vtm-mvt module with MVT tile decoder [#481](https://github.com/mapsforge/vtm/pull/481) +- Nextzen MVT / GeoJSON vector tiles [#498](https://github.com/mapsforge/vtm/issues/498) - OpenMapTiles MVT vector tiles [#482](https://github.com/mapsforge/vtm/issues/482) - Render themes: symbols on lines [#495](https://github.com/mapsforge/vtm/issues/495) - Render themes: styles improvements [#479](https://github.com/mapsforge/vtm/pull/479) diff --git a/vtm-android-example/AndroidManifest.xml b/vtm-android-example/AndroidManifest.xml index f83ee1b0..eac58d63 100644 --- a/vtm-android-example/AndroidManifest.xml +++ b/vtm-android-example/AndroidManifest.xml @@ -84,6 +84,12 @@ + + diff --git a/vtm-android-example/src/org/oscim/android/test/NextzenGeojsonActivity.java b/vtm-android-example/src/org/oscim/android/test/NextzenGeojsonActivity.java new file mode 100644 index 00000000..a6abd99e --- /dev/null +++ b/vtm-android-example/src/org/oscim/android/test/NextzenGeojsonActivity.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 devemux86 + * + * 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.os.Bundle; + +import org.oscim.android.cache.TileCache; +import org.oscim.layers.TileGridLayer; +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 org.oscim.tiling.source.OkHttpEngine; +import org.oscim.tiling.source.UrlTileSource; +import org.oscim.tiling.source.geojson.NextzenGeojsonTileSource; + +public class NextzenGeojsonActivity extends MapActivity { + + private static final boolean USE_CACHE = false; + + private TileCache mCache; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + UrlTileSource tileSource = NextzenGeojsonTileSource.builder() + .apiKey("xxxxxxx") // Put a proper API key + .httpFactory(new OkHttpEngine.OkHttpFactory()) + //.locale("en") + .build(); + + if (USE_CACHE) { + // Cache the tiles into a local SQLite database + mCache = new TileCache(this, null, "tile.db"); + mCache.setCacheSize(512 * (1 << 10)); + tileSource.setCache(mCache); + } + + VectorTileLayer l = mMap.setBaseMap(tileSource); + mMap.setTheme(VtmThemes.MAPZEN); + + mMap.layers().add(new BuildingLayer(mMap, l)); + mMap.layers().add(new LabelLayer(mMap, l)); + + mMap.layers().add(new TileGridLayer(mMap, getResources().getDisplayMetrics().density)); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + if (mCache != null) + mCache.dispose(); + } +} diff --git a/vtm-android-example/src/org/oscim/android/test/NextzenMvtActivity.java b/vtm-android-example/src/org/oscim/android/test/NextzenMvtActivity.java new file mode 100644 index 00000000..8da1cd14 --- /dev/null +++ b/vtm-android-example/src/org/oscim/android/test/NextzenMvtActivity.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 devemux86 + * + * 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.os.Bundle; + +import org.oscim.android.cache.TileCache; +import org.oscim.layers.TileGridLayer; +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 org.oscim.tiling.source.OkHttpEngine; +import org.oscim.tiling.source.UrlTileSource; +import org.oscim.tiling.source.mvt.NextzenMvtTileSource; + +public class NextzenMvtActivity extends MapActivity { + + private static final boolean USE_CACHE = false; + + private TileCache mCache; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + UrlTileSource tileSource = NextzenMvtTileSource.builder() + .apiKey("xxxxxxx") // Put a proper API key + .httpFactory(new OkHttpEngine.OkHttpFactory()) + //.locale("en") + .build(); + + if (USE_CACHE) { + // Cache the tiles into a local SQLite database + mCache = new TileCache(this, null, "tile.db"); + mCache.setCacheSize(512 * (1 << 10)); + tileSource.setCache(mCache); + } + + VectorTileLayer l = mMap.setBaseMap(tileSource); + mMap.setTheme(VtmThemes.MAPZEN); + + mMap.layers().add(new BuildingLayer(mMap, l)); + mMap.layers().add(new LabelLayer(mMap, l)); + + mMap.layers().add(new TileGridLayer(mMap, getResources().getDisplayMetrics().density)); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + if (mCache != null) + mCache.dispose(); + } +} 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 5200ee1a..cf0ae791 100644 --- a/vtm-android-example/src/org/oscim/android/test/Samples.java +++ b/vtm-android-example/src/org/oscim/android/test/Samples.java @@ -83,6 +83,8 @@ public class Samples extends Activity { linearLayout.addView(createButton(MapsforgeActivity.class)); /*linearLayout.addView(createButton(MapzenMvtActivity.class)); linearLayout.addView(createButton(MapzenGeojsonActivity.class));*/ + linearLayout.addView(createButton(NextzenMvtActivity.class)); + linearLayout.addView(createButton(NextzenGeojsonActivity.class)); linearLayout.addView(createButton(OpenMapTilesMvtActivity.class)); linearLayout.addView(createButton(GdxActivity.class)); diff --git a/vtm-json/src/org/oscim/tiling/source/geojson/NextzenGeojsonTileSource.java b/vtm-json/src/org/oscim/tiling/source/geojson/NextzenGeojsonTileSource.java new file mode 100644 index 00000000..cb6b2935 --- /dev/null +++ b/vtm-json/src/org/oscim/tiling/source/geojson/NextzenGeojsonTileSource.java @@ -0,0 +1,123 @@ +/* + * Copyright 2018 devemux86 + * + * 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.tiling.source.geojson; + +import org.oscim.core.MapElement; +import org.oscim.core.Tag; +import org.oscim.tiling.source.UrlTileSource; +import org.oscim.utils.math.MathUtils; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class NextzenGeojsonTileSource extends GeojsonTileSource { + + private final static String DEFAULT_URL = "https://tile.nextzen.org/tilezen/vector/v1/all"; + private final static String DEFAULT_PATH = "/{Z}/{X}/{Y}.json"; + + public static class Builder> extends UrlTileSource.Builder { + private String locale = ""; + + public Builder() { + super(DEFAULT_URL, DEFAULT_PATH, 1, 17); + keyName("api_key"); + } + + public T locale(String locale) { + this.locale = locale; + return self(); + } + + public NextzenGeojsonTileSource build() { + return new NextzenGeojsonTileSource(this); + } + } + + @SuppressWarnings("rawtypes") + public static Builder builder() { + return new Builder(); + } + + private static Map mappings = new LinkedHashMap<>(); + + private static Tag addMapping(String key, String val) { + Tag tag = new Tag(key, val); + mappings.put(key + "=" + val, tag); + return tag; + } + + private final String locale; + + public NextzenGeojsonTileSource(Builder builder) { + super(builder); + this.locale = builder.locale; + } + + public NextzenGeojsonTileSource() { + this(builder()); + } + + public NextzenGeojsonTileSource(String urlString) { + this(builder().url(urlString)); + } + + @Override + public void decodeTags(MapElement mapElement, Map properties) { + boolean hasName = false; + String fallbackName = null; + + for (Map.Entry entry : properties.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + String val = (value instanceof String) ? (String) value : String.valueOf(value); + + if (key.startsWith(Tag.KEY_NAME)) { + int len = key.length(); + if (len == 4) { + fallbackName = val; + continue; + } + if (len < 7) + continue; + if (locale.equals(key.substring(5))) { + hasName = true; + mapElement.tags.add(new Tag(Tag.KEY_NAME, val, false)); + } + continue; + } + + Tag tag = mappings.get(key + "=" + val); + if (tag == null) + tag = addMapping(key, val); + mapElement.tags.add(tag); + } + + if (!hasName && fallbackName != null) + mapElement.tags.add(new Tag(Tag.KEY_NAME, fallbackName, false)); + + // Calculate height of building parts + if (!properties.containsKey(Tag.KEY_HEIGHT)) { + if (properties.containsKey(Tag.KEY_VOLUME) && properties.containsKey(Tag.KEY_AREA)) { + Object volume = properties.get(Tag.KEY_VOLUME); + String volumeStr = (volume instanceof String) ? (String) volume : String.valueOf(volume); + Object area = properties.get(Tag.KEY_AREA); + String areaStr = (area instanceof String) ? (String) area : String.valueOf(area); + float height = Float.parseFloat(volumeStr) / Float.parseFloat(areaStr); + String heightStr = String.valueOf(MathUtils.round2(height)); + mapElement.tags.add(new Tag(Tag.KEY_HEIGHT, heightStr, false)); + } + } + } +} diff --git a/vtm-mvt/src/org/oscim/tiling/source/mvt/NextzenMvtTileSource.java b/vtm-mvt/src/org/oscim/tiling/source/mvt/NextzenMvtTileSource.java new file mode 100644 index 00000000..76280077 --- /dev/null +++ b/vtm-mvt/src/org/oscim/tiling/source/mvt/NextzenMvtTileSource.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 devemux86 + * + * 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.tiling.source.mvt; + +import org.oscim.tiling.ITileDataSource; +import org.oscim.tiling.source.UrlTileDataSource; +import org.oscim.tiling.source.UrlTileSource; + +public class NextzenMvtTileSource extends UrlTileSource { + + private final static String DEFAULT_URL = "https://tile.nextzen.org/tilezen/vector/v1/all"; + private final static String DEFAULT_PATH = "/{Z}/{X}/{Y}.mvt"; + + public static class Builder> extends UrlTileSource.Builder { + private String locale = ""; + + public Builder() { + super(DEFAULT_URL, DEFAULT_PATH, 1, 17); + keyName("api_key"); + } + + public T locale(String locale) { + this.locale = locale; + return self(); + } + + public NextzenMvtTileSource build() { + return new NextzenMvtTileSource(this); + } + } + + @SuppressWarnings("rawtypes") + public static Builder builder() { + return new Builder(); + } + + private final String locale; + + public NextzenMvtTileSource(Builder builder) { + super(builder); + this.locale = builder.locale; + } + + public NextzenMvtTileSource() { + this(builder()); + } + + public NextzenMvtTileSource(String urlString) { + this(builder().url(urlString)); + } + + @Override + public ITileDataSource getDataSource() { + return new UrlTileDataSource(this, new MvtTileDecoder(locale), getHttpEngine()); + } +} diff --git a/vtm-playground/src/org/oscim/test/NextzenGeojsonTest.java b/vtm-playground/src/org/oscim/test/NextzenGeojsonTest.java new file mode 100644 index 00000000..cfa37ce6 --- /dev/null +++ b/vtm-playground/src/org/oscim/test/NextzenGeojsonTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 devemux86 + * + * 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.test; + +import org.oscim.gdx.GdxMapApp; +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 org.oscim.tiling.source.OkHttpEngine; +import org.oscim.tiling.source.UrlTileSource; +import org.oscim.tiling.source.geojson.NextzenGeojsonTileSource; + +import java.io.File; +import java.util.UUID; + +import okhttp3.Cache; +import okhttp3.OkHttpClient; + +public class NextzenGeojsonTest extends GdxMapApp { + + private static final boolean USE_CACHE = false; + + @Override + public void createLayers() { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + if (USE_CACHE) { + // Cache the tiles into file system + File cacheDirectory = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); + int cacheSize = 10 * 1024 * 1024; // 10 MB + Cache cache = new Cache(cacheDirectory, cacheSize); + builder.cache(cache); + } + OkHttpEngine.OkHttpFactory factory = new OkHttpEngine.OkHttpFactory(builder); + + UrlTileSource tileSource = NextzenGeojsonTileSource.builder() + .apiKey("xxxxxxx") // Put a proper API key + .httpFactory(factory) + //.locale("en") + .build(); + + VectorTileLayer l = mMap.setBaseMap(tileSource); + mMap.setTheme(VtmThemes.MAPZEN); + + mMap.layers().add(new BuildingLayer(mMap, l)); + mMap.layers().add(new LabelLayer(mMap, l)); + } + + public static void main(String[] args) { + GdxMapApp.init(); + GdxMapApp.run(new NextzenGeojsonTest()); + } +} diff --git a/vtm-playground/src/org/oscim/test/NextzenMvtTest.java b/vtm-playground/src/org/oscim/test/NextzenMvtTest.java new file mode 100644 index 00000000..2bf658f5 --- /dev/null +++ b/vtm-playground/src/org/oscim/test/NextzenMvtTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 devemux86 + * + * 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.test; + +import org.oscim.gdx.GdxMapApp; +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 org.oscim.tiling.source.OkHttpEngine; +import org.oscim.tiling.source.UrlTileSource; +import org.oscim.tiling.source.mvt.NextzenMvtTileSource; + +import java.io.File; +import java.util.UUID; + +import okhttp3.Cache; +import okhttp3.OkHttpClient; + +public class NextzenMvtTest extends GdxMapApp { + + private static final boolean USE_CACHE = false; + + @Override + public void createLayers() { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + if (USE_CACHE) { + // Cache the tiles into file system + File cacheDirectory = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); + int cacheSize = 10 * 1024 * 1024; // 10 MB + Cache cache = new Cache(cacheDirectory, cacheSize); + builder.cache(cache); + } + OkHttpEngine.OkHttpFactory factory = new OkHttpEngine.OkHttpFactory(builder); + + UrlTileSource tileSource = NextzenMvtTileSource.builder() + .apiKey("xxxxxxx") // Put a proper API key + .httpFactory(factory) + //.locale("en") + .build(); + + VectorTileLayer l = mMap.setBaseMap(tileSource); + mMap.setTheme(VtmThemes.MAPZEN); + + mMap.layers().add(new BuildingLayer(mMap, l)); + mMap.layers().add(new LabelLayer(mMap, l)); + } + + public static void main(String[] args) { + GdxMapApp.init(); + GdxMapApp.run(new NextzenMvtTest()); + } +}