[android] - expose query feature extensions
This commit is contained in:
@@ -285,6 +285,54 @@ public class GeoJsonSource extends Source {
|
||||
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the children of a cluster (on the next zoom level) given its id (cluster_id value from feature properties).
|
||||
* <p>
|
||||
* Requires configuring this source as a cluster by calling {@link GeoJsonOptions#withCluster(boolean)}.
|
||||
* </p>
|
||||
*
|
||||
* @param cluster cluster from which to retrieve children from
|
||||
* @return a list of features for the underlying children
|
||||
*/
|
||||
@NonNull
|
||||
public FeatureCollection getClusterChildren(@NonNull Feature cluster) {
|
||||
checkThread();
|
||||
return FeatureCollection.fromFeatures(nativeGetClusterChildren(cluster));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the leaves of a cluster (given its cluster_id), with pagination support: limit is the number of leaves
|
||||
* to return (set to Infinity for all points), and offset is the amount of points to skip (for pagination).
|
||||
* <p>
|
||||
* Requires configuring this source as a cluster by calling {@link GeoJsonOptions#withCluster(boolean)}.
|
||||
* </p>
|
||||
*
|
||||
* @param cluster cluster from which to retrieve leaves from
|
||||
* @param limit limit is the number of points to return
|
||||
* @param offset offset is the amount of points to skip (for pagination)
|
||||
* @return a list of features for the underlying leaves
|
||||
*/
|
||||
@NonNull
|
||||
public FeatureCollection getClusterLeaves(@NonNull Feature cluster, long limit, long offset) {
|
||||
checkThread();
|
||||
return FeatureCollection.fromFeatures(nativeGetClusterLeaves(cluster, limit, offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the zoom on which the cluster expands into several children (useful for "click to zoom" feature)
|
||||
* given the cluster's cluster_id (cluster_id value from feature properties).
|
||||
* <p>
|
||||
* Requires configuring this source as a cluster by calling {@link GeoJsonOptions#withCluster(boolean)}.
|
||||
* </p>
|
||||
*
|
||||
* @param cluster cluster from which to retrieve the expansion zoom from
|
||||
* @return the zoom on which the cluster expands into several children
|
||||
*/
|
||||
public int getClusterExpansionZoom(@NonNull Feature cluster) {
|
||||
checkThread();
|
||||
return nativeGetClusterExpansionZoom(cluster);
|
||||
}
|
||||
|
||||
@Keep
|
||||
protected native void initialize(String layerId, Object options);
|
||||
|
||||
@@ -311,6 +359,15 @@ public class GeoJsonSource extends Source {
|
||||
@Keep
|
||||
private native Feature[] querySourceFeatures(Object[] filter);
|
||||
|
||||
@Keep
|
||||
private native Feature[] nativeGetClusterChildren(Feature feature);
|
||||
|
||||
@Keep
|
||||
private native Feature[] nativeGetClusterLeaves(Feature feature, long limit, long offset);
|
||||
|
||||
@Keep
|
||||
private native int nativeGetClusterExpansionZoom(Feature feature);
|
||||
|
||||
@Override
|
||||
@Keep
|
||||
protected native void finalize() throws Throwable;
|
||||
|
||||
@@ -802,14 +802,14 @@ class LocationComponentTest : EspressoTest() {
|
||||
assertThat(mapboxMap.style?.getSource(LOCATION_SOURCE), notNullValue())
|
||||
mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
|
||||
mapboxMap.waitForSource(uiController, LOCATION_SOURCE)
|
||||
assertEquals(77.0, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING) as Double, 0.1)
|
||||
assertEquals(77f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f)
|
||||
|
||||
location.bearing = 92f
|
||||
component.forceLocationUpdate(location)
|
||||
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY) // Waiting for the animation to finish
|
||||
mapboxMap.waitForSource(uiController, LOCATION_SOURCE)
|
||||
mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
|
||||
assertEquals(92.0, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING) as Double, 0.1)
|
||||
assertEquals(92.0f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,15 @@
|
||||
package com.mapbox.mapboxsdk.testapp.activity.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.content.res.ResourcesCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
import com.mapbox.geojson.Feature;
|
||||
import com.mapbox.geojson.FeatureCollection;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
@@ -16,11 +21,13 @@ 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;
|
||||
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil;
|
||||
import com.mapbox.mapboxsdk.utils.BitmapUtils;
|
||||
import timber.log.Timber;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.division;
|
||||
@@ -54,6 +61,9 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
|
||||
private MapView mapView;
|
||||
private MapboxMap mapboxMap;
|
||||
|
||||
private GeoJsonSource clusterSource;
|
||||
private int clickOptionCounter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -68,19 +78,119 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
|
||||
mapboxMap = map;
|
||||
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.7749, 122.4194), 0));
|
||||
|
||||
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
|
||||
@Override
|
||||
public void onStyleLoaded(Style style) {
|
||||
style.addImage(
|
||||
"icon-id",
|
||||
BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.ic_hearing_black_24dp)),
|
||||
true
|
||||
);
|
||||
// Add a clustered source with some layers
|
||||
addClusteredGeoJsonSource(style);
|
||||
final int[][] clusterLayers = new int[][] {
|
||||
new int[] {150, ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme())},
|
||||
new int[] {20, ResourcesCompat.getColor(getResources(), R.color.greenAccent, getTheme())},
|
||||
new int[] {0, ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme())}
|
||||
};
|
||||
|
||||
try {
|
||||
mapboxMap.setStyle(new Style.Builder()
|
||||
.fromUrl(Style.LIGHT)
|
||||
.withSource(clusterSource = createClusterSource())
|
||||
.withLayer(createSymbolLayer())
|
||||
.withLayer(createClusterLevelLayer(0, clusterLayers))
|
||||
.withLayer(createClusterLevelLayer(1, clusterLayers))
|
||||
.withLayer(createClusterLevelLayer(2, clusterLayers))
|
||||
.withLayer(createClusterTextLayer())
|
||||
.withImage("icon-id", Objects.requireNonNull(
|
||||
BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.ic_hearing_black_24dp))), true
|
||||
)
|
||||
);
|
||||
} catch (IOException exception) {
|
||||
Timber.e(exception);
|
||||
}
|
||||
|
||||
mapboxMap.addOnMapClickListener(latLng -> {
|
||||
PointF point = mapboxMap.getProjection().toScreenLocation(latLng);
|
||||
List<Feature> features = mapboxMap.queryRenderedFeatures(point, "cluster-0", "cluster-1", "cluster-2");
|
||||
if (!features.isEmpty()) {
|
||||
onClusterClick(features.get(0), new Point((int) point.x, (int) point.y));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
findViewById(R.id.fab).setOnClickListener(v -> {
|
||||
updateClickOptionCounter();
|
||||
notifyClickOptionUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
private void onClusterClick(Feature cluster, Point clickPoint) {
|
||||
if (clickOptionCounter == 0) {
|
||||
double nextZoomLevel = clusterSource.getClusterExpansionZoom(cluster);
|
||||
double zoomDelta = nextZoomLevel - mapboxMap.getCameraPosition().zoom;
|
||||
mapboxMap.animateCamera(CameraUpdateFactory.zoomBy(zoomDelta, clickPoint));
|
||||
Toast.makeText(this, "Zooming to " + nextZoomLevel, Toast.LENGTH_SHORT).show();
|
||||
} else if (clickOptionCounter == 1) {
|
||||
FeatureCollection collection = clusterSource.getClusterChildren(cluster);
|
||||
Toast.makeText(this, "Children: " + collection.toJson(), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
FeatureCollection collection = clusterSource.getClusterLeaves(cluster, 2, 1);
|
||||
Toast.makeText(this, "Leaves: " + collection.toJson(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private GeoJsonSource createClusterSource() throws IOException {
|
||||
String earthQuakes = GeoParseUtil.loadStringFromAssets(this, "earthquakes.geojson");
|
||||
FeatureCollection featureCollection = FeatureCollection.fromJson(earthQuakes);
|
||||
return new GeoJsonSource("earthquakes", featureCollection, new GeoJsonOptions()
|
||||
.withCluster(true)
|
||||
.withClusterMaxZoom(14)
|
||||
.withClusterRadius(50)
|
||||
);
|
||||
}
|
||||
|
||||
private SymbolLayer createSymbolLayer() {
|
||||
return new SymbolLayer("unclustered-points", "earthquakes")
|
||||
.withProperties(
|
||||
iconImage("icon-id"),
|
||||
iconSize(
|
||||
division(
|
||||
get("mag"), literal(4.0f)
|
||||
)
|
||||
),
|
||||
iconColor(
|
||||
interpolate(exponential(1), get("mag"),
|
||||
stop(2.0, rgb(0, 255, 0)),
|
||||
stop(4.5, rgb(0, 0, 255)),
|
||||
stop(7.0, rgb(255, 0, 0))
|
||||
)
|
||||
)
|
||||
)
|
||||
.withFilter(has("mag"));
|
||||
}
|
||||
|
||||
private CircleLayer createClusterLevelLayer(int level, int[][] layerColors) {
|
||||
CircleLayer circles = new CircleLayer("cluster-" + level, "earthquakes");
|
||||
circles.setProperties(
|
||||
circleColor(layerColors[level][1]),
|
||||
circleRadius(18f)
|
||||
);
|
||||
|
||||
Expression pointCount = toNumber(get("point_count"));
|
||||
circles.setFilter(
|
||||
level == 0
|
||||
? all(has("point_count"),
|
||||
gte(pointCount, literal(layerColors[level][0]))
|
||||
) : all(has("point_count"),
|
||||
gt(pointCount, literal(layerColors[level][0])),
|
||||
lt(pointCount, literal(layerColors[level - 1][0]))
|
||||
)
|
||||
);
|
||||
return circles;
|
||||
}
|
||||
|
||||
private SymbolLayer createClusterTextLayer() {
|
||||
return new SymbolLayer("count", "earthquakes")
|
||||
.withProperties(
|
||||
textField(Expression.toString(get("point_count"))),
|
||||
textSize(12f),
|
||||
textColor(Color.WHITE),
|
||||
textIgnorePlacement(true),
|
||||
textAllowOverlap(true)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,82 +246,30 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void addClusteredGeoJsonSource(Style style) {
|
||||
// Add a clustered source
|
||||
try {
|
||||
style.addSource(
|
||||
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) {
|
||||
Timber.e(malformedUrlException, "That's not an url... ");
|
||||
private void updateClickOptionCounter() {
|
||||
if (clickOptionCounter == 2) {
|
||||
clickOptionCounter = 0;
|
||||
} else {
|
||||
clickOptionCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add unclustered layer
|
||||
int[][] layers = new int[][] {
|
||||
new int[] {150, ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme())},
|
||||
new int[] {20, ResourcesCompat.getColor(getResources(), R.color.greenAccent, getTheme())},
|
||||
new int[] {0, ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme())}
|
||||
};
|
||||
|
||||
SymbolLayer unclustered = new SymbolLayer("unclustered-points", "earthquakes");
|
||||
unclustered.setProperties(
|
||||
iconImage("icon-id"),
|
||||
iconSize(
|
||||
division(
|
||||
get("mag"), literal(4.0f)
|
||||
)
|
||||
),
|
||||
iconColor(
|
||||
interpolate(exponential(1), get("mag"),
|
||||
stop(2.0, rgb(0, 255, 0)),
|
||||
stop(4.5, rgb(0, 0, 255)),
|
||||
stop(7.0, rgb(255, 0, 0))
|
||||
)
|
||||
)
|
||||
);
|
||||
unclustered.setFilter(has("mag"));
|
||||
style.addLayer(unclustered);
|
||||
|
||||
for (int i = 0; i < layers.length; i++) {
|
||||
// Add some nice circles
|
||||
CircleLayer circles = new CircleLayer("cluster-" + i, "earthquakes");
|
||||
circles.setProperties(
|
||||
circleColor(layers[i][1]),
|
||||
circleRadius(18f)
|
||||
);
|
||||
|
||||
Expression pointCount = toNumber(get("point_count"));
|
||||
circles.setFilter(
|
||||
i == 0
|
||||
? all(has("point_count"),
|
||||
gte(pointCount, literal(layers[i][0]))
|
||||
) : all(has("point_count"),
|
||||
gt(pointCount, literal(layers[i][0])),
|
||||
lt(pointCount, literal(layers[i - 1][0]))
|
||||
)
|
||||
);
|
||||
style.addLayer(circles);
|
||||
private void notifyClickOptionUpdate() {
|
||||
if (clickOptionCounter == 0) {
|
||||
Toast.makeText(
|
||||
GeoJsonClusteringActivity.this,
|
||||
"Clicking a cluster will zoom to the level where it dissolves",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
} else if (clickOptionCounter == 1) {
|
||||
Toast.makeText(
|
||||
GeoJsonClusteringActivity.this,
|
||||
"Clicking a cluster will show the details of the cluster children",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(
|
||||
GeoJsonClusteringActivity.this,
|
||||
"Clicking a cluster will show the details of the cluster leaves with an offset and limit",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
// Add the count labels
|
||||
SymbolLayer count = new SymbolLayer("count", "earthquakes");
|
||||
count.setProperties(
|
||||
textField(Expression.toString(get("point_count"))),
|
||||
textSize(12f),
|
||||
textColor(Color.WHITE),
|
||||
textIgnorePlacement(true),
|
||||
textAllowOverlap(true)
|
||||
);
|
||||
style.addLayer(count);
|
||||
|
||||
|
||||
// Zoom out to start
|
||||
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/coordinator_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.mapbox.mapboxsdk.maps.MapView
|
||||
android:id="@+id/mapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
android:id="@id/mapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</RelativeLayout>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
android:src="@drawable/ic_refresh"
|
||||
app:backgroundTint="@color/primaryDark"/>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"platform/android/src/gson/json_primitive.cpp",
|
||||
"platform/android/src/image.cpp",
|
||||
"platform/android/src/java/util.cpp",
|
||||
"platform/android/src/math/math.cpp",
|
||||
"platform/android/src/java_types.cpp",
|
||||
"platform/android/src/jni.cpp",
|
||||
"platform/android/src/logger.cpp",
|
||||
@@ -141,6 +142,7 @@
|
||||
"gson/json_object.hpp": "platform/android/src/gson/json_object.hpp",
|
||||
"gson/json_primitive.hpp": "platform/android/src/gson/json_primitive.hpp",
|
||||
"java/util.hpp": "platform/android/src/java/util.hpp",
|
||||
"math/math.hpp": "platform/android/src/math/math.hpp",
|
||||
"java_types.hpp": "platform/android/src/java_types.hpp",
|
||||
"jni.hpp": "platform/android/src/jni.hpp",
|
||||
"logger.hpp": "platform/android/src/logger.hpp",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mbgl/util/async_task.hpp>
|
||||
#include <mbgl/util/thread.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
|
||||
#include "android_renderer_backend.hpp"
|
||||
|
||||
@@ -122,6 +123,14 @@ AnnotationIDs AndroidRendererFrontend::queryShapeAnnotations(const ScreenBox& bo
|
||||
return mapRenderer.actor().ask(&Renderer::queryShapeAnnotations, box).get();
|
||||
}
|
||||
|
||||
FeatureExtensionValue AndroidRendererFrontend::queryFeatureExtensions(const std::string& sourceID,
|
||||
const Feature& feature,
|
||||
const std::string& extension,
|
||||
const std::string& extensionField,
|
||||
const optional<std::map<std::string, mbgl::Value>>& args) const {
|
||||
return mapRenderer.actor().ask(&Renderer::queryFeatureExtensions, sourceID, feature, extension, extensionField, args).get();
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
|
||||
#include "map_renderer.hpp"
|
||||
|
||||
@@ -44,6 +45,15 @@ public:
|
||||
AnnotationIDs queryPointAnnotations(const ScreenBox& box) const;
|
||||
AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const;
|
||||
|
||||
|
||||
// Feature extension query
|
||||
FeatureExtensionValue
|
||||
queryFeatureExtensions(const std::string& sourceID,
|
||||
const Feature& feature,
|
||||
const std::string& extension,
|
||||
const std::string& extensionField,
|
||||
const optional<std::map<std::string, mbgl::Value>>& args) const;
|
||||
|
||||
// Memory
|
||||
void reduceMemoryUse();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "json_array.hpp"
|
||||
#include "json_object.hpp"
|
||||
#include "json_primitive.hpp"
|
||||
#include "../math/math.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
@@ -58,13 +59,21 @@ mbgl::Value JsonElement::convert(jni::JNIEnv &env, const jni::Object<JsonElement
|
||||
static auto getAsBoolean = primitiveClass.GetMethod<jni::jboolean ()>(env, "getAsBoolean");
|
||||
static auto getAsString = primitiveClass.GetMethod<jni::String ()>(env, "getAsString");
|
||||
static auto getAsDouble = primitiveClass.GetMethod<jni::jdouble ()>(env, "getAsDouble");
|
||||
static auto getAsInteger = primitiveClass.GetMethod<jni::jint ()>(env, "getAsInt");
|
||||
|
||||
if (jsonElement.Call(env, isJsonPrimitive)) {
|
||||
auto primitive = jni::Cast(env, primitiveClass, jsonElement);
|
||||
if (primitive.Call(env, isBoolean)) {
|
||||
return bool(primitive.Call(env, getAsBoolean));
|
||||
} else if (primitive.Call(env, isNumber)) {
|
||||
return primitive.Call(env, getAsDouble); // TODO: how to differentiate types here?
|
||||
auto value = primitive.Call(env, getAsDouble);
|
||||
if (value == math::Math::rint(env, value)) {
|
||||
// uint64_t
|
||||
return static_cast<uint64_t>(primitive.Call(env, getAsInteger));
|
||||
} else {
|
||||
// double
|
||||
return value;
|
||||
}
|
||||
} else if (primitive.Call(env, isString)) {
|
||||
return jni::Make<std::string>(env, primitive.Call(env, getAsString));
|
||||
} else {
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "text/collator_jni.hpp"
|
||||
#include "text/local_glyph_rasterizer_jni.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "math/math.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
@@ -114,6 +115,7 @@ void registerNatives(JavaVM *vm) {
|
||||
// Basic types
|
||||
java::registerNatives(env);
|
||||
java::util::registerNative(env);
|
||||
math::registerNative(env);
|
||||
PointF::registerNative(env);
|
||||
RectF::registerNative(env);
|
||||
|
||||
|
||||
13
platform/android/src/math/math.cpp
Normal file
13
platform/android/src/math/math.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "math.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
namespace math {
|
||||
|
||||
void registerNative(jni::JNIEnv& env) {
|
||||
jni::Class<Math>::Singleton(env);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
26
platform/android/src/math/math.hpp
Normal file
26
platform/android/src/math/math.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
namespace math {
|
||||
|
||||
class Math : private mbgl::util::noncopyable {
|
||||
public:
|
||||
static constexpr auto Name() { return "java/lang/Math"; };
|
||||
|
||||
static jni::jdouble rint(jni::JNIEnv& env, const jni::jdouble value) {
|
||||
static auto& javaClass = jni::Class<Math>::Singleton(env);
|
||||
static auto method = javaClass.GetStaticMethod<jni::jdouble (jni::jdouble)>(env, "rint");
|
||||
return javaClass.Call(env, method, value);
|
||||
};
|
||||
};
|
||||
|
||||
void registerNative(jni::JNIEnv&);
|
||||
|
||||
} // namespace math
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
@@ -108,6 +108,53 @@ namespace android {
|
||||
return Feature::convert(env, features);
|
||||
}
|
||||
|
||||
jni::Local<jni::Array<jni::Object<geojson::Feature>>> GeoJSONSource::getClusterChildren(jni::JNIEnv& env, const jni::Object<geojson::Feature>& feature) {
|
||||
using namespace mbgl::android::conversion;
|
||||
using namespace mbgl::android::geojson;
|
||||
|
||||
if (rendererFrontend) {
|
||||
mbgl::Feature _feature = Feature::convert(env, feature);
|
||||
const auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "children", {});
|
||||
if (featureExtension.is<mbgl::FeatureCollection>()) {
|
||||
return Feature::convert(env, featureExtension.get<mbgl::FeatureCollection>());
|
||||
}
|
||||
}
|
||||
return jni::Array<jni::Object<Feature>>::New(env, 0);
|
||||
}
|
||||
|
||||
jni::Local<jni::Array<jni::Object<geojson::Feature>>> GeoJSONSource::getClusterLeaves(jni::JNIEnv& env, const jni::Object<geojson::Feature>& feature, jni::jlong limit, jni::jlong offset) {
|
||||
using namespace mbgl::android::conversion;
|
||||
using namespace mbgl::android::geojson;
|
||||
|
||||
if (rendererFrontend) {
|
||||
mbgl::Feature _feature = Feature::convert(env, feature);
|
||||
const std::map<std::string, mbgl::Value> options = { {"limit", static_cast<uint64_t>(limit)},
|
||||
{"offset", static_cast<uint64_t>(offset)} };
|
||||
auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "leaves", options);
|
||||
if (featureExtension.is<mbgl::FeatureCollection>()) {
|
||||
return Feature::convert(env, featureExtension.get<mbgl::FeatureCollection>());
|
||||
}
|
||||
}
|
||||
return jni::Array<jni::Object<Feature>>::New(env, 0);;
|
||||
}
|
||||
|
||||
jint GeoJSONSource::getClusterExpansionZoom(jni::JNIEnv& env, const jni::Object<geojson::Feature>& feature) {
|
||||
using namespace mbgl::android::conversion;
|
||||
using namespace mbgl::android::geojson;
|
||||
|
||||
if (rendererFrontend) {
|
||||
mbgl::Feature _feature = Feature::convert(env, feature);
|
||||
auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "expansion-zoom", {});
|
||||
if (featureExtension.is<mbgl::Value>()) {
|
||||
auto value = featureExtension.get<mbgl::Value>();
|
||||
if (value.is<uint64_t>()) {
|
||||
return value.get<uint64_t>();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
jni::Local<jni::Object<Source>> GeoJSONSource::createJavaPeer(jni::JNIEnv& env) {
|
||||
static auto& javaClass = jni::Class<GeoJSONSource>::Singleton(env);
|
||||
static auto constructor = javaClass.GetConstructor<jni::jlong>(env);
|
||||
@@ -176,7 +223,10 @@ namespace android {
|
||||
METHOD(&GeoJSONSource::setGeometry, "nativeSetGeometry"),
|
||||
METHOD(&GeoJSONSource::setURL, "nativeSetUrl"),
|
||||
METHOD(&GeoJSONSource::getURL, "nativeGetUrl"),
|
||||
METHOD(&GeoJSONSource::querySourceFeatures, "querySourceFeatures")
|
||||
METHOD(&GeoJSONSource::querySourceFeatures, "querySourceFeatures"),
|
||||
METHOD(&GeoJSONSource::getClusterChildren, "nativeGetClusterChildren"),
|
||||
METHOD(&GeoJSONSource::getClusterLeaves, "nativeGetClusterLeaves"),
|
||||
METHOD(&GeoJSONSource::getClusterExpansionZoom, "nativeGetClusterExpansionZoom")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../../geojson/geometry.hpp"
|
||||
#include "../../geojson/feature.hpp"
|
||||
#include "../../geojson/feature_collection.hpp"
|
||||
#include "../../android_renderer_frontend.hpp"
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -49,6 +50,10 @@ private:
|
||||
jni::Local<jni::Array<jni::Object<geojson::Feature>>> querySourceFeatures(jni::JNIEnv&,
|
||||
const jni::Array<jni::Object<>>&);
|
||||
|
||||
jni::Local<jni::Array<jni::Object<geojson::Feature>>> getClusterChildren(jni::JNIEnv&, const jni::Object<geojson::Feature>&);
|
||||
jni::Local<jni::Array<jni::Object<geojson::Feature>>> getClusterLeaves(jni::JNIEnv&, const jni::Object<geojson::Feature>&, jni::jlong, jni::jlong);
|
||||
jint getClusterExpansionZoom(jni::JNIEnv&, const jni::Object<geojson::Feature>&);
|
||||
|
||||
jni::Local<jni::String> getURL(jni::JNIEnv&);
|
||||
|
||||
jni::Local<jni::Object<Source>> createJavaPeer(jni::JNIEnv&);
|
||||
|
||||
Reference in New Issue
Block a user