From 0ccc7f51ba1d3377b93b4dddc3a4a03d0fda2260 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 18 Oct 2016 17:56:39 +0200 Subject: [PATCH 01/46] [android] - fixup MyLocationView heading (#6671) [android] - convert angles to radiants in jni, correct follow animation for MyLocationView do not sanitise input when recreating from other camera object, input is already sanitised before cleanup mylocationview, made animation bit more smooth, improved UX when switching between tracking modes cleanup CameraUpdateFactory, hide internally used api. only invalidate position if required, remove outdated comments correct camera position values made zoom activity a bit more interesting made dynamic marker activity a bit more interesting FIXUP --- .../mapboxsdk/camera/CameraPosition.java | 12 ++-- .../mapboxsdk/camera/CameraUpdateFactory.java | 22 +++--- .../com/mapbox/mapboxsdk/maps/MapView.java | 6 +- .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 25 +++---- .../maps/widgets/MyLocationView.java | 68 ++++++++----------- .../DynamicMarkerChangeActivity.java | 2 - .../res/layout/activity_dynamic_marker.xml | 7 +- .../main/res/layout/activity_manual_zoom.xml | 5 ++ platform/android/src/jni.cpp | 14 ++-- 9 files changed, 80 insertions(+), 81 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java index f65d012c4..3888abc04 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java @@ -171,10 +171,10 @@ public final class CameraPosition implements Parcelable { public Builder(CameraUpdateFactory.CameraPositionUpdate update) { super(); if (update != null) { - bearing(update.getBearing()); - target(update.getTarget()); - tilt(update.getTilt()); - zoom(update.getZoom()); + bearing = update.getBearing(); + target = update.getTarget(); + tilt = update.getTilt(); + zoom = update.getZoom(); } } @@ -202,7 +202,7 @@ public final class CameraPosition implements Parcelable { super(); if (nativeCameraValues != null && nativeCameraValues.length == 5) { target(new LatLng(nativeCameraValues[0], nativeCameraValues[1])); - bearing(-nativeCameraValues[2]); + bearing(nativeCameraValues[2]); tilt(nativeCameraValues[3]); zoom((float) nativeCameraValues[4]); } @@ -217,7 +217,7 @@ public final class CameraPosition implements Parcelable { public Builder bearing(double bearing) { double direction = bearing; - while (direction > 360) { + while (direction >= 360) { direction -= 360; } while (direction < 0) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java index b12dea643..db05486bc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java @@ -200,16 +200,16 @@ public final class CameraUpdateFactory { private LatLngBounds bounds; private RectF padding; - public CameraBoundsUpdate(LatLngBounds bounds, RectF padding) { + CameraBoundsUpdate(LatLngBounds bounds, RectF padding) { this.bounds = bounds; this.padding = padding; } - public CameraBoundsUpdate(LatLngBounds bounds, int[] padding) { + CameraBoundsUpdate(LatLngBounds bounds, int[] padding) { this(bounds, new RectF(padding[0], padding[1], padding[2], padding[3])); } - public CameraBoundsUpdate(LatLngBounds bounds, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { + CameraBoundsUpdate(LatLngBounds bounds, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { this(bounds, new int[]{paddingLeft, paddingTop, paddingRight, paddingBottom}); } @@ -283,7 +283,7 @@ public final class CameraUpdateFactory { private float x; private float y; - public CameraMoveUpdate(float x, float y) { + CameraMoveUpdate(float x, float y) { this.x = x; this.y = y; } @@ -315,14 +315,14 @@ public final class CameraUpdateFactory { @IntDef({ZOOM_IN, ZOOM_OUT, ZOOM_BY, ZOOM_TO, ZOOM_TO_POINT}) @Retention(RetentionPolicy.SOURCE) - public @interface Type { + @interface Type { } - public static final int ZOOM_IN = 0; - public static final int ZOOM_OUT = 1; - public static final int ZOOM_BY = 2; - public static final int ZOOM_TO = 3; - public static final int ZOOM_TO_POINT = 4; + static final int ZOOM_IN = 0; + static final int ZOOM_OUT = 1; + static final int ZOOM_BY = 2; + static final int ZOOM_TO = 3; + static final int ZOOM_TO_POINT = 4; @Type private final int type; @@ -364,7 +364,7 @@ public final class CameraUpdateFactory { return y; } - public double transformZoom(double currentZoom) { + double transformZoom(double currentZoom) { switch (getType()) { case CameraUpdateFactory.ZoomUpdate.ZOOM_IN: currentZoom++; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 0735c4c19..3d0e1e763 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -1323,7 +1323,7 @@ public class MapView extends FrameLayout { return; } nativeMapView.cancelTransitions(); - nativeMapView.jumpTo(Math.toRadians(-bearing), center, Math.toRadians(pitch), zoom); + nativeMapView.jumpTo(bearing, center, pitch, zoom); } void easeTo(double bearing, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator, @Nullable final MapboxMap.CancelableCallback cancelableCallback) { @@ -1347,7 +1347,7 @@ public class MapView extends FrameLayout { }); } - nativeMapView.easeTo(Math.toRadians(-bearing), center, duration, Math.toRadians(pitch), zoom, easingInterpolator); + nativeMapView.easeTo(bearing, center, duration, pitch, zoom, easingInterpolator); } void flyTo(double bearing, LatLng center, long duration, double pitch, double zoom, @Nullable final MapboxMap.CancelableCallback cancelableCallback) { @@ -1371,7 +1371,7 @@ public class MapView extends FrameLayout { }); } - nativeMapView.flyTo(Math.toRadians(-bearing), center, duration, Math.toRadians(pitch), zoom); + nativeMapView.flyTo(bearing, center, duration, pitch, zoom); } private void adjustTopOffsetPixels() { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index ea4bb4eaf..3ab9900a1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -389,15 +389,16 @@ public class MapboxMap { */ @UiThread public final void moveCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) { - // dismiss tracking, moving camera is equal to a gesture - cameraPosition = update.getCameraPosition(this); mapView.resetTrackingModesIfRequired(cameraPosition); mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); if (callback != null) { callback.onFinish(); } - invalidateCameraPosition(); + + if (onCameraChangeListener != null) { + onCameraChangeListener.onCameraChange(this.cameraPosition); + } } /** @@ -560,8 +561,6 @@ public class MapboxMap { */ @UiThread public final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { - // dismiss tracking, moving camera is equal to a gesture - cameraPosition = update.getCameraPosition(this); mapView.resetTrackingModesIfRequired(cameraPosition); mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, @@ -602,15 +601,17 @@ public class MapboxMap { * Invalidates the current camera position by reconstructing it from mbgl */ private void invalidateCameraPosition() { - invalidCameraPosition = false; + if(invalidCameraPosition) { + invalidCameraPosition = false; - CameraPosition cameraPosition = mapView.invalidateCameraPosition(); - if (cameraPosition != null) { - this.cameraPosition = cameraPosition; - } + CameraPosition cameraPosition = mapView.invalidateCameraPosition(); + if (cameraPosition != null) { + this.cameraPosition = cameraPosition; + } - if (onCameraChangeListener != null) { - onCameraChangeListener.onCameraChange(this.cameraPosition); + if (onCameraChangeListener != null) { + onCameraChangeListener.onCameraChange(this.cameraPosition); + } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index 114bf5f3c..45e0c4903 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -55,13 +55,9 @@ public class MyLocationView extends View { private float contentPaddingX; private float contentPaddingY; - private Location location; private LatLng latLng; - private LatLng interpolatedLocation; - private LatLng previousLocation; + private Location location; private long locationUpdateTimestamp; - - private float gpsDirection; private float previousDirection; private float accuracy; @@ -454,27 +450,29 @@ public class MyLocationView extends View { compassListener.onPause(); if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { // always face north - gpsDirection = bearing; - setCompass(gpsDirection); + setCompass(0); } } invalidate(); - update(); } public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) { - MyLocationBehaviorFactory factory = new MyLocationBehaviorFactory(); myLocationBehavior = factory.getBehavioralModel(myLocationTrackingMode); - if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW && location != null) { - // center map directly if we have a location fix + if (location != null) { + if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { + // center map directly + mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/, false /*do not disable tracking*/, null); + } else { + // do not use interpolated location from tracking mode + latLng = null; + } myLocationBehavior.updateLatLng(location); - mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/, false /*do not disable tracking*/, null); } + this.myLocationTrackingMode = myLocationTrackingMode; invalidate(); - update(); } private void setCompass(float bearing) { @@ -641,7 +639,9 @@ public class MyLocationView extends View { private abstract class MyLocationBehavior { - abstract void updateLatLng(@NonNull Location location); + void updateLatLng(@NonNull Location newLocation) { + location = newLocation; + } void updateLatLng(double lat, double lon) { if (latLng != null) { @@ -670,6 +670,7 @@ public class MyLocationView extends View { @Override void updateLatLng(@NonNull Location location) { + super.updateLatLng(location); if (latLng == null) { // first location fix latLng = new LatLng(location); @@ -677,39 +678,34 @@ public class MyLocationView extends View { } // updateLatLng timestamp - long previousUpdateTimeStamp = locationUpdateTimestamp; + float previousUpdateTimeStamp = locationUpdateTimestamp; locationUpdateTimestamp = SystemClock.elapsedRealtime(); // calculate animation duration - long locationUpdateDuration; + float animationDuration; if (previousUpdateTimeStamp == 0) { - locationUpdateDuration = 0; + animationDuration = 0; } else { - locationUpdateDuration = locationUpdateTimestamp - previousUpdateTimeStamp; + animationDuration = (locationUpdateTimestamp - previousUpdateTimeStamp) * 1.1f /*make animation slightly longer*/; } // calculate interpolated location - previousLocation = latLng; latLng = new LatLng(location); - interpolatedLocation = new LatLng(latLng.getLatitude() , latLng.getLongitude()); - - // build new camera - CameraPosition.Builder builder = new CameraPosition.Builder().target(interpolatedLocation); + CameraPosition.Builder builder = new CameraPosition.Builder().target(latLng); // add direction if (myBearingTrackingMode == MyBearingTracking.GPS) { if (location.hasBearing()) { builder.bearing(location.getBearing()); } - gpsDirection = location.getBearing(); - setCompass(gpsDirection); + setCompass(0); } // accuracy updateAccuracy(location); // ease to new camera position with a linear interpolator - mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), (int) locationUpdateDuration, false /*linear interpolator*/, false /*do not disable tracking*/, null); + mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), (int) animationDuration, false /*linear interpolator*/, false /*do not disable tracking*/, null); } @Override @@ -726,6 +722,7 @@ public class MyLocationView extends View { @Override void updateLatLng(@NonNull final Location location) { + super.updateLatLng(location); if (latLng == null) { // first location update latLng = new LatLng(location); @@ -733,13 +730,11 @@ public class MyLocationView extends View { } // update LatLng location - previousLocation = latLng; - latLng = new LatLng(location); + LatLng newLocation = new LatLng(location); // update LatLng direction if (myBearingTrackingMode == MyBearingTracking.GPS && location.hasBearing()) { - gpsDirection = location.getBearing(); - setCompass(gpsDirection); + setCompass(location.getBearing() + bearing); } // update LatLng accuracy @@ -748,10 +743,7 @@ public class MyLocationView extends View { // calculate updateLatLng time + add some extra offset to improve animation long previousUpdateTimeStamp = locationUpdateTimestamp; locationUpdateTimestamp = SystemClock.elapsedRealtime(); - long locationUpdateDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.3); - - // calculate interpolated entity - interpolatedLocation = new LatLng(latLng.getLatitude() , latLng.getLongitude()); + long locationUpdateDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.2f); // animate changes if (locationChangeAnimator != null) { @@ -760,14 +752,12 @@ public class MyLocationView extends View { } locationChangeAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); - locationChangeAnimator.setDuration((long) (locationUpdateDuration * 1.2)); + locationChangeAnimator.setDuration(locationUpdateDuration); locationChangeAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener(this, - previousLocation, interpolatedLocation + latLng, newLocation )); locationChangeAnimator.start(); - - // use interpolated location as current location - latLng = interpolatedLocation; + latLng = newLocation; } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java index 7842542ef..3c3399168 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java @@ -54,8 +54,6 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity { @Override public void onMapReady(@NonNull MapboxMap mapboxMap) { DynamicMarkerChangeActivity.this.mapboxMap = mapboxMap; - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.506675, -0.128699), 10)); - // Create marker MarkerOptions markerOptions = new MarkerOptions() .position(LAT_LNG_CHELSEA) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml index 6d9a15af8..1b1dca532 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml @@ -25,7 +25,12 @@ + android:layout_height="match_parent" + app:center_latitude="51.506675" + app:center_longitude="-0.128699" + app:direction="90" + app:tilt="40" + app:zoom="10" /> diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 4313b1932..19981c0ea 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -512,7 +512,7 @@ jdoubleArray nativeGetCameraValues(JNIEnv *env, jni::jobject* obj, jlong nativeM jdouble buf[5]; buf[0] = latLng.latitude; buf[1] = latLng.longitude; - buf[2] = nativeMapView->getMap().getBearing(); + buf[2] = -(nativeMapView->getMap().getBearing()-360); buf[3] = nativeMapView->getMap().getPitch(); buf[4] = nativeMapView->getMap().getZoom(); env->SetDoubleArrayRegion(output, start, leng, buf); @@ -1057,12 +1057,12 @@ void nativeJumpTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdoubl mbgl::CameraOptions options; if (angle != -1) { - options.angle = angle; + options.angle = angle * M_PI / 180; } options.center = mbgl::LatLng(latitude, longitude); options.padding = nativeMapView->getInsets(); if (pitch != -1) { - options.pitch = pitch; + options.pitch = pitch * M_PI / 180; } if (zoom != -1) { options.zoom = zoom; @@ -1077,12 +1077,12 @@ void nativeEaseTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdoubl mbgl::CameraOptions cameraOptions; if (angle != -1) { - cameraOptions.angle = angle; + cameraOptions.angle = angle * M_PI / 180; } cameraOptions.center = mbgl::LatLng(latitude, longitude); cameraOptions.padding = nativeMapView->getInsets(); if (pitch != -1) { - cameraOptions.pitch = pitch; + cameraOptions.pitch = pitch * M_PI / 180; } if (zoom != -1) { cameraOptions.zoom = zoom; @@ -1110,12 +1110,12 @@ void nativeFlyTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble mbgl::CameraOptions cameraOptions; if (angle != -1) { - cameraOptions.angle = angle; + cameraOptions.angle = angle * M_PI / 180 ; } cameraOptions.center = mbgl::LatLng(latitude, longitude); cameraOptions.padding = nativeMapView->getInsets(); if (pitch != -1) { - cameraOptions.pitch = pitch; + cameraOptions.pitch = pitch * M_PI / 180; } if (zoom != -1) { cameraOptions.zoom = zoom; From f45712a6b306991f1c5fa73156d9618f2f038cca Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 18 Oct 2016 23:59:57 +0200 Subject: [PATCH 02/46] [android] - add package-info.java for net package (#6733) --- .../src/main/java/com/mapbox/mapboxsdk/net/package-info.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/package-info.java diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/package-info.java new file mode 100644 index 000000000..1b207820c --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Network API classes. + */ +package com.mapbox.mapboxsdk.net; From e5762ab728404bd5c67f4abd25f9ca29cb8b56b5 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 19 Oct 2016 00:00:15 +0200 Subject: [PATCH 03/46] [android] - update map change events javadoc (#6732) --- .../com/mapbox/mapboxsdk/maps/MapView.java | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 3d0e1e763..a0ff646dd 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -2977,162 +2977,180 @@ public class MapView extends FrameLayout { } /** - *

- * This {@link MapChange} is triggered whenever the currently displayed map region is about to changing + * This event is triggered whenever the currently displayed map region is about to changing * without an animation. - *

*

- * This event is followed by a series of {@link MapView#REGION_IS_CHANGING} and ends - * with {@link MapView#REGION_DID_CHANGE}. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int REGION_WILL_CHANGE = 0; /** - *

- * This {@link MapChange} is triggered whenever the currently displayed map region is about to changing + * This event is triggered whenever the currently displayed map region is about to changing * with an animation. - *

- *

- * This event is followed by a series of {@link MapView#REGION_IS_CHANGING} and ends - * with {@link MapView#REGION_DID_CHANGE_ANIMATED}. + *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int REGION_WILL_CHANGE_ANIMATED = 1; /** + * This event is triggered whenever the currently displayed map region is changing. *

- * This {@link MapChange} is triggered whenever the currently displayed map region is changing. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int REGION_IS_CHANGING = 2; /** - *

- * This {@link MapChange} is triggered whenever the currently displayed map region finished changing + * This event is triggered whenever the currently displayed map region finished changing * without an animation. + *

+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int REGION_DID_CHANGE = 3; /** - *

- * This {@link MapChange} is triggered whenever the currently displayed map region finished changing + * This event is triggered whenever the currently displayed map region finished changing * with an animation. + *

+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int REGION_DID_CHANGE_ANIMATED = 4; /** + * This event is triggered when the map is about to start loading a new map style. *

- * This {@link MapChange} is triggered when the map is about to start loading a new map style. - *

- *

- * This event is followed by {@link MapView#DID_FINISH_LOADING_MAP} or - * {@link MapView#DID_FAIL_LOADING_MAP}. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int WILL_START_LOADING_MAP = 5; /** + * This is triggered when the map has successfully loaded a new map style. *

- * This {@link MapChange} is triggered when the map has successfully loaded a new map style. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int DID_FINISH_LOADING_MAP = 6; /** - *

- * This {@link MapChange} is currently not implemented. - *

- *

* This event is triggered when the map has failed to load a new map style. + *

+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int DID_FAIL_LOADING_MAP = 7; /** + * This event is triggered when the map will start rendering a frame. *

- * This {@link MapChange} is currently not implemented. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int WILL_START_RENDERING_FRAME = 8; /** + * This event is triggered when the map finished rendering a frame. *

- * This {@link MapChange} is currently not implemented. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int DID_FINISH_RENDERING_FRAME = 9; /** + * This event is triggered when the map finished rendeirng the frame fully. *

- * This {@link MapChange} is currently not implemented. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int DID_FINISH_RENDERING_FRAME_FULLY_RENDERED = 10; /** + * This event is triggered when the map will start rendering the map. *

- * This {@link MapChange} is currently not implemented. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int WILL_START_RENDERING_MAP = 11; /** + * This event is triggered when the map finished rendering the map. *

- * This {@link MapChange} is currently not implemented. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int DID_FINISH_RENDERING_MAP = 12; /** + * This event is triggered when the map is fully rendered. *

- * This {@link MapChange} is currently not implemented. + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int DID_FINISH_RENDERING_MAP_FULLY_RENDERED = 13; /** + * This {@link MapChange} is triggered when a style has finished loading. *

- * This {@link MapChange} is triggered when a style is loaded + * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. *

* + * @see MapChange * @see MapView.OnMapChangedListener */ public static final int DID_FINISH_LOADING_STYLE = 14; /** * Interface definition for a callback to be invoked when the displayed map view changes. + *

+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}. + *

* * @see MapView#addOnMapChangedListener(OnMapChangedListener) * @see MapView.MapChange From ce243043f5251bb6a7fabc90d8ca3162ade8a44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Tue, 18 Oct 2016 15:03:10 -0700 Subject: [PATCH 04/46] [ios, macos] Raise correct style layer misuse exception (#6738) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the layer property on MGLStyleLayer itself, where it’s declared, so that the check for an abstract style layer doesn’t itself raise an exception. The concrete style layer classes still declare their own layers as covariant properties, although those properties aren’t actually used anywhere. --- platform/darwin/src/MGLStyle.mm | 8 ++++---- platform/darwin/src/MGLStyleLayer.mm | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index f9f2e03d4..3964b47ad 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -176,7 +176,7 @@ static NSURL *MGLStyleURL_emerald; [NSException raise:NSInvalidArgumentException format: @"The style layer %@ cannot be added to the style. " @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", - NSStringFromClass(self)]; + layer]; } self.mapView.mbglMap->addLayer(std::unique_ptr(layer.layer)); @@ -189,14 +189,14 @@ static NSURL *MGLStyleURL_emerald; format: @"The style layer %@ cannot be added to the style. " @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", - NSStringFromClass(layer)]; + layer]; } if (!otherLayer.layer) { [NSException raise:NSInvalidArgumentException format: @"A style layer cannot be placed before %@ in the style. " - @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", - NSStringFromClass(otherLayer)]; + @"Make sure otherLayer was obtained using -[MGLStyle layerWithIdentifier:].", + otherLayer]; } const mbgl::optional belowLayerId{otherLayer.identifier.UTF8String}; diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm index a2bb1fc2c..293aa54f3 100644 --- a/platform/darwin/src/MGLStyleLayer.mm +++ b/platform/darwin/src/MGLStyleLayer.mm @@ -3,6 +3,12 @@ #include +@interface MGLStyleLayer () + +@property (nonatomic) mbgl::style::Layer *layer; + +@end + @implementation MGLStyleLayer - (instancetype)initWithIdentifier:(NSString *)identifier From 3a12dd2d4fec398bc84f88cfddc2ac4a37c3a7f1 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 18 Oct 2016 11:55:57 +0300 Subject: [PATCH 05/46] [core] Skip redundant spherical mercator variable updates in {ease,fly}To --- src/mbgl/map/transform.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 41fc36ce2..bf511ed67 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -132,9 +132,6 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim Duration duration = animation.duration ? *animation.duration : Duration::zero(); const double startWorldSize = state.worldSize(); - state.Bc = startWorldSize / util::DEGREES_MAX; - state.Cc = startWorldSize / util::M2PI; - const double startScale = state.scale; const double startAngle = state.angle; const double startPitch = state.pitch; @@ -292,8 +289,6 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima } const double startWorldSize = state.worldSize(); - state.Bc = startWorldSize / util::DEGREES_MAX; - state.Cc = startWorldSize / util::M2PI; state.panning = true; state.scaling = true; From f01a829dc9e076abeb7df90259e8e5c7d9cfbad6 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 18 Oct 2016 11:29:58 +0300 Subject: [PATCH 06/46] [core] Move TransformState::worldSize() to Projection --- include/mbgl/util/projection.hpp | 14 ++++++++++---- src/mbgl/map/transform.cpp | 6 +++--- src/mbgl/map/transform_state.cpp | 20 ++++++++------------ src/mbgl/map/transform_state.hpp | 7 +++---- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp index eb4508858..0b6e9f6bf 100644 --- a/include/mbgl/util/projection.hpp +++ b/include/mbgl/util/projection.hpp @@ -8,14 +8,20 @@ namespace mbgl { +// Spherical Mercator projection +// http://docs.openlayers.org/library/spherical_mercator.html class Projection { - public: + // Map pixel width at given scale. + static double worldSize(double scale) { + return scale * util::tileSize; + } + static double getMetersPerPixelAtLatitude(double lat, double zoom) { const double constrainedZoom = util::clamp(zoom, util::MIN_ZOOM, util::MAX_ZOOM); - const double mapPixelWidthAtZoom = std::pow(2.0, constrainedZoom) * util::tileSize; + const double constrainedScale = std::pow(2.0, constrainedZoom); const double constrainedLatitude = util::clamp(lat, -util::LATITUDE_MAX, util::LATITUDE_MAX); - return std::cos(constrainedLatitude * util::DEG2RAD) * util::M2PI * util::EARTH_RADIUS_M / mapPixelWidthAtZoom; + return std::cos(constrainedLatitude * util::DEG2RAD) * util::M2PI * util::EARTH_RADIUS_M / worldSize(constrainedScale); } static ProjectedMeters projectedMetersForLatLng(const LatLng& latLng) { @@ -32,7 +38,7 @@ public: } static LatLng latLngForProjectedMeters(const ProjectedMeters& projectedMeters) { - double latitude = (2 * std::atan(std::exp(projectedMeters.northing / util::EARTH_RADIUS_M)) - (M_PI / 2)) * util::RAD2DEG; + double latitude = (2 * std::atan(std::exp(projectedMeters.northing / util::EARTH_RADIUS_M)) - (M_PI / 2.0)) * util::RAD2DEG; double longitude = projectedMeters.easting * util::RAD2DEG / util::EARTH_RADIUS_M; latitude = util::clamp(latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX); diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index bf511ed67..71e7739b5 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -131,8 +132,8 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim Duration duration = animation.duration ? *animation.duration : Duration::zero(); - const double startWorldSize = state.worldSize(); const double startScale = state.scale; + const double startWorldSize = Projection::worldSize(startScale); const double startAngle = state.angle; const double startPitch = state.pitch; state.panning = latLng != startLatLng; @@ -288,8 +289,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima return; } - const double startWorldSize = state.worldSize(); - + const double startWorldSize = Projection::worldSize(state.scale); state.panning = true; state.scaling = true; state.rotating = angle != startAngle; diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index eb6651362..6256c7d0f 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -17,7 +17,7 @@ TransformState::TransformState(ConstrainMode constrainMode_, ViewportMode viewpo void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) const { const uint64_t tileScale = 1ull << tileID.canonical.z; - const double s = worldSize() / tileScale; + const double s = Projection::worldSize(scale) / tileScale; matrix::identity(matrix); matrix::translate(matrix, matrix, @@ -108,12 +108,12 @@ LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const { } double TransformState::pixel_x() const { - const double center = (width - worldSize()) / 2; + const double center = (width - Projection::worldSize(scale)) / 2; return center + x; } double TransformState::pixel_y() const { - const double center = (height - worldSize()) / 2; + const double center = (height - Projection::worldSize(scale)) / 2; return center + y; } @@ -205,7 +205,7 @@ Point TransformState::project(const LatLng& ll) const { return Point( (util::LONGITUDE_MAX + ll.longitude), (util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + ll.latitude * M_PI / util::DEGREES_MAX))) - ) * worldSize() / util::DEGREES_MAX; + ) * Projection::worldSize(scale) / util::DEGREES_MAX; } LatLng TransformState::unproject(const Point& p, double worldSize, LatLng::WrapMode wrapMode) const { @@ -225,10 +225,6 @@ double TransformState::scaleZoom(double s) const { return util::log2(s); } -double TransformState::worldSize() const { - return scale * util::tileSize; -} - ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) const { if (width == 0 || height == 0) { return {}; @@ -284,7 +280,7 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L mat4 TransformState::coordinatePointMatrix(double z) const { mat4 proj; getProjMatrix(proj); - float s = worldSize() / std::pow(2, z); + float s = Projection::worldSize(scale) / std::pow(2, z); matrix::scale(proj, proj, s, s, 1); matrix::multiply(proj, getPixelMatrix(), proj); return proj; @@ -328,7 +324,7 @@ void TransformState::moveLatLng(const LatLng& latLng, const ScreenCoordinate& an auto centerCoord = project(getLatLng(LatLng::Unwrapped)); auto latLngCoord = project(latLng); auto anchorCoord = project(screenCoordinateToLatLng(anchor)); - setLatLngZoom(unproject(centerCoord + latLngCoord - anchorCoord, worldSize()), getZoom()); + setLatLngZoom(unproject(centerCoord + latLngCoord - anchorCoord, Projection::worldSize(scale)), getZoom()); } void TransformState::setLatLngZoom(const LatLng &latLng, double zoom) { @@ -355,8 +351,8 @@ void TransformState::setScalePoint(const double newScale, const ScreenCoordinate scale = constrainedScale; x = constrainedPoint.x; y = constrainedPoint.y; - Bc = worldSize() / util::DEGREES_MAX; - Cc = worldSize() / util::M2PI; + Bc = Projection::worldSize(scale) / util::DEGREES_MAX; + Cc = Projection::worldSize(scale) / util::M2PI; } } // namespace mbgl diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 1e4b2054f..10d2301ea 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -88,8 +89,6 @@ private: // logical dimensions uint16_t width = 0, height = 0; - double worldSize() const; - mat4 coordinatePointMatrix(double z) const; mat4 getPixelMatrix() const; @@ -117,8 +116,8 @@ private: double pitch = 0.0; // cache values for spherical mercator math - double Bc = worldSize() / util::DEGREES_MAX; - double Cc = worldSize() / util::M2PI; + double Bc = Projection::worldSize(scale) / util::DEGREES_MAX; + double Cc = Projection::worldSize(scale) / util::M2PI; }; } // namespace mbgl From 2188d68b6c09dec676c294223aa7d1a4c24c85f0 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 18 Oct 2016 12:12:57 +0300 Subject: [PATCH 07/46] [core] Move TransformState::{un,}project() to Projection --- include/mbgl/util/projection.hpp | 16 ++++++++++++++++ src/mbgl/map/transform.cpp | 15 +++++++-------- src/mbgl/map/transform_state.cpp | 28 ++++++---------------------- src/mbgl/map/transform_state.hpp | 5 +---- src/mbgl/util/tile_coordinate.hpp | 3 ++- 5 files changed, 32 insertions(+), 35 deletions(-) diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp index 0b6e9f6bf..4212e5da7 100644 --- a/include/mbgl/util/projection.hpp +++ b/include/mbgl/util/projection.hpp @@ -46,6 +46,22 @@ public: return LatLng(latitude, longitude); } + + static Point project(const LatLng& latLng, double scale) { + return Point { + util::LONGITUDE_MAX + latLng.longitude, + util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + latLng.latitude * M_PI / util::DEGREES_MAX)) + } * worldSize(scale) / util::DEGREES_MAX; + } + + static LatLng unproject(const Point& p, double scale, LatLng::WrapMode wrapMode = LatLng::Unwrapped) { + auto p2 = p * util::DEGREES_MAX / worldSize(scale); + return LatLng { + util::DEGREES_MAX / M_PI * std::atan(std::exp((util::LONGITUDE_MAX - p2.y) * util::DEG2RAD)) - 90.0, + p2.x - util::LONGITUDE_MAX, + wrapMode + }; + } }; } // namespace mbgl diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 71e7739b5..85805a109 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -113,8 +113,8 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim // Find the shortest path otherwise. else startLatLng.unwrapForShortestPath(latLng); - const Point startPoint = state.project(startLatLng); - const Point endPoint = state.project(latLng); + const Point startPoint = Projection::project(startLatLng, state.scale); + const Point endPoint = Projection::project(latLng, state.scale); ScreenCoordinate center = getScreenCoordinate(padding); center.y = state.height - center.y; @@ -133,7 +133,6 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim Duration duration = animation.duration ? *animation.duration : Duration::zero(); const double startScale = state.scale; - const double startWorldSize = Projection::worldSize(startScale); const double startAngle = state.angle; const double startPitch = state.pitch; state.panning = latLng != startLatLng; @@ -142,7 +141,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim startTransition(camera, animation, [=](double t) { Point framePoint = util::interpolate(startPoint, endPoint, t); - LatLng frameLatLng = state.unproject(framePoint, startWorldSize); + LatLng frameLatLng = Projection::unproject(framePoint, startScale); double frameScale = util::interpolate(startScale, scale, t); state.setLatLngZoom(frameLatLng, state.scaleZoom(frameScale)); @@ -184,8 +183,8 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima LatLng startLatLng = getLatLng(padding).wrapped(); startLatLng.unwrapForShortestPath(latLng); - const Point startPoint = state.project(startLatLng); - const Point endPoint = state.project(latLng); + const Point startPoint = Projection::project(startLatLng, state.scale); + const Point endPoint = Projection::project(latLng, state.scale); ScreenCoordinate center = getScreenCoordinate(padding); center.y = state.height - center.y; @@ -289,7 +288,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima return; } - const double startWorldSize = Projection::worldSize(state.scale); + const double startScale = state.scale; state.panning = true; state.scaling = true; state.rotating = angle != startAngle; @@ -305,7 +304,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima double frameZoom = startZoom + state.scaleZoom(1 / w(s)); // Convert to geographic coordinates and set the new viewpoint. - LatLng frameLatLng = state.unproject(framePoint, startWorldSize); + LatLng frameLatLng = Projection::unproject(framePoint, startScale); state.setLatLngZoom(frameLatLng, frameZoom); if (angle != startAngle) { diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 6256c7d0f..4f6bcecdb 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -201,22 +201,6 @@ bool TransformState::isGestureInProgress() const { #pragma mark - Projection -Point TransformState::project(const LatLng& ll) const { - return Point( - (util::LONGITUDE_MAX + ll.longitude), - (util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + ll.latitude * M_PI / util::DEGREES_MAX))) - ) * Projection::worldSize(scale) / util::DEGREES_MAX; -} - -LatLng TransformState::unproject(const Point& p, double worldSize, LatLng::WrapMode wrapMode) const { - Point p2 = p * util::DEGREES_MAX / worldSize; - return LatLng( - util::DEGREES_MAX / M_PI * std::atan(std::exp((util::LONGITUDE_MAX - p2.y) * util::DEG2RAD)) - 90.0f, - p2.x - util::LONGITUDE_MAX, - wrapMode - ); -} - double TransformState::zoomScale(double zoom) const { return std::pow(2.0f, zoom); } @@ -232,7 +216,7 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) mat4 mat = coordinatePointMatrix(getZoom()); vec4 p; - Point pt = project(latLng) / double(util::tileSize); + Point pt = Projection::project(latLng, scale) / double(util::tileSize); vec4 c = {{ pt.x, pt.y, 0, 1 }}; matrix::transformMat4(p, c, mat); return { p[0] / p[3], height - p[1] / p[3] }; @@ -274,7 +258,7 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L double z1 = coord1[2] / w1; double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0); - return unproject(util::interpolate(p0, p1, t), scale, wrapMode); + return Projection::unproject(util::interpolate(p0, p1, t), scale / util::tileSize, wrapMode); } mat4 TransformState::coordinatePointMatrix(double z) const { @@ -321,10 +305,10 @@ void TransformState::constrain(double& scale_, double& x_, double& y_) const { } void TransformState::moveLatLng(const LatLng& latLng, const ScreenCoordinate& anchor) { - auto centerCoord = project(getLatLng(LatLng::Unwrapped)); - auto latLngCoord = project(latLng); - auto anchorCoord = project(screenCoordinateToLatLng(anchor)); - setLatLngZoom(unproject(centerCoord + latLngCoord - anchorCoord, Projection::worldSize(scale)), getZoom()); + auto centerCoord = Projection::project(getLatLng(LatLng::Unwrapped), scale); + auto latLngCoord = Projection::project(latLng, scale); + auto anchorCoord = Projection::project(screenCoordinateToLatLng(anchor), scale); + setLatLngZoom(Projection::unproject(centerCoord + latLngCoord - anchorCoord, scale), getZoom()); } void TransformState::setLatLngZoom(const LatLng &latLng, double zoom) { diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 10d2301ea..8a12b62a9 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -66,13 +66,10 @@ public: bool isPanning() const; bool isGestureInProgress() const; - // Conversion and projection + // Conversion ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const; LatLng screenCoordinateToLatLng(const ScreenCoordinate&, LatLng::WrapMode = LatLng::Unwrapped) const; - Point project(const LatLng&) const; - LatLng unproject(const Point&, double worldSize, LatLng::WrapMode = LatLng::Unwrapped) const; - double zoomScale(double zoom) const; double scaleZoom(double scale) const; diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp index 194a62ece..46073c0dc 100644 --- a/src/mbgl/util/tile_coordinate.hpp +++ b/src/mbgl/util/tile_coordinate.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace mbgl { @@ -19,7 +20,7 @@ public: static TileCoordinate fromLatLng(const TransformState& state, double zoom, const LatLng& latLng) { const double scale = std::pow(2, zoom - state.getZoom()); - return { state.project(latLng) * scale / double(util::tileSize), zoom }; + return { Projection::project(latLng, state.getScale()) * scale / double(util::tileSize), zoom }; } static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& screenCoordinate) { From ef62b78fce06ad93de87e9a6a6775ae33fff214d Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 18 Oct 2016 14:21:59 +0300 Subject: [PATCH 08/46] [core] TileCoordinate::fromLatLng no longer depens on TransformState --- include/mbgl/util/projection.hpp | 2 +- src/mbgl/util/tile_coordinate.hpp | 14 ++++++++------ src/mbgl/util/tile_cover.cpp | 11 +++++------ test/tile/tile_coordinate.test.cpp | 4 ++-- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp index 4212e5da7..9ca3cd4ab 100644 --- a/include/mbgl/util/projection.hpp +++ b/include/mbgl/util/projection.hpp @@ -2,9 +2,9 @@ #include #include +#include #include -#include namespace mbgl { diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp index 46073c0dc..bcd1c8444 100644 --- a/src/mbgl/util/tile_coordinate.hpp +++ b/src/mbgl/util/tile_coordinate.hpp @@ -18,23 +18,25 @@ public: TileCoordinatePoint p; double z; - static TileCoordinate fromLatLng(const TransformState& state, double zoom, const LatLng& latLng) { - const double scale = std::pow(2, zoom - state.getZoom()); - return { Projection::project(latLng, state.getScale()) * scale / double(util::tileSize), zoom }; + static TileCoordinate fromLatLng(double zoom, const LatLng& latLng) { + const double scale = std::pow(2.0, zoom); + return { Projection::project(latLng, scale) / double(util::tileSize), zoom }; } static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& screenCoordinate) { - return fromLatLng(state, zoom, state.screenCoordinateToLatLng(screenCoordinate)); + return fromLatLng(zoom, state.screenCoordinateToLatLng(screenCoordinate)); } TileCoordinate zoomTo(double zoom) const { - return { p * std::pow(2, zoom - z), zoom }; + const double scaleDiff = std::pow(2.0, zoom - z); + return { p * scaleDiff, zoom }; } static GeometryCoordinate toGeometryCoordinate(const UnwrappedTileID& tileID, const TileCoordinatePoint& point) { + const double scale = std::pow(2.0, tileID.canonical.z); auto zoomed = TileCoordinate { point, 0 }.zoomTo(tileID.canonical.z); return { - int16_t(util::clamp((zoomed.p.x - tileID.canonical.x - tileID.wrap * std::pow(2.0, tileID.canonical.z)) * util::EXTENT, + int16_t(util::clamp((zoomed.p.x - tileID.canonical.x - tileID.wrap * scale) * util::EXTENT, std::numeric_limits::min(), std::numeric_limits::max())), int16_t(util::clamp((zoomed.p.y - tileID.canonical.y) * util::EXTENT, diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp index 5487fb269..c6bf7d362 100644 --- a/src/mbgl/util/tile_cover.cpp +++ b/src/mbgl/util/tile_cover.cpp @@ -147,13 +147,12 @@ std::vector tileCover(const LatLngBounds& bounds_, int32_t z) { { std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() }, { std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() }); - const TransformState state; return tileCover( - TileCoordinate::fromLatLng(state, z, bounds.northwest()).p, - TileCoordinate::fromLatLng(state, z, bounds.northeast()).p, - TileCoordinate::fromLatLng(state, z, bounds.southeast()).p, - TileCoordinate::fromLatLng(state, z, bounds.southwest()).p, - TileCoordinate::fromLatLng(state, z, bounds.center()).p, + TileCoordinate::fromLatLng(z, bounds.northwest()).p, + TileCoordinate::fromLatLng(z, bounds.northeast()).p, + TileCoordinate::fromLatLng(z, bounds.southeast()).p, + TileCoordinate::fromLatLng(z, bounds.southwest()).p, + TileCoordinate::fromLatLng(z, bounds.center()).p, z); } diff --git a/test/tile/tile_coordinate.test.cpp b/test/tile/tile_coordinate.test.cpp index f2337c1e7..740a03894 100644 --- a/test/tile/tile_coordinate.test.cpp +++ b/test/tile/tile_coordinate.test.cpp @@ -41,7 +41,7 @@ TEST(TileCoordinate, FromLatLng) { for (const auto& pair : edges) { const auto& latLng = pair.first; const auto& screenCoordinate = pair.second; - const auto base = TileCoordinate::fromLatLng(transform.getState(), 0, latLng); + const auto base = TileCoordinate::fromLatLng(0, latLng); // 16 is the maximum zoom level where we actually compute placements. for (uint8_t integerZoom = 0; integerZoom <= 16; ++integerZoom) { @@ -52,7 +52,7 @@ TEST(TileCoordinate, FromLatLng) { latLng.latitude == 0 ? 0.5 : latLng.latitude == -util::LATITUDE_MAX ? 1.0 : 0, }; - const auto fromLatLng = TileCoordinate::fromLatLng(transform.getState(), zoom, latLng); + const auto fromLatLng = TileCoordinate::fromLatLng(zoom, latLng); ASSERT_DOUBLE_EQ(fromLatLng.z, zoom); ASSERT_DOUBLE_EQ(fromLatLng.p.x, tilePoint.x * maxTilesPerAxis); ASSERT_NEAR(fromLatLng.p.y, tilePoint.y * maxTilesPerAxis, 1.0e-7); From c50577d039c67b04a60155f7f7b7c6dc9d2c0d30 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 18 Oct 2016 14:22:17 +0300 Subject: [PATCH 09/46] [core] Fix SymbolAnnotation coordinate system conversions --- .../annotation/symbol_annotation_impl.cpp | 25 ++++------------ test/api/annotations.test.cpp | 29 ++++++++++++------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/mbgl/annotation/symbol_annotation_impl.cpp b/src/mbgl/annotation/symbol_annotation_impl.cpp index 040de2121..e5ae5f4b9 100644 --- a/src/mbgl/annotation/symbol_annotation_impl.cpp +++ b/src/mbgl/annotation/symbol_annotation_impl.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace mbgl { @@ -14,26 +15,10 @@ void SymbolAnnotationImpl::updateLayer(const CanonicalTileID& tileID, Annotation std::unordered_map featureProperties; featureProperties.emplace("sprite", annotation.icon.empty() ? std::string("default_marker") : annotation.icon); - const Point& p = annotation.geometry; - - // Clamp to the latitude limits of Web Mercator. - const double constrainedLatitude = util::clamp(p.y, -util::LATITUDE_MAX, util::LATITUDE_MAX); - - // Project a coordinate into unit space in a square map. - const double sine = std::sin(constrainedLatitude * util::DEG2RAD); - const double x = p.x / util::DEGREES_MAX + 0.5; - const double y = 0.5 - 0.25 * std::log((1.0 + sine) / (1.0 - sine)) / M_PI; - - Point projected(x, y); - projected *= std::pow(2, tileID.z); - projected.x = std::fmod(projected.x, 1); - projected.y = std::fmod(projected.y, 1); - projected *= double(util::EXTENT); - - layer.features.emplace_back(id, - FeatureType::Point, - GeometryCollection {{ {{ convertPoint(projected) }} }}, - featureProperties); + LatLng latLng { annotation.geometry.y, annotation.geometry.x }; + TileCoordinate coordinate = TileCoordinate::fromLatLng(0, latLng); + GeometryCoordinate tilePoint = TileCoordinate::toGeometryCoordinate(UnwrappedTileID(0, tileID), coordinate.p); + layer.features.emplace_back(id, FeatureType::Point, GeometryCollection {{ {{ tilePoint }} }}, featureProperties); } } // namespace mbgl diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp index dc4b00170..6d6734a10 100644 --- a/test/api/annotations.test.cpp +++ b/test/api/annotations.test.cpp @@ -49,10 +49,7 @@ TEST(Annotations, SymbolAnnotation) { EXPECT_EQ(features.size(), 1u); test.map.setZoom(test.map.getMaxZoom()); - // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/5419 - //test.map.setZoom(test.map.getMaxZoom()); - //test.checkRendering("point_annotation"); - test::render(test.map); + test.checkRendering("point_annotation"); features = test.map.queryPointAnnotations(screenBox); EXPECT_EQ(features.size(), 1u); @@ -369,10 +366,17 @@ TEST(Annotations, QueryFractionalZoomLevels) { } test.map.setLatLngZoom({ 5, 5 }, 0); - for (uint16_t zoomSteps = 0; zoomSteps <= 20; ++zoomSteps) { + for (uint16_t zoomSteps = 10; zoomSteps <= 20; ++zoomSteps) { test.map.setZoom(zoomSteps / 10.0); test::render(test.map); auto features = test.map.queryRenderedFeatures(box); + + // Filter out repeated features. + // See 'edge-cases/null-island' query-test for reference. + auto sortID = [](const Feature& lhs, const Feature& rhs) { return lhs.id < rhs.id; }; + auto sameID = [](const Feature& lhs, const Feature& rhs) { return lhs.id == rhs.id; }; + std::sort(features.begin(), features.end(), sortID); + features.erase(std::unique(features.begin(), features.end(), sameID), features.end()); EXPECT_EQ(features.size(), ids.size()); } } @@ -385,26 +389,31 @@ TEST(Annotations, VisibleFeatures) { test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json")); test.map.addAnnotationIcon("default_marker", namedMarker("default_marker.png")); - test.map.setZoom(3); + test.map.setLatLngZoom({ 5, 5 }, 3); std::vector ids; - for (int longitude = -5; longitude <= 5; ++longitude) { - for (int latitude = -5; latitude <= 5; ++latitude) { + for (int longitude = 0; longitude < 10; ++longitude) { + for (int latitude = 0; latitude <= 10; ++latitude) { ids.push_back(test.map.addAnnotation(SymbolAnnotation { { double(latitude), double(longitude) }, "default_marker" })); } } - // Change bearing *after* adding annotations cause them to be reordered, - // and some annotations become occluded by others. + // Change bearing *after* adding annotations causes them to be reordered. test.map.setBearing(45); test::render(test.map); auto features = test.map.queryRenderedFeatures(box); + auto sortID = [](const Feature& lhs, const Feature& rhs) { return lhs.id < rhs.id; }; + auto sameID = [](const Feature& lhs, const Feature& rhs) { return lhs.id == rhs.id; }; + std::sort(features.begin(), features.end(), sortID); + features.erase(std::unique(features.begin(), features.end(), sameID), features.end()); EXPECT_EQ(features.size(), ids.size()); test.map.setBearing(0); test.map.setZoom(4); test::render(test.map); features = test.map.queryRenderedFeatures(box); + std::sort(features.begin(), features.end(), sortID); + features.erase(std::unique(features.begin(), features.end(), sameID), features.end()); EXPECT_EQ(features.size(), ids.size()); } From 61a534241f7b2a8e53825a5ed8474c11fea4ee04 Mon Sep 17 00:00:00 2001 From: Cameron Mace Date: Wed, 19 Oct 2016 12:06:16 -0400 Subject: [PATCH 10/46] Adds map dialog activity to testapp (#6741) * adds map dialog activity to testapp * added to genertate-test-code script --- .../src/main/AndroidManifest.xml | 8 ++ .../maplayout/MapInDialogActivity.java | 116 ++++++++++++++++++ .../res/layout/activity_map_in_dialog.xml | 21 ++++ .../main/res/layout/fragment_dialog_map.xml | 18 +++ .../src/main/res/values/strings.xml | 3 + .../android/scripts/generate-test-code.js | 3 +- 6 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 164625d3f..2fd973ee8 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -422,6 +422,14 @@ android:name="@string/category" android:value="@string/category_annotation" /> + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java new file mode 100644 index 000000000..3df236f43 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java @@ -0,0 +1,116 @@ +package com.mapbox.mapboxsdk.testapp.activity.maplayout; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentManager; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.testapp.R; + +public class MapInDialogActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_map_in_dialog); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); + } + + Button button = (Button) findViewById(R.id.button_open_dialog); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + FragmentManager fm = getSupportFragmentManager(); + MapDialogFragment editNameDialogFragment = MapDialogFragment.newInstance("Map Dialog"); + editNameDialogFragment.show(fm, "fragment_dialog_map"); + } + }); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + public static class MapDialogFragment extends DialogFragment { + + private MapView mapView; + + public MapDialogFragment() {} + + public static MapDialogFragment newInstance(String title) { + MapDialogFragment frag = new MapDialogFragment(); + Bundle args = new Bundle(); + args.putString("title", title); + frag.setArguments(args); + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_dialog_map, container); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mapView = (MapView) view.findViewById(R.id.mapView); + mapView.onCreate(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml new file mode 100644 index 000000000..1edc45625 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml @@ -0,0 +1,21 @@ + + + + + +