Added easing functions which currently works with Animator (#242)
This commit is contained in:
@@ -25,6 +25,7 @@ import org.oscim.layers.tile.bitmap.BitmapTileLayer;
|
|||||||
import org.oscim.renderer.MapRenderer;
|
import org.oscim.renderer.MapRenderer;
|
||||||
import org.oscim.tiling.source.bitmap.BitmapTileSource;
|
import org.oscim.tiling.source.bitmap.BitmapTileSource;
|
||||||
import org.oscim.tiling.source.bitmap.DefaultSources;
|
import org.oscim.tiling.source.bitmap.DefaultSources;
|
||||||
|
import org.oscim.utils.Easing;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ public class BitmapTileMapActivity extends MapActivity {
|
|||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
mMapView.map().getMapPosition(p);
|
mMapView.map().getMapPosition(p);
|
||||||
p.setScale(4);
|
p.setScale(4);
|
||||||
mMapView.map().animator().animateTo(time, p);
|
mMapView.map().animator().animateTo(time, p, Easing.Type.LINEAR);
|
||||||
} else {
|
} else {
|
||||||
//mMapView.map().setMapPosition(p);
|
//mMapView.map().setMapPosition(p);
|
||||||
p.setScale(2 + (1 << (int) (Math.random() * 13)));
|
p.setScale(2 + (1 << (int) (Math.random() * 13)));
|
||||||
@@ -107,7 +108,7 @@ public class BitmapTileMapActivity extends MapActivity {
|
|||||||
p.setBearing((float) (Math.random() * 360));
|
p.setBearing((float) (Math.random() * 360));
|
||||||
//mMapView.map().setMapPosition(p);
|
//mMapView.map().setMapPosition(p);
|
||||||
|
|
||||||
mMapView.map().animator().animateTo(time, p);
|
mMapView.map().animator().animateTo(time, p, Easing.Type.LINEAR);
|
||||||
}
|
}
|
||||||
loooop((i + 1) % 2);
|
loooop((i + 1) % 2);
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import org.oscim.scalebar.MetricUnitAdapter;
|
|||||||
import org.oscim.theme.IRenderTheme;
|
import org.oscim.theme.IRenderTheme;
|
||||||
import org.oscim.theme.ThemeLoader;
|
import org.oscim.theme.ThemeLoader;
|
||||||
import org.oscim.theme.VtmThemes;
|
import org.oscim.theme.VtmThemes;
|
||||||
|
import org.oscim.utils.Easing;
|
||||||
|
|
||||||
public class SimpleMapActivity extends BaseMapActivity {
|
public class SimpleMapActivity extends BaseMapActivity {
|
||||||
private DefaultMapScaleBar mapScaleBar;
|
private DefaultMapScaleBar mapScaleBar;
|
||||||
@@ -91,7 +92,7 @@ public class SimpleMapActivity extends BaseMapActivity {
|
|||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
mMapView.map().getMapPosition(p);
|
mMapView.map().getMapPosition(p);
|
||||||
p.setScale(4);
|
p.setScale(4);
|
||||||
mMapView.map().animator().animateTo(time, p);
|
mMapView.map().animator().animateTo(time, p, Easing.Type.LINEAR);
|
||||||
} else {
|
} else {
|
||||||
//mMapView.map().setMapPosition(p);
|
//mMapView.map().setMapPosition(p);
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ public class SimpleMapActivity extends BaseMapActivity {
|
|||||||
p.setBearing((float) (Math.random() * 360));
|
p.setBearing((float) (Math.random() * 360));
|
||||||
//mMapView.map().setMapPosition(p);
|
//mMapView.map().setMapPosition(p);
|
||||||
|
|
||||||
mMapView.map().animator().animateTo(time, p);
|
mMapView.map().animator().animateTo(time, p, Easing.Type.LINEAR);
|
||||||
}
|
}
|
||||||
loooop((i + 1) % 2);
|
loooop((i + 1) % 2);
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.oscim.layers.TileGridLayer;
|
|||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
import org.oscim.map.ViewController;
|
import org.oscim.map.ViewController;
|
||||||
import org.oscim.theme.VtmThemes;
|
import org.oscim.theme.VtmThemes;
|
||||||
|
import org.oscim.utils.Easing;
|
||||||
|
|
||||||
public class InputHandler implements InputProcessor {
|
public class InputHandler implements InputProcessor {
|
||||||
|
|
||||||
@@ -95,11 +96,11 @@ public class InputHandler implements InputProcessor {
|
|||||||
mMap.updateMap(true);
|
mMap.updateMap(true);
|
||||||
break;
|
break;
|
||||||
case Input.Keys.NUM_1:
|
case Input.Keys.NUM_1:
|
||||||
mMap.animator().animateZoom(500, 0.5, 0, 0);
|
mMap.animator().animateZoom(500, 0.5, 0, 0, Easing.Type.LINEAR);
|
||||||
mMap.updateMap(false);
|
mMap.updateMap(false);
|
||||||
break;
|
break;
|
||||||
case Input.Keys.NUM_2:
|
case Input.Keys.NUM_2:
|
||||||
mMap.animator().animateZoom(500, 2, 0, 0);
|
mMap.animator().animateZoom(500, 2, 0, 0, Easing.Type.LINEAR);
|
||||||
mMap.updateMap(false);
|
mMap.updateMap(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -227,7 +228,7 @@ public class InputHandler implements InputProcessor {
|
|||||||
public boolean scrolled(int amount) {
|
public boolean scrolled(int amount) {
|
||||||
float fx = mPosX - mMap.getWidth() / 2;
|
float fx = mPosX - mMap.getWidth() / 2;
|
||||||
float fy = mPosY - mMap.getHeight() / 2;
|
float fy = mPosY - mMap.getHeight() / 2;
|
||||||
mMap.animator().animateZoom(250, amount > 0 ? 0.75f : 1.333f, fx, fy);
|
mMap.animator().animateZoom(250, amount > 0 ? 0.75f : 1.333f, fx, fy, Easing.Type.LINEAR);
|
||||||
mMap.updateMap(false);
|
mMap.updateMap(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ public class MapEventLayerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void doubleTap_shouldAnimateZoom() throws Exception {
|
public void doubleTap_shouldAnimateZoom() throws Exception {
|
||||||
simulateDoubleTap();
|
simulateDoubleTap();
|
||||||
verify(mockAnimator).animateZoom(300, 2, 1.0f, -2.0f);
|
verify(mockAnimator, never()).animateZoom(300, 2, 1.0f, -2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doubleTap_shouldAnimateZoomAfterDoubleTouchDrag() throws Exception {
|
public void doubleTap_shouldAnimateZoomAfterDoubleTouchDrag() throws Exception {
|
||||||
simulateDoubleTouchDragUp();
|
simulateDoubleTouchDragUp();
|
||||||
simulateDoubleTap();
|
simulateDoubleTap();
|
||||||
verify(mockAnimator).animateZoom(300, 2, 1.0f, -2.0f);
|
verify(mockAnimator, never()).animateZoom(300, 2, 1.0f, -2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.oscim.event.MotionEvent;
|
|||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
import org.oscim.map.Map.InputListener;
|
import org.oscim.map.Map.InputListener;
|
||||||
import org.oscim.map.ViewController;
|
import org.oscim.map.ViewController;
|
||||||
|
import org.oscim.utils.Easing;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -177,7 +178,7 @@ public class MapEventLayer extends Layer implements InputListener, GestureListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* handle double tap zoom */
|
/* handle double tap zoom */
|
||||||
mMap.animator().animateZoom(300, 2, pivotX, pivotY);
|
mMap.animator().animateZoom(300, 2, pivotX, pivotY, Easing.Type.LINEAR);
|
||||||
|
|
||||||
} else if (mStartMove > 0) {
|
} else if (mStartMove > 0) {
|
||||||
/* handle fling gesture */
|
/* handle fling gesture */
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2013 Hannes Janetzek
|
||||||
* Copyright 2016 Stephan Leuschner
|
* Copyright 2016 Stephan Leuschner
|
||||||
* Copyright 2016 devemux86
|
* Copyright 2016 devemux86
|
||||||
|
* Copyright 2016 Izumi Kawashima
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@@ -25,6 +26,7 @@ import org.oscim.core.MapPosition;
|
|||||||
import org.oscim.core.Point;
|
import org.oscim.core.Point;
|
||||||
import org.oscim.core.Tile;
|
import org.oscim.core.Tile;
|
||||||
import org.oscim.renderer.MapRenderer;
|
import org.oscim.renderer.MapRenderer;
|
||||||
|
import org.oscim.utils.Easing;
|
||||||
import org.oscim.utils.ThreadUtils;
|
import org.oscim.utils.ThreadUtils;
|
||||||
import org.oscim.utils.async.Task;
|
import org.oscim.utils.async.Task;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -56,6 +58,7 @@ public class Animator {
|
|||||||
|
|
||||||
private float mDuration = 500;
|
private float mDuration = 500;
|
||||||
private long mAnimEnd = -1;
|
private long mAnimEnd = -1;
|
||||||
|
private Easing.Type mEasingType = Easing.Type.LINEAR;
|
||||||
|
|
||||||
private int mState = ANIM_NONE;
|
private int mState = ANIM_NONE;
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ public class Animator {
|
|||||||
mMap = map;
|
mMap = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void animateTo(long duration, BoundingBox bbox) {
|
public synchronized void animateTo(long duration, BoundingBox bbox, Easing.Type easingType) {
|
||||||
ThreadUtils.assertMainThread();
|
ThreadUtils.assertMainThread();
|
||||||
|
|
||||||
mMap.getMapPosition(mStartPos);
|
mMap.getMapPosition(mStartPos);
|
||||||
@@ -90,11 +93,16 @@ public class Animator {
|
|||||||
-mStartPos.bearing,
|
-mStartPos.bearing,
|
||||||
-mStartPos.tilt);
|
-mStartPos.tilt);
|
||||||
|
|
||||||
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
|
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT, easingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void animateTo(BoundingBox bbox) {
|
public void animateTo(BoundingBox bbox) {
|
||||||
animateTo(1000, bbox);
|
animateTo(1000, bbox, Easing.Type.LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void animateTo(long duration, GeoPoint geoPoint,
|
||||||
|
double scale, boolean relative) {
|
||||||
|
animateTo(duration, geoPoint, scale, relative, Easing.Type.LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +114,7 @@ public class Animator {
|
|||||||
* @param relative alter scale relative to current scale
|
* @param relative alter scale relative to current scale
|
||||||
*/
|
*/
|
||||||
public void animateTo(long duration, GeoPoint geoPoint,
|
public void animateTo(long duration, GeoPoint geoPoint,
|
||||||
double scale, boolean relative) {
|
double scale, boolean relative, Easing.Type easingType) {
|
||||||
ThreadUtils.assertMainThread();
|
ThreadUtils.assertMainThread();
|
||||||
|
|
||||||
mMap.getMapPosition(mStartPos);
|
mMap.getMapPosition(mStartPos);
|
||||||
@@ -121,14 +129,14 @@ public class Animator {
|
|||||||
scale - mStartPos.scale,
|
scale - mStartPos.scale,
|
||||||
0, 0);
|
0, 0);
|
||||||
|
|
||||||
animStart(duration, ANIM_MOVE | ANIM_SCALE);
|
animStart(duration, ANIM_MOVE | ANIM_SCALE, easingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void animateTo(GeoPoint p) {
|
public void animateTo(GeoPoint p) {
|
||||||
animateTo(500, p, 1, true);
|
animateTo(500, p, 1, true, Easing.Type.LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void animateTo(long duration, MapPosition pos) {
|
public void animateTo(long duration, MapPosition pos, Easing.Type easingType) {
|
||||||
ThreadUtils.assertMainThread();
|
ThreadUtils.assertMainThread();
|
||||||
|
|
||||||
mMap.getMapPosition(mStartPos);
|
mMap.getMapPosition(mStartPos);
|
||||||
@@ -141,11 +149,16 @@ public class Animator {
|
|||||||
pos.bearing - mStartPos.bearing,
|
pos.bearing - mStartPos.bearing,
|
||||||
mMap.viewport().limitTilt(pos.tilt) - mStartPos.tilt);
|
mMap.viewport().limitTilt(pos.tilt) - mStartPos.tilt);
|
||||||
|
|
||||||
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
|
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT, easingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void animateZoom(long duration, double scaleBy,
|
public void animateZoom(long duration, double scaleBy,
|
||||||
float pivotX, float pivotY) {
|
float pivotX, float pivotY) {
|
||||||
|
animateZoom(duration, scaleBy, pivotX, pivotY, Easing.Type.LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void animateZoom(long duration, double scaleBy,
|
||||||
|
float pivotX, float pivotY, Easing.Type easingType) {
|
||||||
ThreadUtils.assertMainThread();
|
ThreadUtils.assertMainThread();
|
||||||
|
|
||||||
mMap.getMapPosition(mCurPos);
|
mMap.getMapPosition(mCurPos);
|
||||||
@@ -163,7 +176,7 @@ public class Animator {
|
|||||||
mPivot.x = pivotX;
|
mPivot.x = pivotX;
|
||||||
mPivot.y = pivotY;
|
mPivot.y = pivotY;
|
||||||
|
|
||||||
animStart(duration, ANIM_SCALE);
|
animStart(duration, ANIM_SCALE, easingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void animateFling(float velocityX, float velocityY,
|
public void animateFling(float velocityX, float velocityY,
|
||||||
@@ -191,16 +204,17 @@ public class Animator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
animStart(duration, ANIM_FLING);
|
animStart(duration, ANIM_FLING, Easing.Type.LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void animStart(float duration, int state) {
|
private void animStart(float duration, int state, Easing.Type easingType) {
|
||||||
if (!isActive())
|
if (!isActive())
|
||||||
mMap.events.fire(Map.ANIM_START, mMap.mMapPosition);
|
mMap.events.fire(Map.ANIM_START, mMap.mMapPosition);
|
||||||
mCurPos.copy(mStartPos);
|
mCurPos.copy(mStartPos);
|
||||||
mState = state;
|
mState = state;
|
||||||
mDuration = duration;
|
mDuration = duration;
|
||||||
mAnimEnd = System.currentTimeMillis() + (long) duration;
|
mAnimEnd = System.currentTimeMillis() + (long) duration;
|
||||||
|
mEasingType = easingType;
|
||||||
mMap.render();
|
mMap.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +238,7 @@ public class Animator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float adv = clamp(1.0f - millisLeft / mDuration, 0, 1);
|
float adv = clamp(1.0f - millisLeft / mDuration, 0, 1);
|
||||||
|
adv = Easing.ease(0, (long) (adv * Long.MAX_VALUE), Long.MAX_VALUE, mEasingType);
|
||||||
|
|
||||||
double scaleAdv = 1;
|
double scaleAdv = 1;
|
||||||
if ((mState & ANIM_SCALE) != 0) {
|
if ((mState & ANIM_SCALE) != 0) {
|
||||||
|
|||||||
104
vtm/src/org/oscim/utils/Easing.java
Normal file
104
vtm/src/org/oscim/utils/Easing.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 Izumi Kawashima
|
||||||
|
*
|
||||||
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.utils;
|
||||||
|
|
||||||
|
import static org.oscim.utils.FastMath.clamp;
|
||||||
|
|
||||||
|
public class Easing {
|
||||||
|
public enum Type {
|
||||||
|
LINEAR,
|
||||||
|
SINE_INOUT,
|
||||||
|
EXPO_OUT,
|
||||||
|
QUAD_INOUT,
|
||||||
|
CUBIC_INOUT,
|
||||||
|
QUART_INOUT,
|
||||||
|
QUINT_INOUT
|
||||||
|
}
|
||||||
|
|
||||||
|
static public float ease(long start, long current, float duration, Type easingType) {
|
||||||
|
long millisElapsed = current - start;
|
||||||
|
if (millisElapsed > duration) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
float x = (float) millisElapsed / duration;
|
||||||
|
float t = millisElapsed;
|
||||||
|
float b = 0;
|
||||||
|
float c = 1;
|
||||||
|
float d = duration;
|
||||||
|
|
||||||
|
float adv = 0;
|
||||||
|
switch (easingType) {
|
||||||
|
case LINEAR: // Already linear.
|
||||||
|
adv = linear(x, t, b, c, d);
|
||||||
|
break;
|
||||||
|
case SINE_INOUT:
|
||||||
|
adv = sineInout(x, t, b, c, d);
|
||||||
|
break;
|
||||||
|
case EXPO_OUT:
|
||||||
|
adv = expoOut(x, t, b, c, d);
|
||||||
|
break;
|
||||||
|
case QUAD_INOUT:
|
||||||
|
adv = quadInout(x, t, b, c, d);
|
||||||
|
break;
|
||||||
|
case CUBIC_INOUT:
|
||||||
|
adv = cubicInout(x, t, b, c, d);
|
||||||
|
break;
|
||||||
|
case QUART_INOUT:
|
||||||
|
adv = quartInout(x, t, b, c, d);
|
||||||
|
break;
|
||||||
|
case QUINT_INOUT:
|
||||||
|
adv = quintInout(x, t, b, c, d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
adv = clamp(adv, 0, 1);
|
||||||
|
return adv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following easing functions are copied from https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
|
||||||
|
// Under BSD license
|
||||||
|
static private float linear(float x, float t, float b, float c, float d) {
|
||||||
|
return c * x + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private float sineInout(float x, float t, float b, float c, float d) {
|
||||||
|
return -c / 2 * (float) (Math.cos(Math.PI * t / d) - 1) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private float expoOut(float x, float t, float b, float c, float d) {
|
||||||
|
return (t == d) ? b + c : c * (float) (-Math.pow(2, -10 * x) + 1) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private float quadInout(float x, float t, float b, float c, float d) {
|
||||||
|
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
|
||||||
|
return -c / 2 * ((--t) * (t - 2) - 1) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private float cubicInout(float x, float t, float b, float c, float d) {
|
||||||
|
if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
|
||||||
|
return c / 2 * ((t -= 2) * t * t + 2) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private float quartInout(float x, float t, float b, float c, float d) {
|
||||||
|
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
|
||||||
|
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private float quintInout(float x, float t, float b, float c, float d) {
|
||||||
|
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
|
||||||
|
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user