Cherry pick latlngbounds to release branch (#8788)
* [android] - move calculation of LatLngBounds to core * [core] Ignore shortest path in Map::pixelForLatLng * [android] - convert camera position values coming from core (#8794)
This commit is contained in:
@@ -231,24 +231,6 @@ public final class CameraPosition implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Builder from an existing array of doubles.
|
||||
* <p>
|
||||
* These values conform to map.ccp representation of a camera position.
|
||||
* </p>
|
||||
*
|
||||
* @param nativeCameraValues Values containing target, bearing, tilt and zoom
|
||||
*/
|
||||
public Builder(double[] nativeCameraValues) {
|
||||
super();
|
||||
if (nativeCameraValues != null && nativeCameraValues.length == 5) {
|
||||
target(new LatLng(nativeCameraValues[0], nativeCameraValues[1]).wrap());
|
||||
bearing(MathUtils.convertNativeBearing(nativeCameraValues[2]));
|
||||
tilt(nativeCameraValues[3]);
|
||||
zoom(nativeCameraValues[4]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the direction that the camera is pointing in, in degrees clockwise from north.
|
||||
*
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.mapbox.mapboxsdk.camera;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
@@ -11,7 +10,6 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.Projection;
|
||||
import com.mapbox.mapboxsdk.maps.UiSettings;
|
||||
import com.mapbox.services.android.telemetry.utils.MathUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -199,15 +197,11 @@ public final class CameraUpdateFactory {
|
||||
static final class CameraBoundsUpdate implements CameraUpdate {
|
||||
|
||||
private LatLngBounds bounds;
|
||||
private RectF padding;
|
||||
|
||||
CameraBoundsUpdate(LatLngBounds bounds, RectF padding) {
|
||||
this.bounds = bounds;
|
||||
this.padding = padding;
|
||||
}
|
||||
private int[] padding;
|
||||
|
||||
CameraBoundsUpdate(LatLngBounds bounds, int[] padding) {
|
||||
this(bounds, new RectF(padding[0], padding[1], padding[2], padding[3]));
|
||||
this.bounds = bounds;
|
||||
this.padding = padding;
|
||||
}
|
||||
|
||||
CameraBoundsUpdate(LatLngBounds bounds, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
|
||||
@@ -218,64 +212,13 @@ public final class CameraUpdateFactory {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public RectF getPadding() {
|
||||
public int[] getPadding() {
|
||||
return padding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) {
|
||||
// Get required objects
|
||||
Projection projection = mapboxMap.getProjection();
|
||||
UiSettings uiSettings = mapboxMap.getUiSettings();
|
||||
|
||||
// calculate correct padding
|
||||
int[] mapPadding = mapboxMap.getPadding();
|
||||
RectF latLngPadding = getPadding();
|
||||
RectF padding = new RectF(latLngPadding.left + mapPadding[0],
|
||||
latLngPadding.top + mapPadding[1],
|
||||
latLngPadding.right + mapPadding[2],
|
||||
latLngPadding.bottom + mapPadding[3]);
|
||||
|
||||
// Calculate the bounds of the possibly rotated shape with respect to the viewport
|
||||
PointF nePixel = new PointF(-Float.MAX_VALUE, -Float.MAX_VALUE);
|
||||
PointF swPixel = new PointF(Float.MAX_VALUE, Float.MAX_VALUE);
|
||||
float viewportHeight = uiSettings.getHeight();
|
||||
for (LatLng latLng : getBounds().toLatLngs()) {
|
||||
PointF pixel = projection.toScreenLocation(latLng);
|
||||
swPixel.x = Math.min(swPixel.x, pixel.x);
|
||||
nePixel.x = Math.max(nePixel.x, pixel.x);
|
||||
swPixel.y = Math.min(swPixel.y, viewportHeight - pixel.y);
|
||||
nePixel.y = Math.max(nePixel.y, viewportHeight - pixel.y);
|
||||
}
|
||||
|
||||
// Calculate width/height
|
||||
float width = nePixel.x - swPixel.x;
|
||||
float height = nePixel.y - swPixel.y;
|
||||
|
||||
double zoom = 0;
|
||||
float minScale = 1;
|
||||
// Calculate the zoom level
|
||||
if (padding != null) {
|
||||
float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width;
|
||||
float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height;
|
||||
minScale = scaleX < scaleY ? scaleX : scaleY;
|
||||
zoom = projection.calculateZoom(minScale);
|
||||
zoom = MathUtils.clamp(zoom, mapboxMap.getMinZoomLevel(), mapboxMap.getMaxZoomLevel());
|
||||
}
|
||||
|
||||
// Calculate the center point
|
||||
PointF paddedNEPixel = new PointF(nePixel.x + padding.right / minScale, nePixel.y + padding.top / minScale);
|
||||
PointF paddedSWPixel = new PointF(swPixel.x - padding.left / minScale, swPixel.y - padding.bottom / minScale);
|
||||
PointF centerPixel = new PointF((paddedNEPixel.x + paddedSWPixel.x) / 2, (paddedNEPixel.y + paddedSWPixel.y) / 2);
|
||||
centerPixel.y = viewportHeight - centerPixel.y;
|
||||
LatLng center = projection.fromScreenLocation(centerPixel);
|
||||
|
||||
return new CameraPosition.Builder()
|
||||
.target(center)
|
||||
.zoom(zoom)
|
||||
.tilt(0)
|
||||
.bearing(0)
|
||||
.build();
|
||||
return mapboxMap.getCameraForLatLngBounds(bounds, padding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.mapbox.mapboxsdk.constants.MyBearingTracking;
|
||||
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
|
||||
import com.mapbox.mapboxsdk.constants.Style;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
|
||||
import com.mapbox.mapboxsdk.style.layers.Filter;
|
||||
import com.mapbox.mapboxsdk.style.layers.Layer;
|
||||
@@ -1504,6 +1505,32 @@ public final class MapboxMap {
|
||||
return annotationManager.getInfoWindowManager().isAllowConcurrentMultipleOpenInfoWindows();
|
||||
}
|
||||
|
||||
//
|
||||
// LatLngBounds
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Gets a camera position that would fit a bounds.
|
||||
*
|
||||
* @param latLngBounds the bounds to constrain the map with
|
||||
*/
|
||||
public CameraPosition getCameraForLatLngBounds(@Nullable LatLngBounds latLngBounds, int[] padding) {
|
||||
// calculate and set additional bounds padding
|
||||
int[] mapPadding = getPadding();
|
||||
for (int i = 0; i < padding.length; i++) {
|
||||
padding[i] = mapPadding[i] + padding[i];
|
||||
}
|
||||
projection.setContentPadding(padding, myLocationViewSettings.getPadding());
|
||||
|
||||
// get padded camera position from LatLngBounds
|
||||
CameraPosition cameraPosition = nativeMapView.getCameraForLatLngBounds(latLngBounds);
|
||||
|
||||
// reset map padding
|
||||
setPadding(mapPadding);
|
||||
return cameraPosition;
|
||||
}
|
||||
|
||||
//
|
||||
// Padding
|
||||
//
|
||||
@@ -1527,7 +1554,11 @@ public final class MapboxMap {
|
||||
* @param bottom The bottom margin in pixels.
|
||||
*/
|
||||
public void setPadding(int left, int top, int right, int bottom) {
|
||||
projection.setContentPadding(new int[] {left, top, right, bottom}, myLocationViewSettings.getPadding());
|
||||
setPadding(new int[] {left, top, right, bottom});
|
||||
}
|
||||
|
||||
private void setPadding(int[] padding) {
|
||||
projection.setContentPadding(padding, myLocationViewSettings.getPadding());
|
||||
uiSettings.invalidate();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,10 @@ import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
import com.mapbox.mapboxsdk.annotations.Polygon;
|
||||
import com.mapbox.mapboxsdk.annotations.Polyline;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.constants.MapboxConstants;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
|
||||
import com.mapbox.mapboxsdk.storage.FileSource;
|
||||
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
|
||||
@@ -309,6 +311,13 @@ final class NativeMapView {
|
||||
return nativeGetLatLng().wrap();
|
||||
}
|
||||
|
||||
public CameraPosition getCameraForLatLngBounds(LatLngBounds latLngBounds) {
|
||||
if (isDestroyedOn("getCameraForLatLngBounds")) {
|
||||
return null;
|
||||
}
|
||||
return nativeGetCameraForLatLngBounds(latLngBounds);
|
||||
}
|
||||
|
||||
public void resetPosition() {
|
||||
if (isDestroyedOn("resetPosition")) {
|
||||
return;
|
||||
@@ -717,11 +726,11 @@ final class NativeMapView {
|
||||
nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
|
||||
}
|
||||
|
||||
public double[] getCameraValues() {
|
||||
public CameraPosition getCameraPosition() {
|
||||
if (isDestroyedOn("getCameraValues")) {
|
||||
return new double[] {};
|
||||
return new CameraPosition.Builder().build();
|
||||
}
|
||||
return nativeGetCameraValues();
|
||||
return nativeGetCameraPosition();
|
||||
}
|
||||
|
||||
// Runtime style Api
|
||||
@@ -1005,6 +1014,8 @@ final class NativeMapView {
|
||||
|
||||
private native LatLng nativeGetLatLng();
|
||||
|
||||
private native CameraPosition nativeGetCameraForLatLngBounds(LatLngBounds latLngBounds);
|
||||
|
||||
private native void nativeResetPosition();
|
||||
|
||||
private native double nativeGetPitch();
|
||||
@@ -1095,7 +1106,7 @@ final class NativeMapView {
|
||||
private native void nativeFlyTo(double angle, double latitude, double longitude,
|
||||
long duration, double pitch, double zoom);
|
||||
|
||||
private native double[] nativeGetCameraValues();
|
||||
private native CameraPosition nativeGetCameraPosition();
|
||||
|
||||
private native long nativeGetTransitionDuration();
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ final class Transform implements MapView.OnMapChangedListener {
|
||||
@Nullable
|
||||
CameraPosition invalidateCameraPosition() {
|
||||
if (mapView != null) {
|
||||
cameraPosition = new CameraPosition.Builder(mapView.getCameraValues()).build();
|
||||
cameraPosition = mapView.getCameraPosition();
|
||||
if (onCameraChangeListener != null) {
|
||||
onCameraChangeListener.onCameraChange(this.cameraPosition);
|
||||
}
|
||||
|
||||
@@ -110,8 +110,7 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
|
||||
* @param bearing the direction value of the map
|
||||
*/
|
||||
public void update(final double bearing) {
|
||||
// compass needs reverse bearing #8123
|
||||
rotation = (float) -bearing;
|
||||
rotation = (float) bearing;
|
||||
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.mapbox.mapboxsdk.testapp.activity.camera;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.constants.Style;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
@@ -11,14 +13,8 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||
import com.mapbox.mapboxsdk.maps.UiSettings;
|
||||
import com.mapbox.mapboxsdk.testapp.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Test activity showcasing using the LatLngBounds camera API.
|
||||
* <p>
|
||||
@@ -31,6 +27,9 @@ public class LatLngBoundsActivity extends AppCompatActivity implements OnMapRead
|
||||
private static final LatLng LOS_ANGELES = new LatLng(34.053940, -118.242622);
|
||||
private static final LatLng NEW_YORK = new LatLng(40.712730, -74.005953);
|
||||
|
||||
private final LatLng CHINA_BOTTOM_LEFT = new LatLng(15.68169, 73.499857);
|
||||
private final LatLng CHINA_TOP_RIGHT = new LatLng(53.560711, 134.77281);
|
||||
|
||||
private MapView mapView;
|
||||
private MapboxMap mapboxMap;
|
||||
|
||||
@@ -46,41 +45,31 @@ public class LatLngBoundsActivity extends AppCompatActivity implements OnMapRead
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapReady(MapboxMap map) {
|
||||
public void onMapReady(final MapboxMap map) {
|
||||
mapboxMap = map;
|
||||
UiSettings uiSettings = mapboxMap.getUiSettings();
|
||||
uiSettings.setAllGesturesEnabled(false);
|
||||
moveToBounds(new LatLngBounds.Builder().include(NEW_YORK).include(LOS_ANGELES).build(), new int[] {0, 0, 0, 0});
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
moveToBounds(new LatLngBounds.Builder().include(CHINA_BOTTOM_LEFT).include(CHINA_TOP_RIGHT).build(),
|
||||
new int[] {100, 100, 100, 100 });
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
mapboxMap.addMarker(new MarkerOptions()
|
||||
.title("Los Angeles")
|
||||
.snippet("City Hall")
|
||||
.position(LOS_ANGELES));
|
||||
|
||||
mapboxMap.addMarker(new MarkerOptions()
|
||||
.title("New York")
|
||||
.snippet("City Hall")
|
||||
.position(NEW_YORK));
|
||||
|
||||
List<LatLng> points = new ArrayList<>();
|
||||
points.add(NEW_YORK);
|
||||
points.add(LOS_ANGELES);
|
||||
|
||||
// Create Bounds
|
||||
final LatLngBounds bounds = new LatLngBounds.Builder()
|
||||
.includes(points)
|
||||
.build();
|
||||
|
||||
// Add map padding
|
||||
int mapPadding = (int) getResources().getDimension(R.dimen.fab_margin);
|
||||
mapboxMap.setPadding(mapPadding, mapPadding, mapPadding, mapPadding);
|
||||
|
||||
// Move camera to the bounds with added padding
|
||||
int padding = (int) getResources().getDimension(R.dimen.coordinatebounds_margin);
|
||||
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding), 1500);
|
||||
|
||||
// Log data
|
||||
Timber.e("Move to bounds: " + bounds.toString());
|
||||
Timber.e("Resulting bounds:" + mapboxMap.getProjection().getVisibleRegion().latLngBounds.toString());
|
||||
private void moveToBounds(LatLngBounds latLngBounds, int[] padding) {
|
||||
mapboxMap.clear();
|
||||
mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatNorth(),latLngBounds.getLonEast())));
|
||||
mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatSouth(), latLngBounds.getLonEast())));
|
||||
mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatSouth(), latLngBounds.getLonWest())));
|
||||
mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatNorth(), latLngBounds.getLonWest())));
|
||||
CameraUpdate update =
|
||||
CameraUpdateFactory.newLatLngBounds(latLngBounds,
|
||||
padding[0],
|
||||
padding[1],
|
||||
padding[2],
|
||||
padding[3]);
|
||||
mapboxMap.moveCamera(update);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -60,22 +60,6 @@ public class CameraPositionTest {
|
||||
assertEquals("zoom should match", zoom, cameraPosition.zoom, DELTA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJniBuilder() {
|
||||
double bearing = 180;
|
||||
double zoom = 12;
|
||||
double latitude = 10;
|
||||
double longitude = 11;
|
||||
double tilt = 44;
|
||||
|
||||
double[] cameraVars = new double[]{latitude, longitude, bearing, tilt, zoom};
|
||||
CameraPosition cameraPosition = new CameraPosition.Builder(cameraVars).build();
|
||||
assertEquals("bearing should match", bearing, cameraPosition.bearing, DELTA);
|
||||
assertEquals("latlng should match", new LatLng(latitude, longitude), cameraPosition.target);
|
||||
assertEquals("tilt should match", tilt, cameraPosition.tilt, DELTA);
|
||||
assertEquals("zoom should match", zoom, cameraPosition.zoom, DELTA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
LatLng latLng = new LatLng(1, 2);
|
||||
|
||||
@@ -3,7 +3,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
classpath 'com.android.tools.build:gradle:2.3.1'
|
||||
classpath 'com.amazonaws:aws-devicefarm-gradle-plugin:1.2'
|
||||
classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.1'
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ macro(mbgl_platform_core)
|
||||
platform/android/src/style/conversion/property_value.hpp
|
||||
platform/android/src/style/conversion/types.hpp
|
||||
platform/android/src/style/conversion/types_string_values.hpp
|
||||
platform/android/src/map/camera_position.cpp
|
||||
platform/android/src/map/camera_position.hpp
|
||||
|
||||
# Style conversion Java -> C++
|
||||
platform/android/src/style/android_conversion.hpp
|
||||
|
||||
@@ -127,6 +127,9 @@ void registerNatives(JavaVM *vm) {
|
||||
IdentityStops::registerNative(env);
|
||||
IntervalStops::registerNative(env);
|
||||
|
||||
// Map
|
||||
CameraPosition::registerNative(env);
|
||||
|
||||
// Connectivity
|
||||
ConnectivityListener::registerNative(env);
|
||||
|
||||
|
||||
38
platform/android/src/map/camera_position.cpp
Normal file
38
platform/android/src/map/camera_position.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "camera_position.hpp"
|
||||
#include "../geometry/lat_lng.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
jni::Object<CameraPosition> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options) {
|
||||
static auto constructor = CameraPosition::javaClass.GetConstructor<jni::Object<LatLng>, double, double, double>(env);
|
||||
|
||||
// wrap LatLng values coming from core
|
||||
auto center = options.center.value();
|
||||
center.wrap();
|
||||
|
||||
// convert bearing, core ranges from [−π rad, π rad], android from 0 to 360 degrees
|
||||
double bearing_degrees = options.angle.value_or(0) * 180.0 / M_PI;
|
||||
while (bearing_degrees > 360) {
|
||||
bearing_degrees -= 360;
|
||||
}
|
||||
while (bearing_degrees < 0) {
|
||||
bearing_degrees += 360;
|
||||
}
|
||||
|
||||
// convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60
|
||||
double tilt_degrees = options.pitch.value_or(0) * 180 / M_PI;
|
||||
|
||||
return CameraPosition::javaClass.New(env, constructor, LatLng::New(env, center.latitude, center.longitude), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
|
||||
}
|
||||
|
||||
void CameraPosition::registerNative(jni::JNIEnv &env) {
|
||||
// Lookup the class
|
||||
CameraPosition::javaClass = *jni::Class<CameraPosition>::Find(env).NewGlobalRef(env).release();
|
||||
}
|
||||
|
||||
jni::Class<CameraPosition> CameraPosition::javaClass;
|
||||
|
||||
|
||||
} // namespace android
|
||||
} // namespace mb
|
||||
26
platform/android/src/map/camera_position.hpp
Normal file
26
platform/android/src/map/camera_position.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/map/camera.hpp>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
class CameraPosition : private mbgl::util::noncopyable {
|
||||
public:
|
||||
|
||||
static constexpr auto Name() { return "com/mapbox/mapboxsdk/camera/CameraPosition"; };
|
||||
|
||||
static jni::Object<CameraPosition> New(jni::JNIEnv&, mbgl::CameraOptions);
|
||||
|
||||
static jni::Class<CameraPosition> javaClass;
|
||||
|
||||
static void registerNative(jni::JNIEnv&);
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
@@ -44,6 +44,8 @@
|
||||
#include "bitmap.hpp"
|
||||
#include "run_loop_impl.hpp"
|
||||
#include "java/util.hpp"
|
||||
#include "geometry/lat_lng_bounds.hpp"
|
||||
#include "map/camera_position.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
@@ -369,6 +371,10 @@ void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble
|
||||
map->setLatLng(mbgl::LatLng(latitude, longitude), insets, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
|
||||
}
|
||||
|
||||
jni::Object<CameraPosition> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> jBounds) {
|
||||
return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), insets));
|
||||
}
|
||||
|
||||
void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) {
|
||||
if (reachable) {
|
||||
mbgl::NetworkStatus::Reachable();
|
||||
@@ -494,21 +500,8 @@ void NativeMapView::enableFps(jni::JNIEnv&, jni::jboolean enable) {
|
||||
fpsEnabled = enable;
|
||||
}
|
||||
|
||||
jni::Array<jni::jdouble> NativeMapView::getCameraValues(jni::JNIEnv& env) {
|
||||
//Create buffer with values
|
||||
jdouble buf[5];
|
||||
mbgl::LatLng latLng = map->getLatLng(insets);
|
||||
buf[0] = latLng.latitude;
|
||||
buf[1] = latLng.longitude;
|
||||
buf[2] = -map->getBearing();
|
||||
buf[3] = map->getPitch();
|
||||
buf[4] = map->getZoom();
|
||||
|
||||
//Convert to Java array
|
||||
auto output = jni::Array<jni::jdouble>::New(env, 5);
|
||||
jni::SetArrayRegion(env, *output, 0, 5, buf);
|
||||
|
||||
return output;
|
||||
jni::Object<CameraPosition> NativeMapView::getCameraPosition(jni::JNIEnv& env) {
|
||||
return CameraPosition::New(env, map->getCameraOptions(insets));
|
||||
}
|
||||
|
||||
void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, jni::String jid) {
|
||||
@@ -1429,6 +1422,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::flyTo, "nativeFlyTo"),
|
||||
METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"),
|
||||
METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"),
|
||||
METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"),
|
||||
METHOD(&NativeMapView::setReachability, "nativeSetReachability"),
|
||||
METHOD(&NativeMapView::resetPosition, "nativeResetPosition"),
|
||||
METHOD(&NativeMapView::getPitch, "nativeGetPitch"),
|
||||
@@ -1452,7 +1446,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::setContentPadding, "nativeSetContentPadding"),
|
||||
METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"),
|
||||
METHOD(&NativeMapView::enableFps, "nativeSetEnableFps"),
|
||||
METHOD(&NativeMapView::getCameraValues, "nativeGetCameraValues"),
|
||||
METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"),
|
||||
METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"),
|
||||
METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"),
|
||||
METHOD(&NativeMapView::setDebug, "nativeSetDebug"),
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "geometry/projected_meters.hpp"
|
||||
#include "style/layers/layers.hpp"
|
||||
#include "style/sources/sources.hpp"
|
||||
#include "geometry/lat_lng_bounds.hpp"
|
||||
#include "map/camera_position.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <jni.h>
|
||||
@@ -107,6 +109,8 @@ public:
|
||||
|
||||
void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
|
||||
|
||||
jni::Object<CameraPosition> getCameraForLatLngBounds(jni::JNIEnv&, jni::Object<mbgl::android::LatLngBounds>);
|
||||
|
||||
void setReachability(jni::JNIEnv&, jni::jboolean);
|
||||
|
||||
void resetPosition(jni::JNIEnv&);
|
||||
@@ -153,7 +157,7 @@ public:
|
||||
|
||||
void enableFps(jni::JNIEnv&, jni::jboolean enable);
|
||||
|
||||
jni::Array<jni::jdouble> getCameraValues(jni::JNIEnv&);
|
||||
jni::Object<CameraPosition> getCameraPosition(jni::JNIEnv&);
|
||||
|
||||
void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, jni::String);
|
||||
|
||||
|
||||
@@ -593,7 +593,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional
|
||||
ScreenCoordinate swPixel = {INFINITY, INFINITY};
|
||||
double viewportHeight = getSize().height;
|
||||
for (LatLng latLng : latLngs) {
|
||||
ScreenCoordinate pixel = pixelForLatLng(latLng);
|
||||
ScreenCoordinate pixel = impl->transform.latLngToScreenCoordinate(latLng);
|
||||
swPixel.x = std::min(swPixel.x, pixel.x);
|
||||
nePixel.x = std::max(nePixel.x, pixel.x);
|
||||
swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y);
|
||||
@@ -777,7 +777,12 @@ LatLng Map::latLngForProjectedMeters(const ProjectedMeters& projectedMeters) con
|
||||
}
|
||||
|
||||
ScreenCoordinate Map::pixelForLatLng(const LatLng& latLng) const {
|
||||
return impl->transform.latLngToScreenCoordinate(latLng);
|
||||
// If the center and point longitudes are not in the same side of the
|
||||
// antimeridian, we unwrap the point longitude so it would be seen if
|
||||
// e.g. the next antimeridian side is visible.
|
||||
LatLng unwrappedLatLng = latLng.wrapped();
|
||||
unwrappedLatLng.unwrapForShortestPath(getLatLng());
|
||||
return impl->transform.latLngToScreenCoordinate(unwrappedLatLng);
|
||||
}
|
||||
|
||||
LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const {
|
||||
|
||||
@@ -643,12 +643,7 @@ void Transform::setGestureInProgress(bool inProgress) {
|
||||
#pragma mark Conversion and projection
|
||||
|
||||
ScreenCoordinate Transform::latLngToScreenCoordinate(const LatLng& latLng) const {
|
||||
// If the center and point longitudes are not in the same side of the
|
||||
// antimeridian, we unwrap the point longitude so it would be seen if
|
||||
// e.g. the next antimeridian side is visible.
|
||||
LatLng unwrappedLatLng = latLng.wrapped();
|
||||
unwrappedLatLng.unwrapForShortestPath(getLatLng());
|
||||
ScreenCoordinate point = state.latLngToScreenCoordinate(unwrappedLatLng);
|
||||
ScreenCoordinate point = state.latLngToScreenCoordinate(latLng);
|
||||
point.y = state.size.height - point.y;
|
||||
return point;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,18 @@ TEST(Map, LatLngBehavior) {
|
||||
ASSERT_DOUBLE_EQ(latLng1.longitude, latLng2.longitude);
|
||||
}
|
||||
|
||||
TEST(Map, LatLngBoundsToCamera) {
|
||||
MapTest test;
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
|
||||
map.setLatLngZoom({ 40.712730, -74.005953 }, 16.0);
|
||||
|
||||
LatLngBounds bounds = LatLngBounds::hull({15.68169,73.499857}, {53.560711, 134.77281});
|
||||
|
||||
CameraOptions virtualCamera = map.cameraForLatLngBounds(bounds, {});
|
||||
ASSERT_TRUE(bounds.contains(*virtualCamera.center));
|
||||
}
|
||||
|
||||
TEST(Map, Offline) {
|
||||
MapTest test;
|
||||
DefaultFileSource fileSource(":memory:", ".");
|
||||
|
||||
@@ -181,17 +181,17 @@ TEST(Transform, UnwrappedLatLng) {
|
||||
ASSERT_NEAR(fromScreenCoordinate.latitude, 37.999999999999829, 0.0001); // 1.71E-13
|
||||
ASSERT_NEAR(fromScreenCoordinate.longitude, -76.999999999999773, 0.0001); // 2.27E-13
|
||||
|
||||
LatLng wrappedForwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, 283 }));
|
||||
ASSERT_NEAR(wrappedForwards.latitude, 37.999999999999716, 0.0001); // 2.84E-13
|
||||
ASSERT_NEAR(wrappedForwards.longitude, 282.99999999988751, 0.0001); // 1.1249E-11
|
||||
wrappedForwards.wrap();
|
||||
ASSERT_NEAR(wrappedForwards.longitude, -77.000000000112493, 0.001); // 1.1249E-11
|
||||
LatLng wrappedRightwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, 283 }));
|
||||
ASSERT_NEAR(wrappedRightwards.latitude, 37.999999999999716, 0.0001); // 2.84E-13
|
||||
ASSERT_NEAR(wrappedRightwards.longitude, 282.99999999988751, 0.0001); // 1.1249E-11
|
||||
wrappedRightwards.wrap();
|
||||
ASSERT_NEAR(wrappedRightwards.longitude, -77.000000000112493, 0.001); // 1.1249E-11
|
||||
|
||||
LatLng wrappedBackwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, -437 }));
|
||||
ASSERT_NEAR(wrappedBackwards.latitude, wrappedForwards.latitude, 0.001);
|
||||
ASSERT_NEAR(wrappedBackwards.longitude, -436.99999999988728, 0.001); // 1.1272E-11
|
||||
wrappedBackwards.wrap();
|
||||
ASSERT_NEAR(wrappedBackwards.longitude, -76.99999999988728, 0.001); // 1.1272E-11
|
||||
LatLng wrappedLeftwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, -437 }));
|
||||
ASSERT_NEAR(wrappedLeftwards.latitude, wrappedRightwards.latitude, 0.001);
|
||||
ASSERT_NEAR(wrappedLeftwards.longitude, -436.99999999988728, 0.001); // 1.1272E-11
|
||||
wrappedLeftwards.wrap();
|
||||
ASSERT_NEAR(wrappedLeftwards.longitude, -76.99999999988728, 0.001); // 1.1272E-11
|
||||
}
|
||||
|
||||
TEST(Transform, ConstrainHeightOnly) {
|
||||
@@ -399,21 +399,30 @@ TEST(Transform, Antimeridian) {
|
||||
transform.resize({ 1000, 1000 });
|
||||
transform.setLatLngZoom({ 0, 0 }, 1);
|
||||
|
||||
// San Francisco
|
||||
const LatLng coordinateSanFrancisco { 37.7833, -122.4167 };
|
||||
ScreenCoordinate pixelSF = transform.latLngToScreenCoordinate(coordinateSanFrancisco);
|
||||
ASSERT_NEAR(151.79409149185352, pixelSF.x, 1e-2);
|
||||
ASSERT_NEAR(383.76774094913071, pixelSF.y, 1e-2);
|
||||
|
||||
transform.setLatLng({ 0, -181 });
|
||||
ScreenCoordinate pixelSFBackwards = transform.latLngToScreenCoordinate(coordinateSanFrancisco);
|
||||
ASSERT_NEAR(666.63617954008976, pixelSFBackwards.x, 1e-2);
|
||||
ASSERT_DOUBLE_EQ(pixelSF.y, pixelSFBackwards.y);
|
||||
|
||||
ScreenCoordinate pixelSFLongest = transform.latLngToScreenCoordinate(coordinateSanFrancisco);
|
||||
ASSERT_NEAR(-357.36306616412816, pixelSFLongest.x, 1e-2);
|
||||
ASSERT_DOUBLE_EQ(pixelSF.y, pixelSFLongest.y);
|
||||
LatLng unwrappedSF = coordinateSanFrancisco.wrapped();
|
||||
unwrappedSF.unwrapForShortestPath(transform.getLatLng());
|
||||
|
||||
ScreenCoordinate pixelSFShortest = transform.latLngToScreenCoordinate(unwrappedSF);
|
||||
ASSERT_NEAR(666.63617954008976, pixelSFShortest.x, 1e-2);
|
||||
ASSERT_DOUBLE_EQ(pixelSF.y, pixelSFShortest.y);
|
||||
|
||||
transform.setLatLng({ 0, 179 });
|
||||
ScreenCoordinate pixelSFForwards = transform.latLngToScreenCoordinate(coordinateSanFrancisco);
|
||||
ASSERT_DOUBLE_EQ(pixelSFBackwards.x, pixelSFForwards.x);
|
||||
ASSERT_DOUBLE_EQ(pixelSFBackwards.y, pixelSFForwards.y);
|
||||
pixelSFShortest = transform.latLngToScreenCoordinate(coordinateSanFrancisco);
|
||||
ASSERT_DOUBLE_EQ(pixelSFLongest.x, pixelSFShortest.x);
|
||||
ASSERT_DOUBLE_EQ(pixelSFLongest.y, pixelSFShortest.y);
|
||||
|
||||
// Waikiri
|
||||
const LatLng coordinateWaikiri{ -16.9310, 179.9787 };
|
||||
transform.setLatLngZoom(coordinateWaikiri, 10);
|
||||
ScreenCoordinate pixelWaikiri = transform.latLngToScreenCoordinate(coordinateWaikiri);
|
||||
@@ -421,18 +430,26 @@ TEST(Transform, Antimeridian) {
|
||||
ASSERT_NEAR(500, pixelWaikiri.y, 1e-2);
|
||||
|
||||
transform.setLatLng({ coordinateWaikiri.latitude, 180.0213 });
|
||||
ScreenCoordinate pixelWaikiriForwards = transform.latLngToScreenCoordinate(coordinateWaikiri);
|
||||
ASSERT_NEAR(437.95953728819512, pixelWaikiriForwards.x, 1e-2);
|
||||
ASSERT_DOUBLE_EQ(pixelWaikiri.y, pixelWaikiriForwards.y);
|
||||
LatLng coordinateFromPixel = transform.screenCoordinateToLatLng(pixelWaikiriForwards);
|
||||
ScreenCoordinate pixelWaikiriLongest = transform.latLngToScreenCoordinate(coordinateWaikiri);
|
||||
ASSERT_NEAR(524725.96438108233, pixelWaikiriLongest.x, 1e-2);
|
||||
ASSERT_DOUBLE_EQ(pixelWaikiri.y, pixelWaikiriLongest.y);
|
||||
|
||||
LatLng unwrappedWaikiri = coordinateWaikiri.wrapped();
|
||||
unwrappedWaikiri.unwrapForShortestPath(transform.getLatLng());
|
||||
ScreenCoordinate pixelWaikiriShortest = transform.latLngToScreenCoordinate(unwrappedWaikiri);
|
||||
ASSERT_NEAR(437.95953728819512, pixelWaikiriShortest.x, 1e-2);
|
||||
ASSERT_DOUBLE_EQ(pixelWaikiri.y, pixelWaikiriShortest.y);
|
||||
|
||||
LatLng coordinateFromPixel = transform.screenCoordinateToLatLng(pixelWaikiriLongest);
|
||||
ASSERT_NEAR(coordinateWaikiri.latitude, coordinateFromPixel.latitude, 0.000001);
|
||||
ASSERT_NEAR(coordinateWaikiri.longitude, coordinateFromPixel.longitude, 0.000001);
|
||||
|
||||
transform.setLatLng({ coordinateWaikiri.latitude, -179.9787 });
|
||||
ScreenCoordinate pixelWaikiriBackwards = transform.latLngToScreenCoordinate(coordinateWaikiri);
|
||||
ASSERT_DOUBLE_EQ(pixelWaikiriForwards.x, pixelWaikiriBackwards.x);
|
||||
ASSERT_DOUBLE_EQ(pixelWaikiriForwards.y, pixelWaikiriBackwards.y);
|
||||
coordinateFromPixel = transform.screenCoordinateToLatLng(pixelWaikiriBackwards);
|
||||
pixelWaikiriShortest = transform.latLngToScreenCoordinate(coordinateWaikiri);
|
||||
ASSERT_DOUBLE_EQ(pixelWaikiriLongest.x, pixelWaikiriShortest.x);
|
||||
ASSERT_DOUBLE_EQ(pixelWaikiriLongest.y, pixelWaikiriShortest.y);
|
||||
|
||||
coordinateFromPixel = transform.screenCoordinateToLatLng(pixelWaikiriShortest);
|
||||
ASSERT_NEAR(coordinateWaikiri.latitude, coordinateFromPixel.latitude, 0.000001);
|
||||
ASSERT_NEAR(coordinateWaikiri.longitude, coordinateFromPixel.longitude, 0.000001);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user