From 6b0d9c0f36662e054a44758aae3757e330321fcf Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 21 Feb 2018 17:27:00 +0100 Subject: [android] - add expression conversion, add getters --- .../mapboxsdk/style/expressions/Expression.java | 7 ++ .../mapbox/mapboxsdk/style/functions/Function.java | 37 ++++++- .../mapboxsdk/style/functions/SourceFunction.java | 9 ++ .../activity/style/SymbolGeneratorActivity.java | 31 ++++-- .../android/src/geojson/conversion/geometry.hpp | 4 +- platform/android/src/style/conversion/function.hpp | 13 +-- platform/android/src/style/conversion/json.hpp | 114 +++++++++++++++++++++ .../src/style/conversion/property_value.hpp | 2 + 8 files changed, 199 insertions(+), 18 deletions(-) create mode 100644 platform/android/src/style/conversion/json.hpp diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index 7b841a2580..901b0b1b87 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -10,6 +10,8 @@ import com.mapbox.mapboxsdk.style.layers.PropertyFactory; import java.util.ArrayList; import java.util.List; +import timber.log.Timber; + /** * The value for any layout property, paint property, or filter may be specified as an expression. * An expression defines a formula for computing the value of the property using the operators described below. @@ -1794,4 +1796,9 @@ public class Expression { builder.append("]"); return builder.toString(); } + + @Override + public boolean equals(Object obj) { + return this.toString().equals(obj.toString()); + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java index e7bb52ebb3..82fd33843f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java @@ -3,6 +3,9 @@ package com.mapbox.mapboxsdk.style.functions; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops; import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops; import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops; @@ -10,6 +13,8 @@ import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops; import com.mapbox.mapboxsdk.style.functions.stops.Stop; import com.mapbox.mapboxsdk.style.functions.stops.Stops; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import timber.log.Timber; @@ -249,7 +254,8 @@ public class Function { // Class definition // - private final Stops stops; + private Stops stops; + private JsonArray expression; /** * JNI Cosntructor for implementation classes @@ -260,6 +266,35 @@ public class Function { this.stops = stops; } + Function(Object object) { + Timber.e("Class: %s", object.getClass().getSimpleName()); + if (object instanceof JsonArray) { + this.expression = (JsonArray) object; + } + } + + public Expression getExpression() { + return convert(this.expression); + } + + private Expression convert(JsonArray jsonArray) { + final String operator = jsonArray.get(0).getAsString(); + final List arguments = new ArrayList<>(); + + JsonElement jsonElement; + for (int i = 1; i < jsonArray.size(); i++) { + jsonElement = jsonArray.get(i); + if (jsonElement instanceof JsonArray) { + arguments.add(convert((JsonArray) jsonElement)); + } else { + arguments.add(new Expression(jsonElement.getAsString())); + } + } + + return new Expression(operator, arguments.toArray(new Expression[arguments.size()])); + } + + /** * @return the stops in this function */ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java index 33f436ae71..ae080c8753 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java @@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.style.functions; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.google.gson.JsonArray; import com.mapbox.mapboxsdk.style.functions.stops.Stops; import com.mapbox.mapboxsdk.style.layers.PropertyValue; @@ -41,6 +42,14 @@ public class SourceFunction extends Function { this.defaultValue = defaultValue != null ? new PropertyValue<>(property, defaultValue) : null; } + /** + * JNI Constructor + */ + private SourceFunction(@Nullable O defaultValue, @NonNull String property, @NonNull Object expression) { + super(expression); + this.property = property; + this.defaultValue = defaultValue != null ? new PropertyValue<>(property, defaultValue) : null; + } /** * INTERNAL USAGE ONLY diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java index ca4176be6e..e623173da3 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java @@ -20,6 +20,7 @@ import com.mapbox.geojson.FeatureCollection; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.Filter; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; @@ -27,7 +28,6 @@ import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils; - import java.io.IOException; import java.util.HashMap; import java.util.List; @@ -226,19 +226,16 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR } public void onDataLoaded(@NonNull FeatureCollection featureCollection) { - // add a geojson to the map - Source source = new GeoJsonSource(SOURCE_ID, featureCollection); - mapboxMap.addSource(source); + Expression iconSizeExpression = division(get(literal(FEATURE_RANK)), literal(2)); - // create layer use - mapboxMap.addLayer(new SymbolLayer(LAYER_ID, SOURCE_ID) + SymbolLayer symbolLayer = new SymbolLayer(LAYER_ID, SOURCE_ID) .withProperties( // icon configuration iconImage(get(literal(FEATURE_ID))), iconAllowOverlap(false), iconSize( - division(get(literal(FEATURE_RANK)), literal(2)) + iconSizeExpression ), iconAnchor(ICON_ANCHOR_BOTTOM), iconOffset(new Float[] {0.0f, -5.0f}), @@ -256,8 +253,24 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR product(get(literal(FEATURE_RANK)), pi()) ), textAnchor(TEXT_ANCHOR_TOP) - ) - ); + ); + + // add a geojson to the map + Source source = new GeoJsonSource(SOURCE_ID, featureCollection); + mapboxMap.addSource(source); + + // create layer use + mapboxMap.addLayer(symbolLayer); + + Timber.e((symbolLayer.getIconSize().getFunction().getExpression()).toString()); + + Expression result = symbolLayer.getIconSize().getFunction().getExpression(); + + if (iconSizeExpression.equals(result)) { + Timber.e("PERFECT"); + } else { + Timber.e("FAIL"); + } new GenerateSymbolTask(mapboxMap, this).execute(featureCollection); } diff --git a/platform/android/src/geojson/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp index 5d2aab4c2d..38ed0470f0 100644 --- a/platform/android/src/geojson/conversion/geometry.hpp +++ b/platform/android/src/geojson/conversion/geometry.hpp @@ -54,7 +54,7 @@ public: return reinterpret_cast(jni::CallStaticMethod(env, *javaClass, *fromLngLats, coordinates.get())); } - /** + /**ยง * static Polygon fromLngLats(List> coordinates) */ jni::jobject* operator()(const mapbox::geometry::polygon &geometry) const { @@ -97,7 +97,7 @@ public: // Create the MultiPolygon static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/MultiPolygon")).release(); - static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/MultiPolygon;"); + static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/ArrayList;)Lcom/mapbox/geojson/MultiPolygon;"); return reinterpret_cast(jni::CallStaticMethod(env, *javaClass, *fromGeometries, arrayList)); } diff --git a/platform/android/src/style/conversion/function.hpp b/platform/android/src/style/conversion/function.hpp index ad01a7afc2..41382bc189 100644 --- a/platform/android/src/style/conversion/function.hpp +++ b/platform/android/src/style/conversion/function.hpp @@ -12,7 +12,7 @@ #include "../functions/interval_stops.hpp" #include - +#include "json.hpp" #include #include @@ -183,11 +183,12 @@ struct Converter> { Result operator()(jni::JNIEnv& env, const mbgl::style::SourceFunction& value) const { static jni::jclass* clazz = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/SourceFunction")).release(); static jni::jmethodID* constructor = &jni::GetMethodID(env, *clazz, "", - "(Ljava/lang/Object;Ljava/lang/String;Lcom/mapbox/mapboxsdk/style/functions/stops/Stops;)V"); + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V"); - // Convert stops - StopsEvaluator evaluator(env); - jni::jobject* stops = apply_visitor(evaluator, value.stops); + // Convert expressions + mbgl::Value expressionValue = value.getExpression().serialize(); + JsonEvaluator jsonEvaluator{env}; + jni::jobject* converted = apply_visitor(jsonEvaluator, expressionValue); // Convert default value jni::jobject* defaultValue = nullptr; @@ -195,7 +196,7 @@ struct Converter> { defaultValue = *convert(env, *value.defaultValue); } - return { &jni::NewObject(env, *clazz, *constructor, defaultValue, jni::Make(env, value.property).Get(), stops) }; + return { &jni::NewObject(env, *clazz, *constructor, defaultValue, jni::Make(env, value.property).Get(), converted) }; } }; diff --git a/platform/android/src/style/conversion/json.hpp b/platform/android/src/style/conversion/json.hpp new file mode 100644 index 0000000000..c2ab4e360d --- /dev/null +++ b/platform/android/src/style/conversion/json.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include "../../conversion/constant.hpp" +#include "../../conversion/collection.hpp" + +#include +#include +#include "../../jni/local_object.hpp" +#include "mapbox/geometry/feature.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +/** + * Turn mapbox::geometry::value type into Java Json + */ +class JsonEvaluator { +public: + + jni::JNIEnv& env; + + jni::jobject* operator()(const mapbox::geometry::null_value_t) const { + return (jni::jobject*) nullptr;; + } + + jni::jobject* operator()(const bool& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/Boolean;)V"); + + // Create JsonPrimitive + jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted); + + return object; + } + + template + jni::jobject* operator()(const Number& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/Number;)V"); + + // Create JsonPrimitive + jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + jni::jobject* operator()(const std::string value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/String;)V"); + + // Create JsonPrimitive + jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + jni::jobject*operator()(const std::vector values) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonArray")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V"); + + // Create json array + jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor); + + // Add values + for (const auto &v : values) { + jni::LocalObject converted = jni::NewLocalObject(env, mapbox::geometry::value::visit(v, *this)); + jni::CallMethod(env, jarray, *add, converted.get()); + } + + return jarray; + } + + jni::jobject*operator()(const std::unordered_map value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); + + // Create json object + jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); + + // Add items + for (auto &item : value) { + jni::LocalObject converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this)); + jni::LocalObject key = jni::NewLocalObject(env, *convert(env, item.first)); + jni::CallMethod(env, jsonObject, *add, key.get(), converted.get()); + } + + return jsonObject; + } + +private: + +}; + +/** + * mapbox::geometry::value -> Java Json + */ +template <> +struct Converter { + Result operator()(jni::JNIEnv& env, const mapbox::geometry::value& value) const { + JsonEvaluator evaluator { env } ; + jni::jobject* converted = mapbox::geometry::value::visit(value, evaluator); + return {converted}; + } +}; + +} +} +} diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp index a58cf975a7..5f6a1266d4 100644 --- a/platform/android/src/style/conversion/property_value.hpp +++ b/platform/android/src/style/conversion/property_value.hpp @@ -6,6 +6,7 @@ #include "../../conversion/constant.hpp" #include "types.hpp" #include "function.hpp" +#include "json.hpp" namespace mbgl { namespace android { @@ -34,6 +35,7 @@ public: } jni::jobject* operator()(const mbgl::style::SourceFunction &value) const { + Result result = convert(env, value.getExpression().serialize()); return *convert>(env, value); } -- cgit v1.2.1