diff options
Diffstat (limited to 'platform/android/src/geojson')
22 files changed, 1165 insertions, 0 deletions
diff --git a/platform/android/src/geojson/conversion/feature.hpp b/platform/android/src/geojson/conversion/feature.hpp new file mode 100644 index 0000000000..86aa5fc03c --- /dev/null +++ b/platform/android/src/geojson/conversion/feature.hpp @@ -0,0 +1,217 @@ +#pragma once + +#include "../../conversion/constant.hpp" +#include "../../conversion/conversion.hpp" +#include "geometry.hpp" +#include "../../gson/json_object.hpp" + +#include <mbgl/util/feature.hpp> +#include <mapbox/variant.hpp> +#include <mapbox/geometry.hpp> + +#include <jni/jni.hpp> +#include "../../jni/local_object.hpp" +#include "../feature.hpp" + +#include <string> +#include <array> +#include <vector> +#include <sstream> + +#include <mbgl/util/logging.hpp> + +namespace mbgl { +namespace android { +namespace conversion { + +/** + * Turn feature identifier into std::string + */ +class FeatureIdVisitor { +public: + + template<class T> + std::string operator()(const T& i) const { + return std::to_string(i); + } + + std::string operator()(const std::string& i) const { + return i; + } + + std::string operator()(const std::nullptr_t&) const { + return ""; + } + +}; + +/** + * Turn properties into Java GSON JsonObject's + */ +class PropertyValueEvaluator { +public: + jni::JNIEnv& env; + + /** + * null + */ + jni::jobject* operator()(const mapbox::geometry::null_value_t &) const { + return (jni::jobject*) nullptr; + } + + /** + * Boolean primitive + */ + 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, "<init>", "(Ljava/lang/Boolean;)V"); + + // Create JsonPrimitive + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, bool>(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted); + + return object; + } + + /** + * String primitive + */ + 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, "<init>", "(Ljava/lang/String;)V"); + + // Create JsonPrimitive + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + /** + * Number primitives + */ + template <class Number> + 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, "<init>", "(Ljava/lang/Number;)V"); + + // Create JsonPrimitive + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, Number>(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + + /** + * Json Array + */ + jni::jobject* operator()(const std::vector<mbgl::Value> &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, "<init>", "()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<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(v, *this)); + jni::CallMethod<void>(env, jarray, *add, converted.get()); + } + + return jarray; + } + + /** + * Json Object + */ + jni::jobject* operator()(const std::unordered_map<std::string, mbgl::Value> &value) const { + // TODO: clean up duplication here + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()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<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this)); + jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first)); + jni::CallMethod<void>(env, jsonObject, *add, key.get(), converted.get()); + } + + return jsonObject; + } +}; + +template <> +struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> { + Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::unordered_map<std::string, mbgl::Value>& 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, "<init>", "()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 + PropertyValueEvaluator evaluator {env}; + for (auto &item : value) { + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, evaluator)); + jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first)); + jni::CallMethod<void>(env, jsonObject, *add, key.get(), converted.get()); + } + + return {jsonObject}; + } +}; + + +template <> +struct Converter<jni::Object<android::geojson::Feature>, mbgl::Feature> { + Result<jni::Object<android::geojson::Feature>> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { + + // Convert Id + FeatureIdVisitor idEvaluator; + std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : ""; + auto jid = jni::Make<jni::String>(env, id); + + // Convert properties + auto properties = jni::Object<gson::JsonObject>(*convert<jni::jobject*>(env, value.properties)); + + // Convert geometry + auto geometry = jni::Object<android::geojson::Geometry>(*convert<jni::jobject*>(env, value.geometry)); + + // Create feature + auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); + + //Cleanup + jni::DeleteLocalRef(env, jid); + jni::DeleteLocalRef(env, geometry); + jni::DeleteLocalRef(env, properties); + + return feature; + } +}; + +template <> +struct Converter<jni::Array<jni::Object<android::geojson::Feature>>, std::vector<mbgl::Feature>> { + Result<jni::Array<jni::Object<android::geojson::Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const { + using namespace mbgl::android::geojson; + auto features = jni::Array<jni::Object<Feature>>::New(env, value.size(), Feature::javaClass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + auto converted = *convert<jni::Object<android::geojson::Feature>, mbgl::Feature>(env, value.at(i)); + features.Set(env, i, converted); + jni::DeleteLocalRef(env, converted); + } + + return {features}; + } +}; + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/geojson/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp new file mode 100644 index 0000000000..2ca63e2c11 --- /dev/null +++ b/platform/android/src/geojson/conversion/geometry.hpp @@ -0,0 +1,184 @@ +#pragma once + +#include "../../conversion/constant.hpp" +#include "../../conversion/collection.hpp" + +#include <mapbox/geometry.hpp> +#include <jni/jni.hpp> +#include "../../jni/local_object.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +/** + * Turn mapbox::geometry type into Java GeoJson Geometries + */ +template <typename T> +class GeometryEvaluator { +public: + + jni::JNIEnv& env; + + /** + * Point (double[]) + */ + jni::jobject* operator()(const mapbox::geometry::point<T> &geometry) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Point")).release(); + static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([D)Lcom/mapbox/services/commons/geojson/Point;"); + + // Create Point + jni::LocalObject<jni::jarray<jni::jdouble>> position = jni::NewLocalObject(env, toGeoJsonPosition(env, geometry.x, geometry.y)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, position.get())); + } + + /** + * LineString (double[][]) + */ + jni::jobject* operator()(const mapbox::geometry::line_string<T> &geometry) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/LineString")).release(); + static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/LineString;"); + + // Create + jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get())); + } + + /** + * MultiPoint (double[][]) + */ + jni::jobject* operator()(const mapbox::geometry::multi_point<T> &geometry) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPoint")).release(); + static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/MultiPoint;"); + + // Create + jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get())); + } + + /** + * Polygon (double[][][]) + */ + jni::jobject* operator()(const mapbox::geometry::polygon<T> &geometry) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Polygon")).release(); + static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/Polygon;"); + + // Create + jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get())); + } + + /** + * MultiLineString (double[][][]) + */ + jni::jobject* operator()(const mapbox::geometry::multi_line_string<T> &geometry) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiLineString")).release(); + static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/MultiLineString;"); + + // Create + jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get())); + } + + /** + * MultiPolygon (double[][][][]) -> [[[D + Object array == [[[[D + */ + jni::jobject* operator()(const mapbox::geometry::multi_polygon<T> &geometry) const { + static jni::jclass* listClass = jni::NewGlobalRef(env, &jni::FindClass(env, "[[[D")).release(); + jni::LocalObject<jni::jarray<jni::jobject>> jarray = jni::NewLocalObject(env, &jni::NewObjectArray(env, geometry.size(), *listClass)); + + for(size_t i = 0; i < geometry.size(); i = i + 1) { + jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry.at(i))); + jni::SetObjectArrayElement(env, *jarray, i, shape.get()); + } + + // Create the MultiPolygon + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPolygon")).release(); + static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[[D)Lcom/mapbox/services/commons/geojson/MultiPolygon;"); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometries, jarray.get())); + } + + /** + * GeometryCollection + */ + jni::jobject* operator()(const mapbox::geometry::geometry_collection<T> &collection) const { + static jni::jclass* geometryClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Geometry")).release(); + jni::LocalObject<jni::jarray<jni::jobject>> jarray = jni::NewLocalObject(env, &jni::NewObjectArray(env, collection.size(), *geometryClass)); + + for(size_t i = 0; i < collection.size(); i = i + 1) { + auto& geometry = collection.at(i); + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mapbox::geometry::geometry<T>::visit(geometry, *this)); + jni::SetObjectArrayElement(env, *jarray, i, converted.get()); + } + + // Turn into array list and create the GeometryCollection + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/GeometryCollection")).release(); + static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromGeometries", "(Ljava/util/List;)Lcom/mapbox/services/commons/geojson/GeometryCollection;"); + + jni::LocalObject<jni::jobject> list = jni::NewLocalObject(env, toArrayList<>(env, *jarray)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometries, list.get())); + } + +private: + + /** + * x, y -> jarray<jdouble> ([x,y]) + */ + static jni::jarray<jni::jdouble>* toGeoJsonPosition(JNIEnv& env, double x, double y) { + jni::jarray<jni::jdouble>& jarray = jni::NewArray<jni::jdouble>(env, 2); + jni::jdouble array[] = {x, y}; + jni::SetArrayRegion(env, jarray, 0, 2, array); + return &jarray; + } + + /** + * vector<point<T>> -> jarray<jobject> (double[][]) -> [D + Object array == [[D + */ + static jni::jarray<jni::jobject>* toGeoJsonCoordinates(JNIEnv& env, std::vector<mapbox::geometry::point<T>> points) { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "[D")).release(); + jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, points.size(), *javaClass); + + for(size_t i = 0; i < points.size(); i = i + 1) { + mapbox::geometry::point<T> point = points.at(i); + jni::LocalObject<jni::jarray<jni::jdouble>> position = jni::NewLocalObject(env, toGeoJsonPosition(env, point.x, point.y)); + jni::SetObjectArrayElement(env, jarray, i, position.get()); + } + + return &jarray; + } + + /** + * polygon<T> + * multi_line_string<T> + * -> jarray<jobject> (double[][][]) -> [[D + Object array == [[[D + */ + template <class SHAPE> + static jni::jarray<jni::jobject>* toShape(JNIEnv& env, SHAPE value) { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "[[D")).release(); + jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *javaClass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, value.at(i))); + jni::SetObjectArrayElement(env, jarray, i, coordinates.get()); + } + + return &jarray; + } +}; + +/** + * mapbox::geometry::geometry<T> -> Java GeoJson Geometry<> + */ +template <class T> +struct Converter<jni::jobject*, mapbox::geometry::geometry<T>> { + Result<jni::jobject*> operator()(jni::JNIEnv& env, const mapbox::geometry::geometry<T>& value) const { + GeometryEvaluator<double> evaluator { env } ; + jni::jobject* converted = mapbox::geometry::geometry<double>::visit(value, evaluator); + return {converted}; + } +}; + + +} +} +} diff --git a/platform/android/src/geojson/feature.cpp b/platform/android/src/geojson/feature.cpp new file mode 100644 index 0000000000..a6b387cd15 --- /dev/null +++ b/platform/android/src/geojson/feature.cpp @@ -0,0 +1,63 @@ +#include "feature.hpp" + +#include "geometry.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mbgl::Feature Feature::convert(jni::JNIEnv& env, jni::Object<Feature> jFeature) { + // Convert + auto jGeometry = getGeometry(env, jFeature); + auto jProperties = Feature::getProperties(env, jFeature); + + std::experimental::optional<mapbox::geometry::identifier> id; + auto jId = Feature::getId(env, jFeature); + if (jId) { + id = { jni::Make<std::string>(env, jId) }; + } + + auto feature = mbgl::Feature { + Geometry::convert(env, jGeometry), + gson::JsonObject::convert(env, jProperties), + id + }; + + // Cleanup + jni::DeleteLocalRef(env, jGeometry); + jni::DeleteLocalRef(env, jProperties); + jni::DeleteLocalRef(env, jId); + + return feature; +} + +jni::Object<Geometry> Feature::getGeometry(jni::JNIEnv& env, jni::Object<Feature> jFeature) { + static auto method = Feature::javaClass.GetMethod<jni::Object<Geometry> ()>(env, "getGeometry"); + return jFeature.Call(env, method); +} + +jni::Object<gson::JsonObject> Feature::getProperties(jni::JNIEnv& env, jni::Object<Feature> jFeature) { + static auto method = Feature::javaClass.GetMethod<jni::Object<gson::JsonObject> ()>(env, "getProperties"); + return jFeature.Call(env, method); +} + +jni::String Feature::getId(jni::JNIEnv& env, jni::Object<Feature> jFeature) { + static auto method = Feature::javaClass.GetMethod<jni::String ()>(env, "getId"); + return jFeature.Call(env, method); +} + +jni::Object<Feature> Feature::fromGeometry(jni::JNIEnv& env, jni::Object<Geometry> geometry, jni::Object<gson::JsonObject> properties, jni::String id) { + static auto method = Feature::javaClass.GetStaticMethod<jni::Object<Feature> (jni::Object<Geometry>, jni::Object<gson::JsonObject>, jni::String)>(env, "fromGeometry"); + return Feature::javaClass.Call(env, method, geometry, properties, id); +} + +void Feature::registerNative(jni::JNIEnv& env) { + // Lookup the class + Feature::javaClass = *jni::Class<Feature>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Feature> Feature::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/feature.hpp b/platform/android/src/geojson/feature.hpp new file mode 100644 index 0000000000..b5d856cc42 --- /dev/null +++ b/platform/android/src/geojson/feature.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include <mbgl/util/feature.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +#include "geometry.hpp" +#include "../gson/json_object.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class Feature : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Feature"; }; + + static jni::Object<Feature> fromGeometry(jni::JNIEnv&, jni::Object<Geometry>, jni::Object<gson::JsonObject>, jni::String); + + static mbgl::Feature convert(jni::JNIEnv&, jni::Object<Feature>); + + static jni::Object<Geometry> getGeometry(jni::JNIEnv&, jni::Object<Feature>); + + static jni::String getId(jni::JNIEnv&, jni::Object<Feature>); + + static jni::Object<gson::JsonObject> getProperties(jni::JNIEnv&, jni::Object<Feature>); + + static jni::Class<Feature> javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/feature_collection.cpp b/platform/android/src/geojson/feature_collection.cpp new file mode 100644 index 0000000000..2f156532ae --- /dev/null +++ b/platform/android/src/geojson/feature_collection.cpp @@ -0,0 +1,40 @@ +#include "feature_collection.hpp" + +#include "feature.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) { + auto jFeatureList = FeatureCollection::getFeatures(env, jCollection); + auto jFeatures = java::util::List::toArray<Feature>(env, jFeatureList); + auto size = size_t(jFeatures.Length(env)); + + auto collection = mbgl::FeatureCollection(); + collection.reserve(size); + + for (size_t i = 0; i < size; i++) { + auto jFeature = jFeatures.Get(env, i); + collection.push_back(Feature::convert(env, jFeature)); + jni::DeleteLocalRef(env, jFeature); + } + + return collection; +} + +jni::Object<java::util::List> FeatureCollection::getFeatures(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) { + static auto method = FeatureCollection::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getFeatures"); + return jCollection.Call(env, method); +} + +void FeatureCollection::registerNative(jni::JNIEnv& env) { + // Lookup the class + javaClass = *jni::Class<FeatureCollection>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<FeatureCollection> FeatureCollection::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/feature_collection.hpp b/platform/android/src/geojson/feature_collection.hpp new file mode 100644 index 0000000000..8e9717e82b --- /dev/null +++ b/platform/android/src/geojson/feature_collection.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "../java/util.hpp" + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { +namespace geojson { + +class FeatureCollection : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/FeatureCollection"; }; + + static mbgl::FeatureCollection convert(jni::JNIEnv&, jni::Object<FeatureCollection>); + + static jni::Object<java::util::List> getFeatures(jni::JNIEnv&, jni::Object<FeatureCollection>); + + static jni::Class<FeatureCollection> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/geometry.cpp b/platform/android/src/geojson/geometry.cpp new file mode 100644 index 0000000000..33bb4ee3db --- /dev/null +++ b/platform/android/src/geojson/geometry.cpp @@ -0,0 +1,52 @@ +#include "geometry.hpp" + +#include "point.hpp" +#include "multi_point.hpp" +#include "line_string.hpp" +#include "multi_line_string.hpp" +#include "polygon.hpp" +#include "multi_polygon.hpp" + +#include <string> + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::geometry Geometry::convert(jni::JNIEnv &env, jni::Object<Geometry> jGeometry) { + auto type = Geometry::getType(env, jGeometry); + if (type == Point::Type()) { + return { Point::convert(env, jni::Object<Point>(jGeometry.Get())) }; + } else if (type == MultiPoint::Type()) { + return { MultiPoint::convert(env, jni::Object<MultiPoint>(jGeometry.Get())) }; + } else if (type == LineString::Type()) { + return { LineString::convert(env, jni::Object<LineString>(jGeometry.Get())) }; + } else if (type == MultiLineString::Type()) { + return { MultiLineString::convert(env, jni::Object<MultiLineString>(jGeometry.Get())) }; + } else if (type == Polygon::Type()) { + return { Polygon::convert(env, jni::Object<Polygon>(jGeometry.Get())) }; + } else if (type == MultiPolygon::Type()) { + return { MultiPolygon::convert(env, jni::Object<MultiPolygon>(jGeometry.Get())) }; + } + + throw std::runtime_error(std::string {"Unsupported GeoJSON type: " } + type); +} + +std::string Geometry::getType(jni::JNIEnv &env, jni::Object<Geometry> jGeometry) { + static auto method = Geometry::javaClass.GetMethod<jni::String ()>(env, "getType"); + auto jType = jGeometry.Call(env, method); + auto type = jni::Make<std::string>(env, jType); + jni::DeleteLocalRef(env, jType); + return type; +} + +void Geometry::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Geometry>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Geometry> Geometry::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/geometry.hpp b/platform/android/src/geojson/geometry.hpp new file mode 100644 index 0000000000..bdcff6bb3e --- /dev/null +++ b/platform/android/src/geojson/geometry.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { +namespace geojson { + +class Geometry : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; }; + + static mapbox::geojson::geometry convert(jni::JNIEnv&, jni::Object<Geometry>); + + static std::string getType(jni::JNIEnv&, jni::Object<Geometry>); + + static jni::Class<Geometry> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/line_string.cpp b/platform/android/src/geojson/line_string.cpp new file mode 100644 index 0000000000..d0719f2538 --- /dev/null +++ b/platform/android/src/geojson/line_string.cpp @@ -0,0 +1,54 @@ +#include "line_string.hpp" + +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<LineString> jLineString) { + mapbox::geojson::line_string lineString; + + if (jLineString) { + auto jPositionList = LineString::getCoordinates(env, jLineString); + lineString = LineString::convert(env, jPositionList); + jni::DeleteLocalRef(env, jPositionList); + } + + return lineString; +} + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<Position>*/> jPositionList) { + mapbox::geojson::line_string lineString; + + if (jPositionList) { + auto jPositionArray = java::util::List::toArray<Position>(env, jPositionList); + + auto size = jPositionArray.Length(env); + for (std::size_t i = 0; i < size; i++) { + auto jPosition = jPositionArray.Get(env, i); + lineString.push_back(Position::convert(env, jPosition)); + jni::DeleteLocalRef(env, jPosition); + } + + jni::DeleteLocalRef(env, jPositionArray); + } + + return lineString; +} + +jni::Object<java::util::List> LineString::getCoordinates(jni::JNIEnv &env, jni::Object<LineString> jLineString) { + static auto method = LineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); + return jLineString.Call(env, method); +} + +void LineString::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<LineString>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<LineString> LineString::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/line_string.hpp b/platform/android/src/geojson/line_string.hpp new file mode 100644 index 0000000000..d3be68d0a5 --- /dev/null +++ b/platform/android/src/geojson/line_string.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + + +class LineString : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/LineString"; }; + + static constexpr auto Type() { return "LineString"; }; + + static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<LineString>); + + static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<Position>*/>); + + static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<LineString>); + + static jni::Class<LineString> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/multi_line_string.cpp b/platform/android/src/geojson/multi_line_string.cpp new file mode 100644 index 0000000000..b676144bf5 --- /dev/null +++ b/platform/android/src/geojson/multi_line_string.cpp @@ -0,0 +1,56 @@ +#include "multi_line_string.hpp" + +#include "line_string.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object<MultiLineString> jMultiLineString) { + mapbox::geojson::multi_line_string multiLineString; + + if (jMultiLineString) { + auto jPositionListsList = MultiLineString::getCoordinates(env, jMultiLineString); + multiLineString = MultiLineString::convert(env, jPositionListsList); + jni::DeleteLocalRef(env, jPositionListsList); + } + + return multiLineString; +} + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Position>>*/> jPositionListsList) { + mapbox::geojson::multi_line_string multiLineString; + + if (jPositionListsList) { + auto jPositionListsArray = java::util::List::toArray<java::util::List>(env, jPositionListsList); + + auto size = jPositionListsArray.Length(env); + multiLineString.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + auto jPositionList = jPositionListsArray.Get(env, i); + multiLineString.push_back(LineString::convert(env, jPositionList)); + jni::DeleteLocalRef(env, jPositionList); + } + + jni::DeleteLocalRef(env, jPositionListsArray); + } + + return multiLineString; +} + +jni::Object<java::util::List> MultiLineString::getCoordinates(jni::JNIEnv &env, jni::Object<MultiLineString> jLineString) { + static auto method = MultiLineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); + return jLineString.Call(env, method); +} + +void MultiLineString::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<MultiLineString>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<MultiLineString> MultiLineString::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/multi_line_string.hpp b/platform/android/src/geojson/multi_line_string.hpp new file mode 100644 index 0000000000..af33fe72d6 --- /dev/null +++ b/platform/android/src/geojson/multi_line_string.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiLineString : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiLineString"; }; + + static constexpr auto Type() { return "MultiLineString"; }; + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object<MultiLineString>); + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Position>>*/>); + + static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiLineString>); + + static jni::Class<MultiLineString> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/multi_point.cpp b/platform/android/src/geojson/multi_point.cpp new file mode 100644 index 0000000000..df4fdd7dfa --- /dev/null +++ b/platform/android/src/geojson/multi_point.cpp @@ -0,0 +1,35 @@ +#include "multi_point.hpp" + +#include "line_string.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv &env, jni::Object<MultiPoint> jMultiPoint) { + mapbox::geojson::multi_point multiPoint; + + if (jMultiPoint) { + auto jPositionListsList = MultiPoint::getCoordinates(env, jMultiPoint); + multiPoint = LineString::convert(env, jPositionListsList); + jni::DeleteLocalRef(env, jPositionListsList); + } + + return multiPoint; +} + +jni::Object<java::util::List> MultiPoint::getCoordinates(jni::JNIEnv &env, jni::Object<MultiPoint> jMultiPoint) { + static auto method = MultiPoint::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); + return jMultiPoint.Call(env, method); +} + +void MultiPoint::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<MultiPoint>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<MultiPoint> MultiPoint::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/multi_point.hpp b/platform/android/src/geojson/multi_point.hpp new file mode 100644 index 0000000000..7a698287eb --- /dev/null +++ b/platform/android/src/geojson/multi_point.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPoint : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPoint"; }; + + static constexpr auto Type() { return "MultiPoint"; }; + + static mapbox::geojson::multi_point convert(jni::JNIEnv&, jni::Object<MultiPoint>); + + static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiPoint>); + + static jni::Class<MultiPoint> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/multi_polygon.cpp b/platform/android/src/geojson/multi_polygon.cpp new file mode 100644 index 0000000000..a55884a110 --- /dev/null +++ b/platform/android/src/geojson/multi_polygon.cpp @@ -0,0 +1,46 @@ +#include "multi_polygon.hpp" + +#include "polygon.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv &env, jni::Object<MultiPolygon> jMultiPolygon) { + mapbox::geojson::multi_polygon multiPolygon; + + if (jMultiPolygon) { + auto jPositionListsListList = MultiPolygon::getCoordinates(env, jMultiPolygon); + auto jPositionListsListArray = java::util::List::toArray<java::util::List>(env, jPositionListsListList); + + auto size = jPositionListsListArray.Length(env); + multiPolygon.reserve(size); + + for (size_t i = 0; i < size; i++) { + auto jPositionListsList = jPositionListsListArray.Get(env, i); + multiPolygon.push_back(Polygon::convert(env, jPositionListsList)); + jni::DeleteLocalRef(env, jPositionListsList); + } + + jni::DeleteLocalRef(env, jPositionListsListList); + jni::DeleteLocalRef(env, jPositionListsListArray); + } + + return multiPolygon; +} + +jni::Object<java::util::List> MultiPolygon::getCoordinates(jni::JNIEnv &env, jni::Object<MultiPolygon> jPolygon) { + static auto method = MultiPolygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); + return jPolygon.Call(env, method); +} + +void MultiPolygon::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<MultiPolygon>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<MultiPolygon> MultiPolygon::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/multi_polygon.hpp b/platform/android/src/geojson/multi_polygon.hpp new file mode 100644 index 0000000000..1f144cffd2 --- /dev/null +++ b/platform/android/src/geojson/multi_polygon.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPolygon : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPolygon"; }; + + static constexpr auto Type() { return "MultiPolygon"; }; + + static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, jni::Object<MultiPolygon>); + + static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiPolygon>); + + static jni::Class<MultiPolygon> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp new file mode 100644 index 0000000000..3d19a119d7 --- /dev/null +++ b/platform/android/src/geojson/point.cpp @@ -0,0 +1,28 @@ +#include "point.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object<Point> jPoint) { + auto jPosition = Point::getPosition(env, jPoint); + auto point = Position::convert(env, jPosition); + jni::DeleteLocalRef(env, jPosition); + return point; +} + +jni::Object<Position> Point::getPosition(JNIEnv& env, jni::Object<Point> jPoint) { + static auto method = Point::javaClass.GetMethod<jni::Object<Position> ()>(env, "getCoordinates"); + return jPoint.Call(env, method); +} + +void Point::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Point>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Point> Point::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/point.hpp b/platform/android/src/geojson/point.hpp new file mode 100644 index 0000000000..64ac0af9cc --- /dev/null +++ b/platform/android/src/geojson/point.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include "position.hpp" + +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { +namespace geojson { + +class Point : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Point"; }; + + static constexpr auto Type() { return "Point"; }; + + static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<Point>); + + static jni::Object<Position> getPosition(JNIEnv&, jni::Object<Point>); + + static jni::Class<Point> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/polygon.cpp b/platform/android/src/geojson/polygon.cpp new file mode 100644 index 0000000000..bb37b8d99e --- /dev/null +++ b/platform/android/src/geojson/polygon.cpp @@ -0,0 +1,48 @@ +#include "polygon.hpp" + +#include "multi_line_string.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<Polygon> jPolygon) { + mapbox::geojson::polygon polygon; + + if (jPolygon) { + auto jPositionListsList = Polygon::getCoordinates(env, jPolygon); + polygon = Polygon::convert(env, jPositionListsList); + jni::DeleteLocalRef(env, jPositionListsList); + } + + return polygon; +} + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Position>>*/> jPositionListsList) { + mapbox::geojson::polygon polygon; + + if (jPositionListsList) { + auto multiLine = MultiLineString::convert(env, jPositionListsList); + polygon.reserve(multiLine.size()); + polygon.insert(std::end(polygon), std::begin(multiLine), std::end(multiLine)); + } + + return polygon; +} + + +jni::Object<java::util::List> Polygon::getCoordinates(jni::JNIEnv &env, jni::Object<Polygon> jPolygon) { + static auto method = Polygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); + return jPolygon.Call(env, method); +} + +void Polygon::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Polygon>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Polygon> Polygon::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/polygon.hpp b/platform/android/src/geojson/polygon.hpp new file mode 100644 index 0000000000..e5362cedf1 --- /dev/null +++ b/platform/android/src/geojson/polygon.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class Polygon : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Polygon"; }; + + static constexpr auto Type() { return "Polygon"; }; + + static mapbox::geojson::polygon convert(jni::JNIEnv &, jni::Object<Polygon>); + + static mapbox::geojson::polygon convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Position>>*/>); + + static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<Polygon>); + + static jni::Class<Polygon> javaClass; + + static void registerNative(jni::JNIEnv &); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/position.cpp b/platform/android/src/geojson/position.cpp new file mode 100644 index 0000000000..c0e6da3887 --- /dev/null +++ b/platform/android/src/geojson/position.cpp @@ -0,0 +1,27 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::point Position::convert(jni::JNIEnv &env, jni::Object<Position> jPosition) { + static auto method = Position::javaClass.GetMethod<jni::Array<jdouble> ()>(env, "getCoordinates"); + // Array with 0: longitude, 1: latitude (and optionally 2: altitude) + auto coordinates = jPosition.Call(env, method); + jdouble lngLat[2]; + coordinates.GetRegion(env, 0, lngLat); + mapbox::geojson::point point(lngLat[0], lngLat[1]); + jni::DeleteLocalRef(env, coordinates); + return point; +} + +void Position::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Position>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Position> Position::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/position.hpp b/platform/android/src/geojson/position.hpp new file mode 100644 index 0000000000..7017a8172a --- /dev/null +++ b/platform/android/src/geojson/position.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <mbgl/util/geojson.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { +namespace geojson { + +class Position : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/models/Position"; }; + + static constexpr auto Type() { return "Position"; }; + + static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<Position>); + + static jni::Class<Position> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file |