From acc6079b088c75d279b4e55bd8687edf8916144c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 16 Jul 2019 18:20:43 +0200 Subject: [android] improve rotation inertia, adjust velocity ratios for screen density --- .../mapboxsdk/constants/MapboxConstants.java | 20 ++++---- .../mapbox/mapboxsdk/maps/MapGestureDetector.java | 57 ++++++++++++++-------- .../src/main/res/values/dimens.xml | 8 ++- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index d5c5c4d999..015260322c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -73,11 +73,6 @@ public class MapboxConstants { */ public static final long VELOCITY_THRESHOLD_IGNORE_FLING = 1000; - /** - * Value by which the default rotation threshold will be increased when scaling - */ - public static final float ROTATION_THRESHOLD_INCREASE_WHEN_SCALING = 25f; - /** * Maximum absolute zoom change for multi-pointer scale velocity animation */ @@ -89,19 +84,24 @@ public class MapboxConstants { public static final double SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER = 150; /** - * Time within which user needs to lift fingers for velocity animation to start. + * Last scale span delta to XY velocity ratio required to execute scale velocity animation. */ - public static final long SCHEDULED_ANIMATION_TIMEOUT = 150L; + public static final double SCALE_VELOCITY_RATIO_THRESHOLD = 4 * 1e-3; /** - * Minimum angular velocity for rotation animation + * Last rotation delta to XY velocity ratio required to execute rotation velocity animation. */ - public static final float MINIMUM_ANGULAR_VELOCITY = 1.5f; + public static final double ROTATE_VELOCITY_RATIO_THRESHOLD = 2.2 * 1e-4; + + /** + * Time within which user needs to lift fingers for velocity animation to start. + */ + public static final long SCHEDULED_ANIMATION_TIMEOUT = 150L; /** * Maximum angular velocity for rotation animation */ - public static final float MAXIMUM_ANGULAR_VELOCITY = 20f; + public static final float MAXIMUM_ANGULAR_VELOCITY = 30f; /** * Factor to calculate tilt change based on pixel change during shove gesture. diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 6b61f01b8a..80b1e32413 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -29,8 +29,11 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAXIMUM_ANGULAR_VELOCITY; import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.ROTATE_VELOCITY_RATIO_THRESHOLD; import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_RATIO_THRESHOLD; import static com.mapbox.mapboxsdk.constants.MapboxConstants.ZOOM_RATE; import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE; @@ -114,11 +117,14 @@ final class MapGestureDetector { com.mapbox.android.gestures.R.dimen.mapbox_defaultScaleSpanSinceStartThreshold)); MoveGestureListener moveGestureListener = new MoveGestureListener(); ScaleGestureListener scaleGestureListener = new ScaleGestureListener( + context.getResources().getDimension(R.dimen.mapbox_density_constant), context.getResources().getDimension(R.dimen.mapbox_minimum_scale_speed), context.getResources().getDimension(R.dimen.mapbox_minimum_angled_scale_speed), context.getResources().getDimension(R.dimen.mapbox_minimum_scale_velocity) ); RotateGestureListener rotateGestureListener = new RotateGestureListener( + context.getResources().getDimension(R.dimen.mapbox_density_constant), + context.getResources().getDimension(R.dimen.mapbox_angular_velocity_multiplier), context.getResources().getDimension(R.dimen.mapbox_minimum_angular_velocity)); ShoveGestureListener shoveGestureListener = new ShoveGestureListener(); TapGestureListener tapGestureListener = new TapGestureListener(); @@ -258,7 +264,7 @@ final class MapGestureDetector { }; /** - * Schedules a velocity animator to be executed when user lift fingers, + * Schedules a velocity animator to be executed when user lifts fingers, * unless canceled by the {@link #cancelAnimatorsRunnable}. * * @param animator animator ot be scheduled @@ -483,12 +489,16 @@ final class MapGestureDetector { private final float minimumGestureSpeed; private final float minimumAngledGestureSpeed; private final float minimumVelocity; + private final double scaleVelocityRatioThreshold; private boolean quickZoom; + private float spanSinceLast; - ScaleGestureListener(float minimumGestureSpeed, float minimumAngledGestureSpeed, float minimumVelocity) { + ScaleGestureListener(double densityMultiplier, float minimumGestureSpeed, float minimumAngledGestureSpeed, + float minimumVelocity) { this.minimumGestureSpeed = minimumGestureSpeed; this.minimumAngledGestureSpeed = minimumAngledGestureSpeed; this.minimumVelocity = minimumVelocity; + this.scaleVelocityRatioThreshold = SCALE_VELOCITY_RATIO_THRESHOLD * densityMultiplier; } @Override @@ -539,6 +549,8 @@ final class MapGestureDetector { notifyOnScaleBeginListeners(detector); + spanSinceLast = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan()); + return true; } @@ -554,6 +566,8 @@ final class MapGestureDetector { notifyOnScaleListeners(detector); + spanSinceLast = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan()); + return true; } @@ -571,7 +585,9 @@ final class MapGestureDetector { float velocityXY = Math.abs(velocityX) + Math.abs(velocityY); - if (!uiSettings.isScaleVelocityAnimationEnabled() || velocityXY < minimumVelocity) { + if (!uiSettings.isScaleVelocityAnimationEnabled() + || velocityXY < minimumVelocity + || spanSinceLast / velocityXY < scaleVelocityRatioThreshold) { // notifying listeners that camera is idle only if there is no follow-up animation dispatchCameraIdle(); return; @@ -625,10 +641,14 @@ final class MapGestureDetector { } private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { + private final float angularVelocityMultiplier; private final float minimumAngularVelocity; + private final double rotateVelocityRatioThreshold; - RotateGestureListener(float minimumAngularVelocity) { + RotateGestureListener(double densityMultiplier, float angularVelocityMultiplier, float minimumAngularVelocity) { + this.angularVelocityMultiplier = angularVelocityMultiplier; this.minimumAngularVelocity = minimumAngularVelocity; + this.rotateVelocityRatioThreshold = ROTATE_VELOCITY_RATIO_THRESHOLD * densityMultiplier; } @Override @@ -685,24 +705,23 @@ final class MapGestureDetector { float velocityY, float angularVelocity) { notifyOnRotateEndListeners(detector); - if (!uiSettings.isRotateVelocityAnimationEnabled() || Math.abs(angularVelocity) < minimumAngularVelocity) { + angularVelocity = angularVelocity * angularVelocityMultiplier; + angularVelocity = MathUtils.clamp(angularVelocity, -MAXIMUM_ANGULAR_VELOCITY, MAXIMUM_ANGULAR_VELOCITY); + + float velocityXY = Math.abs(velocityX) + Math.abs(velocityY); + float delta = Math.abs(detector.getDeltaSinceLast()); + double ratio = delta / velocityXY; + + if (!uiSettings.isRotateVelocityAnimationEnabled() + || Math.abs(angularVelocity) < minimumAngularVelocity + || (gesturesManager.getStandardScaleGestureDetector().isInProgress() && ratio < rotateVelocityRatioThreshold)) { // notifying listeners that camera is idle only if there is no follow-up animation dispatchCameraIdle(); return; } - boolean negative = angularVelocity < 0; - angularVelocity = (float) Math.pow(angularVelocity, 2); - angularVelocity = MathUtils.clamp( - angularVelocity, MapboxConstants.MINIMUM_ANGULAR_VELOCITY, MapboxConstants.MAXIMUM_ANGULAR_VELOCITY); - - long animationTime = (long) (Math.log(angularVelocity + 1) * 500); - - if (negative) { - angularVelocity = -angularVelocity; - } - - // todo clear scale velocity if angular velocity exceeds a threshold + long animationTime = (long) ((Math.log((Math.abs(angularVelocity)) + 1 / Math.pow(Math.E, 2)) + 2) + * SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER); PointF focalPoint = getRotateFocalPoint(detector); rotateAnimator = createRotateAnimator(angularVelocity, animationTime, focalPoint); @@ -929,10 +948,6 @@ final class MapGestureDetector { && (!uiSettings.isTiltGesturesEnabled() || !gesturesManager.getShoveGestureDetector().isInProgress()); } - private boolean isZoomValid(double mapZoom) { - return mapZoom >= MapboxConstants.MINIMUM_ZOOM && mapZoom <= MapboxConstants.MAXIMUM_ZOOM; - } - void notifyOnMapClickListeners(@NonNull PointF tapPoint) { for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) { if (listener.onMapClick(projection.fromScreenLocation(tapPoint))) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml index 018750400c..b2a0061c5b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml @@ -13,7 +13,13 @@ 225dp - 0.025dp + 0.10dp + + + 1.3dp + + + 0.29dp 25dp 400dp -- cgit v1.2.1