summaryrefslogtreecommitdiff
path: root/platform/android/src/style/sources/custom_geometry_source.cpp
blob: 205fe55ed9fa0139e4398c957334381845b10b0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "custom_geometry_source.hpp"

#include <mbgl/renderer/query.hpp>

// Java -> C++ conversion
#include "../android_conversion.hpp"
#include "../conversion/filter.hpp"
//#include "../conversion/geojson.hpp"

// C++ -> Java conversion
#include "../../conversion/conversion.hpp"
#include "../../conversion/collection.hpp"
#include "../../geojson/conversion/feature.hpp"
#include <mbgl/style/conversion/custom_geometry_source_options.hpp>

#include <string>

namespace mbgl {
namespace android {

    // This conversion is expected not to fail because it's used only in contexts where
    // the value was originally a GeoJsonOptions object on the Java side. If it fails
    // to convert, it's a bug in our serialization or Java-side static typing.
    static style::CustomGeometrySource::Options convertCustomGeometrySourceOptions(jni::JNIEnv& env, jni::Object<> options, style::TileFunction fetchFn, style::TileFunction cancelFn) {
        using namespace mbgl::style::conversion;
        if (!options) {
            return style::CustomGeometrySource::Options();
        }
        Error error;
        optional<style::CustomGeometrySource::Options> result = convert<style::CustomGeometrySource::Options>(Value(env, options), error);
        if (!result) {
            throw std::logic_error(error.message);
        }
        result->fetchTileFunction = fetchFn;
        result->cancelTileFunction = cancelFn;
        return *result;
    }

    CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, jni::Object<CustomGeometrySource> _obj, jni::String sourceId, jni::Object<> options)
        : Source(env, std::make_unique<mbgl::style::CustomGeometrySource>(
            jni::Make<std::string>(env, sourceId),
            convertCustomGeometrySourceOptions(env,
                options,
                std::bind(&CustomGeometrySource::fetchTile, this, std::placeholders::_1),
                std::bind(&CustomGeometrySource::cancelTile, this, std::placeholders::_1))) ),
        javaPeer(_obj.NewGlobalRef(env))  {
    }

    CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env,
                                               mbgl::style::Source& coreSource,
                                               AndroidRendererFrontend& frontend)
        : Source(env, coreSource, createJavaPeer(env), frontend) {
    }

    CustomGeometrySource::~CustomGeometrySource() = default;

    void CustomGeometrySource::fetchTile (const mbgl::CanonicalTileID& tileID) {
        android::UniqueEnv _env = android::AttachEnv();
        static auto fetchTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "fetchTile");
        assert(javaPeer);
        javaPeer->Call(*_env, fetchTile, (int)tileID.z, (int)tileID.x, (int)tileID.y);
    };

    void CustomGeometrySource::cancelTile(const mbgl::CanonicalTileID& tileID) {
        android::UniqueEnv _env = android::AttachEnv();
        static auto cancelTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "cancelTile");
        assert(javaPeer);
        javaPeer->Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y);
    };

    void CustomGeometrySource::setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, jni::Object<geojson::FeatureCollection> jFeatures) {
        using namespace mbgl::android::geojson;

        // Convert the jni object
        auto geometry = geojson::FeatureCollection::convert(env, jFeatures);

        // Update the core source
        source.as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry));
    }

    void CustomGeometrySource::invalidateTile(jni::JNIEnv&, jni::jint z, jni::jint x, jni::jint y) {
        source.as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateTile(CanonicalTileID(z, x, y));
    }
    void CustomGeometrySource::invalidateBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> jBounds) {
        auto bounds = LatLngBounds::getLatLngBounds(env, jBounds);
        source.as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateRegion(bounds);
    }

    jni::Array<jni::Object<geojson::Feature>> CustomGeometrySource::querySourceFeatures(jni::JNIEnv& env,
                                                                        jni::Array<jni::Object<>> jfilter) {
        using namespace mbgl::android::conversion;
        using namespace mbgl::android::geojson;

        std::vector<mbgl::Feature> features;
        if (rendererFrontend) {
            features = rendererFrontend->querySourceFeatures(source.getID(), { {},  toFilter(env, jfilter) });
        }
        return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, features);
    }

    jni::Class<CustomGeometrySource> CustomGeometrySource::javaClass;

    jni::Object<Source> CustomGeometrySource::createJavaPeer(jni::JNIEnv& env) {
        static auto constructor = CustomGeometrySource::javaClass.template GetConstructor<jni::jlong>(env);
        return jni::Object<Source>(CustomGeometrySource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get());
    }

    void CustomGeometrySource::registerNative(jni::JNIEnv& env) {
        // Lookup the class
        CustomGeometrySource::javaClass = *jni::Class<CustomGeometrySource>::Find(env).NewGlobalRef(env).release();

        #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)

        // Register the peer
        jni::RegisterNativePeer<CustomGeometrySource>(
            env, CustomGeometrySource::javaClass, "nativePtr",
            std::make_unique<CustomGeometrySource, JNIEnv&, jni::Object<CustomGeometrySource>, jni::String, jni::Object<>>,
            "initialize",
            "finalize",
            METHOD(&CustomGeometrySource::querySourceFeatures, "querySourceFeatures"),
            METHOD(&CustomGeometrySource::setTileData, "nativeSetTileData"),
            METHOD(&CustomGeometrySource::invalidateTile, "nativeInvalidateTile"),
            METHOD(&CustomGeometrySource::invalidateBounds, "nativeInvalidateBounds")
        );
    }

} // namespace android
} // namespace mbgl