From d3fe499b6e1236534b42c086253b4c6e60cecd4c Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 5 Sep 2016 16:26:16 +0200 Subject: [PATCH] [android] complete peer model, add geojson options construction time --- .../style/sources/GeoJsonOptions.java | 63 +++++++++++ .../style/sources/GeoJsonSource.java | 106 +++++++++++++----- .../mapboxsdk/style/sources/RasterSource.java | 7 ++ .../mapboxsdk/style/sources/VectorSource.java | 7 ++ .../style/GeoJsonClusteringActivity.java | 12 +- .../activity/style/RuntimeStyleActivity.java | 12 +- platform/android/src/jni.cpp | 1 + .../src/style/sources/geojson_source.cpp | 22 +++- .../src/style/sources/geojson_source.hpp | 2 +- platform/android/src/style/sources/source.cpp | 13 +++ platform/android/src/style/sources/source.hpp | 2 + 11 files changed, 209 insertions(+), 38 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java new file mode 100644 index 00000000000..d7a92823719 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java @@ -0,0 +1,63 @@ +package com.mapbox.mapboxsdk.style.sources; + +import java.util.HashMap; + +/** + * Options for the GeoJsonSource + */ +public class GeoJsonOptions extends HashMap { + + /** + * Defaults to 18. + * Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels). + */ + public GeoJsonOptions withMaxZoom(int maxZoom) { + this.put("maxzoom", maxZoom); + return this; + } + + /** + * Defaults to 128. + * Tile buffer size on each side (measured in 1/512ths of a tile; higher means fewer rendering artifacts near tile edges but slower performance). + */ + public GeoJsonOptions withBuffer(int buffer) { + this.put("buffer", buffer); + return this; + } + + /** + * Defaults to 0.375. + * Douglas-Peucker simplification tolerance (higher means simpler geometries and faster performance). + */ + public GeoJsonOptions withTolerance(float tolerance) { + this.put("tolerance", tolerance); + return this; + } + + /** + * Defaults to false. + * If the data is a collection of point features, setting this to true clusters the points by radius into groups. + */ + public GeoJsonOptions withCluster(boolean cluster) { + this.put("cluster", cluster); + return this; + } + + /** + * Defaults to 50. + * Radius of each cluster when clustering points, measured in 1/512ths of a tile. + */ + public GeoJsonOptions withClusterMaxZoom(int clusterMaxZoom) { + this.put("clusterMaxZoom", clusterMaxZoom); + return this; + } + + /** + * Max zoom to cluster points on. Defaults to one zoom less than maxzoom (so that last zoom features are not clustered). + */ + public GeoJsonOptions withClusterRadius(int clusterRadius) { + this.put("clusterRadius", clusterRadius); + return this; + } + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java index 286d2e28986..a66e0a4adca 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java @@ -1,9 +1,10 @@ package com.mapbox.mapboxsdk.style.sources; -import com.google.gson.Gson; +import com.mapbox.services.commons.geojson.Feature; import com.mapbox.services.commons.geojson.FeatureCollection; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; /** @@ -13,13 +14,32 @@ */ public class GeoJsonSource extends Source { + /** + * Internal use + */ + public GeoJsonSource(long nativePtr) { + super(nativePtr); + } + /** * Create an empty GeoJsonSource * * @param id the source id */ public GeoJsonSource(String id) { - initialize(id); + initialize(id, null); + setGeoJson(FeatureCollection.fromFeatures(new ArrayList())); + } + + /** + * Create an empty GeoJsonSource + * + * @param id the source id + * @param options options + */ + public GeoJsonSource(String id, GeoJsonOptions options) { + initialize(id, options); + setGeoJson(FeatureCollection.fromFeatures(new ArrayList())); } /** @@ -32,8 +52,23 @@ public GeoJsonSource(String id, String geoJson) { if (geoJson == null || geoJson.startsWith("http")) { throw new IllegalArgumentException("Expected a raw json body"); } - initialize(id); - nativeSetGeoJson(geoJson); + initialize(id, null); + setGeoJson(geoJson); + } + + /** + * Create a GeoJsonSource from a raw json string + * + * @param id the source id + * @param geoJson raw Json body + * @param options options + */ + public GeoJsonSource(String id, String geoJson, GeoJsonOptions options) { + if (geoJson == null || geoJson.startsWith("http")) { + throw new IllegalArgumentException("Expected a raw json body"); + } + initialize(id, options); + setGeoJson(geoJson); } /** @@ -43,7 +78,19 @@ public GeoJsonSource(String id, String geoJson) { * @param url remote json file */ public GeoJsonSource(String id, URL url) { - initialize(id); + initialize(id, null); + nativeSetUrl(url.toExternalForm()); + } + + /** + * Create a GeoJsonSource from a remote geo json file + * + * @param id the source id + * @param url remote json file + * @param options options + */ + public GeoJsonSource(String id, URL url, GeoJsonOptions options) { + initialize(id, options); nativeSetUrl(url.toExternalForm()); } @@ -54,46 +101,55 @@ public GeoJsonSource(String id, URL url) { * @param features the features */ public GeoJsonSource(String id, FeatureCollection features) { - initialize(id); - nativeSetGeoJson(features.toJson()); + initialize(id, null); + setGeoJson(features); + } + + /** + * Create a GeoJsonSource from a FeatureCollection + * + * @param id the source id + * @param features the features + * @param options options + */ + public GeoJsonSource(String id, FeatureCollection features, GeoJsonOptions options) { + initialize(id, options); + setGeoJson(features); } public void setGeoJson(FeatureCollection features) { - nativeSetGeoJson(features.toJson()); + checkValidity(); + setGeoJson(features.toJson()); } public void setGeoJson(String json) { - nativeSetGeoJson(json); + checkValidity(); + setRawJson(json); } public void setUrl(URL url) { - nativeSetUrl(url.toExternalForm()); + checkValidity(); + setUrl(url.toExternalForm()); } public void setUrl(String url) { + checkValidity(); nativeSetUrl(url); } - public GeoJsonSource withCluster(boolean cluster) { - //TODO this.put("cluster", cluster); - return this; - } - - public GeoJsonSource withClusterMaxZoom(float zoom) { - //TODO this.put("clusterMaxZoom", zoom); - return this; - } - - public GeoJsonSource withClusterRadius(float radius) { - //TODO this.put("clusterRadius", radius); - return this; + protected void setRawJson(String geoJson) { + //Wrap the String in a map as an Object is expected by the + //style conversion template + HashMap wrapper = new HashMap<>(); + wrapper.put("data", geoJson); + nativeSetGeoJson(wrapper); } - protected native void initialize(String layerId); + protected native void initialize(String layerId, Object options); protected native void nativeSetUrl(String url); - protected native void nativeSetGeoJson(String geoJson); + private native void nativeSetGeoJson(Object geoJson); @Override protected native void finalize() throws Throwable; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java index abcc5dc39ec..14bd8bb9ed5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java @@ -10,6 +10,13 @@ public class RasterSource extends Source { public static final int DEFAULT_TILE_SIZE = 512; + /** + * Internal use + */ + public RasterSource(long nativePtr) { + super(nativePtr); + } + public RasterSource(String id, URL url) { this(id, url.toExternalForm()); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java index 50b8479113a..a9c191f96a6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java @@ -9,6 +9,13 @@ */ public class VectorSource extends Source { + /** + * Internal use + */ + public VectorSource(long nativePtr) { + super(nativePtr); + } + /** * Create a vector source from a remote url * diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java index ca4460eac2a..9d13ee165df 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java @@ -16,6 +16,7 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.testapp.R; @@ -110,10 +111,13 @@ private void addClusteredGeoJsonSource() { //Add a clustered source try { mapboxMap.addSource( - new GeoJsonSource("earthquakes", new URL("https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson")) - .withCluster(true) - .withClusterMaxZoom(14) - .withClusterRadius(50) + new GeoJsonSource("earthquakes", + new URL("https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"), + new GeoJsonOptions() + .withCluster(true) + .withClusterMaxZoom(14) + .withClusterRadius(50) + ) ); } catch (MalformedURLException malformedUrlException) { Log.e(TAG, "That's not an url... " + malformedUrlException.getMessage()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java index 3e62d449ff6..c6cc31279b7 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java @@ -291,13 +291,13 @@ private void addDynamicParksLayer() { return; } - //Add a source + //Add an empty source mapboxMap.addSource(new GeoJsonSource("dynamic-park-source")); FillLayer layer = new FillLayer("dynamic-parks-layer", "dynamic-park-source"); layer.setProperties( - fillColor(Color.RED), - fillOutlineColor(Color.BLUE), + fillColor(Color.GREEN), + fillOutlineColor(Color.GREEN), fillOpacity(0.8f), fillAntialias(true) ); @@ -325,6 +325,12 @@ public void run() { GeoJsonSource source = mapboxMap.getSourceAs("dynamic-park-source"); + if (source == null) { + Log.e(TAG, "Source not found"); + Toast.makeText(RuntimeStyleActivity.this, "Source not found", Toast.LENGTH_SHORT).show(); + return; + } + List features = new ArrayList<>(); features.add(parks.getFeatures().get(park)); source.setGeoJson(FeatureCollection.fromFeatures(features)); diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index dd83d3cbf08..e168e6d0dee 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -1693,6 +1693,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { java::registerNatives(env); registerNativeLayers(env); + registerNativeSources(env); latLngClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLng"); latLngClass = jni::NewGlobalRef(env, latLngClass).release(); diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index e4105eeca09..cb03cc06c62 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -1,15 +1,21 @@ #include "geojson_source.hpp" -#include +#include "../android_conversion.hpp" #include "../conversion/geojson.hpp" +#include +#include #include namespace mbgl { namespace android { - GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, jni::String sourceId) - : Source(env, std::make_unique(jni::Make(env, sourceId))) { + GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<> options) + : Source(env, std::make_unique( + jni::Make(env, sourceId), + options ? *style::conversion::convert(Value(env, options)) : style::GeoJSONOptions() + ) + ) { } GeoJSONSource::GeoJSONSource(mbgl::Map& map, mbgl::style::GeoJSONSource& coreSource) @@ -30,11 +36,17 @@ namespace android { //Update the core source source.as()->GeoJSONSource::setGeoJSON(*converted); + + //Repaint + updateStyle(false); } void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) { //Update the core source source.as()->GeoJSONSource::setURL(jni::Make(env, url)); + + //Repaint + updateStyle(false); } jni::Class GeoJSONSource::javaClass; @@ -53,11 +65,11 @@ namespace android { //Register the peer jni::RegisterNativePeer( env, GeoJSONSource::javaClass, "nativePtr", - std::make_unique, + std::make_unique>, "initialize", "finalize", METHOD(&GeoJSONSource::setGeoJSON, "nativeSetGeoJson"), - METHOD(&GeoJSONSource::setGeoJSON, "nativeSetUrl") + METHOD(&GeoJSONSource::setURL, "nativeSetUrl") ); } diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp index 340bef446c3..10c51e81b25 100644 --- a/platform/android/src/style/sources/geojson_source.hpp +++ b/platform/android/src/style/sources/geojson_source.hpp @@ -16,7 +16,7 @@ class GeoJSONSource : public Source { static void registerNative(jni::JNIEnv&); - GeoJSONSource(jni::JNIEnv&, jni::String); + GeoJSONSource(jni::JNIEnv&, jni::String, jni::Object<>); GeoJSONSource(mbgl::Map&, mbgl::style::GeoJSONSource&); diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index f3daa777d14..4f306e7c54a 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -35,6 +35,19 @@ namespace android { return jni::Make(env, source.getID()); } + void Source::updateStyle(jni::jboolean updateClasses) { + //Update the style only if attached + if (ownedSource == nullptr) { + Update flags = mbgl::Update::RecalculateStyle; + if(updateClasses) { + flags = flags | mbgl::Update::Classes; + } + map->update(flags); + } else { + mbgl::Log::Debug(mbgl::Event::JNI, "Not updating as source is not attached to map (yet)"); + } + } + std::unique_ptr Source::releaseCoreSource() { assert(ownedSource != nullptr); return std::move(ownedSource); diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp index aaaa6daf459..7fdc43a8335 100644 --- a/platform/android/src/style/sources/source.hpp +++ b/platform/android/src/style/sources/source.hpp @@ -40,6 +40,8 @@ class Source : private mbgl::util::noncopyable { std::unique_ptr releaseCoreSource(); protected: + void updateStyle(jni::jboolean); + std::unique_ptr ownedSource; mbgl::style::Source& source; mbgl::Map* map;