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());
+ }
+}