- use self-made fling

- add utilities from libgdx
This commit is contained in:
Hannes Janetzek 2013-03-18 03:48:31 +01:00
parent a1fcac202c
commit 38e2ac110d
4 changed files with 706 additions and 37 deletions

View File

@ -0,0 +1,420 @@
/*******************************************************************************
* Copyright 2011 libgdx authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils;
/**
* Takes a linear value in the range of 0-1 and outputs a (usually) non-linear,
* interpolated value.
*
* @author Nathan Sweet
*/
public abstract class Interpolation {
/** @param a Alpha value between 0 and 1.*/
abstract public float apply(float a);
/** @param a Alpha value between 0 and 1. */
public float apply(float start, float end, float a) {
return start + (end - start) * apply(a);
}
static public final Interpolation linear = new Interpolation() {
@Override
public float apply(float a) {
return a;
}
};
static public final Interpolation fade = new Interpolation() {
@Override
public float apply(float a) {
return MathUtils.clamp(a * a * a * (a * (a * 6 - 15) + 10), 0, 1);
}
};
static public final Pow pow2 = new Pow(2);
static public final PowIn pow2In = new PowIn(2);
static public final PowOut pow2Out = new PowOut(2);
static public final Pow pow3 = new Pow(3);
static public final PowIn pow3In = new PowIn(3);
static public final PowOut pow3Out = new PowOut(3);
static public final Pow pow4 = new Pow(4);
static public final PowIn pow4In = new PowIn(4);
static public final PowOut pow4Out = new PowOut(4);
static public final Pow pow5 = new Pow(5);
static public final PowIn pow5In = new PowIn(5);
static public final PowOut pow5Out = new PowOut(5);
static public final Interpolation sine = new Interpolation() {
@Override
public float apply(float a) {
return (1 - MathUtils.cos(a * MathUtils.PI)) / 2;
}
};
static public final Interpolation sineIn = new Interpolation() {
@Override
public float apply(float a) {
return 1 - MathUtils.cos(a * MathUtils.PI / 2);
}
};
static public final Interpolation sineOut = new Interpolation() {
@Override
public float apply(float a) {
return MathUtils.sin(a * MathUtils.PI / 2);
}
};
static public final Interpolation exp10 = new Exp(2, 10);
static public final Interpolation exp10In = new ExpIn(2, 10);
static public final Interpolation exp10Out = new ExpOut(2, 10);
static public final Interpolation exp5 = new Exp(2, 5);
static public final Interpolation exp5In = new ExpIn(2, 5);
static public final Interpolation exp5Out = new ExpOut(2, 5);
static public final Interpolation circle = new Interpolation() {
@Override
public float apply(float a) {
if (a <= 0.5f) {
a *= 2;
return (1 - (float) Math.sqrt(1 - a * a)) / 2;
}
a--;
a *= 2;
return ((float) Math.sqrt(1 - a * a) + 1) / 2;
}
};
static public final Interpolation circleIn = new Interpolation() {
@Override
public float apply(float a) {
return 1 - (float) Math.sqrt(1 - a * a);
}
};
static public final Interpolation circleOut = new Interpolation() {
@Override
public float apply(float a) {
a--;
return (float) Math.sqrt(1 - a * a);
}
};
static public final Elastic elastic = new Elastic(2, 10);
static public final Elastic elasticIn = new ElasticIn(2, 10);
static public final Elastic elasticOut = new ElasticOut(2, 10);
static public final Interpolation swing = new Swing(1.5f);
static public final Interpolation swingIn = new SwingIn(2f);
static public final Interpolation swingOut = new SwingOut(2f);
static public final Interpolation bounce = new Bounce(4);
static public final Interpolation bounceIn = new BounceIn(4);
static public final Interpolation bounceOut = new BounceOut(4);
//
static public class Pow extends Interpolation {
final int power;
public Pow(int power) {
this.power = power;
}
@Override
public float apply(float a) {
if (a <= 0.5f)
return (float) Math.pow(a * 2, power) / 2;
return (float) Math.pow((a - 1) * 2, power) / (power % 2 == 0 ? -2 : 2) + 1;
}
}
static public class PowIn extends Pow {
public PowIn(int power) {
super(power);
}
@Override
public float apply(float a) {
return (float) Math.pow(a, power);
}
}
static public class PowOut extends Pow {
public PowOut(int power) {
super(power);
}
@Override
public float apply(float a) {
return (float) Math.pow(a - 1, power) * (power % 2 == 0 ? -1 : 1) + 1;
}
}
//
static public class Exp extends Interpolation {
final float value, power, min, scale;
public Exp(float value, float power) {
this.value = value;
this.power = power;
min = (float) Math.pow(value, -power);
scale = 1 / (1 - min);
}
@Override
public float apply(float a) {
if (a <= 0.5f)
return ((float) Math.pow(value, power * (a * 2 - 1)) - min) * scale / 2;
return (2 - ((float) Math.pow(value, -power * (a * 2 - 1)) - min) * scale) / 2;
}
}
static public class ExpIn extends Exp {
public ExpIn(float value, float power) {
super(value, power);
}
@Override
public float apply(float a) {
return ((float) Math.pow(value, power * (a - 1)) - min) * scale;
}
}
static public class ExpOut extends Exp {
public ExpOut(float value, float power) {
super(value, power);
}
@Override
public float apply(float a) {
return 1 - ((float) Math.pow(value, -power * a) - min) * scale;
}
}
//
static public class Elastic extends Interpolation {
final float value, power;
public Elastic(float value, float power) {
this.value = value;
this.power = power;
}
@Override
public float apply(float a) {
if (a <= 0.5f) {
a *= 2;
return (float) Math.pow(value, power * (a - 1)) * MathUtils.sin(a * 20) * 1.0955f
/ 2;
}
a = 1 - a;
a *= 2;
return 1 - (float) Math.pow(value, power * (a - 1)) * MathUtils.sin((a) * 20) * 1.0955f
/ 2;
}
}
static public class ElasticIn extends Elastic {
public ElasticIn(float value, float power) {
super(value, power);
}
@Override
public float apply(float a) {
return (float) Math.pow(value, power * (a - 1)) * MathUtils.sin(a * 20) * 1.0955f;
}
}
static public class ElasticOut extends Elastic {
public ElasticOut(float value, float power) {
super(value, power);
}
@Override
public float apply(float a) {
a = 1 - a;
return (1 - (float) Math.pow(value, power * (a - 1)) * MathUtils.sin(a * 20) * 1.0955f);
}
}
//
static public class Bounce extends BounceOut {
public Bounce(float[] widths, float[] heights) {
super(widths, heights);
}
public Bounce(int bounces) {
super(bounces);
}
private float out(float a) {
float test = a + widths[0] / 2;
if (test < widths[0])
return test / (widths[0] / 2) - 1;
return super.apply(a);
}
@Override
public float apply(float a) {
if (a <= 0.5f)
return (1 - out(1 - a * 2)) / 2;
return out(a * 2 - 1) / 2 + 0.5f;
}
}
static public class BounceOut extends Interpolation {
final float[] widths, heights;
public BounceOut(float[] widths, float[] heights) {
if (widths.length != heights.length)
throw new IllegalArgumentException("Must be the same number of widths and heights.");
this.widths = widths;
this.heights = heights;
}
public BounceOut(int bounces) {
if (bounces < 2 || bounces > 5)
throw new IllegalArgumentException("bounces cannot be < 2 or > 5: " + bounces);
widths = new float[bounces];
heights = new float[bounces];
heights[0] = 1;
switch (bounces) {
case 2:
widths[0] = 0.6f;
widths[1] = 0.4f;
heights[1] = 0.33f;
break;
case 3:
widths[0] = 0.4f;
widths[1] = 0.4f;
widths[2] = 0.2f;
heights[1] = 0.33f;
heights[2] = 0.1f;
break;
case 4:
widths[0] = 0.34f;
widths[1] = 0.34f;
widths[2] = 0.2f;
widths[3] = 0.15f;
heights[1] = 0.26f;
heights[2] = 0.11f;
heights[3] = 0.03f;
break;
case 5:
widths[0] = 0.3f;
widths[1] = 0.3f;
widths[2] = 0.2f;
widths[3] = 0.1f;
widths[4] = 0.1f;
heights[1] = 0.45f;
heights[2] = 0.3f;
heights[3] = 0.15f;
heights[4] = 0.06f;
break;
}
widths[0] *= 2;
}
@Override
public float apply(float a) {
a += widths[0] / 2;
float width = 0, height = 0;
for (int i = 0, n = widths.length; i < n; i++) {
width = widths[i];
if (a <= width) {
height = heights[i];
break;
}
a -= width;
}
a /= width;
float z = 4 / width * height * a;
return 1 - (z - z * a) * width;
}
}
static public class BounceIn extends BounceOut {
public BounceIn(float[] widths, float[] heights) {
super(widths, heights);
}
public BounceIn(int bounces) {
super(bounces);
}
@Override
public float apply(float a) {
return 1 - super.apply(1 - a);
}
}
//
static public class Swing extends Interpolation {
private final float scale;
public Swing(float scale) {
this.scale = scale * 2;
}
@Override
public float apply(float a) {
if (a <= 0.5f) {
a *= 2;
return a * a * ((scale + 1) * a - scale) / 2;
}
a--;
a *= 2;
return a * a * ((scale + 1) * a + scale) / 2 + 1;
}
}
static public class SwingOut extends Interpolation {
private final float scale;
public SwingOut(float scale) {
this.scale = scale;
}
@Override
public float apply(float a) {
a--;
return a * a * ((scale + 1) * a + scale) + 1;
}
}
static public class SwingIn extends Interpolation {
private final float scale;
public SwingIn(float scale) {
this.scale = scale;
}
@Override
public float apply(float a) {
return a * a * ((scale + 1) * a - scale);
}
}
}

View File

@ -0,0 +1,248 @@
/*******************************************************************************
* Copyright 2011 libgdx authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils;
import java.util.Random;
/** Utility and fast math functions.
* <p>
* Thanks to Riven on JavaGaming.org for the basis of sin/cos/atan2/floor/ceil.
* @author Nathan Sweet */
public class MathUtils {
static public final float nanoToSec = 1 / 1000000000f;
// ---
static public final float PI = 3.1415927f;
public static final float PI2 = PI * 2;
static private final int SIN_BITS = 13; // Adjust for accuracy.
static private final int SIN_MASK = ~(-1 << SIN_BITS);
static private final int SIN_COUNT = SIN_MASK + 1;
static private final float radFull = PI * 2;
static private final float degFull = 360;
static private final float radToIndex = SIN_COUNT / radFull;
static private final float degToIndex = SIN_COUNT / degFull;
static public final float radiansToDegrees = 180f / PI;
static public final float radDeg = radiansToDegrees;
static public final float degreesToRadians = PI / 180;
static public final float degRad = degreesToRadians;
static private class Sin {
static final float[] table = new float[SIN_COUNT];
static {
for (int i = 0; i < SIN_COUNT; i++)
table[i] = (float)Math.sin((i + 0.5f) / SIN_COUNT * radFull);
for (int i = 0; i < 360; i += 90)
table[(int)(i * degToIndex) & SIN_MASK] = (float)Math.sin(i * degreesToRadians);
}
}
static private class Cos {
static final float[] table = new float[SIN_COUNT];
static {
for (int i = 0; i < SIN_COUNT; i++)
table[i] = (float)Math.cos((i + 0.5f) / SIN_COUNT * radFull);
for (int i = 0; i < 360; i += 90)
table[(int)(i * degToIndex) & SIN_MASK] = (float)Math.cos(i * degreesToRadians);
}
}
/** Returns the sine in radians. */
static public final float sin (float radians) {
return Sin.table[(int)(radians * radToIndex) & SIN_MASK];
}
/** Returns the cosine in radians. */
static public final float cos (float radians) {
return Cos.table[(int)(radians * radToIndex) & SIN_MASK];
}
/** Returns the sine in radians. */
static public final float sinDeg (float degrees) {
return Sin.table[(int)(degrees * degToIndex) & SIN_MASK];
}
/** Returns the cosine in radians. */
static public final float cosDeg (float degrees) {
return Cos.table[(int)(degrees * degToIndex) & SIN_MASK];
}
// ---
static private final int ATAN2_BITS = 7; // Adjust for accuracy.
static private final int ATAN2_BITS2 = ATAN2_BITS << 1;
static private final int ATAN2_MASK = ~(-1 << ATAN2_BITS2);
static private final int ATAN2_COUNT = ATAN2_MASK + 1;
static final int ATAN2_DIM = (int)Math.sqrt(ATAN2_COUNT);
static private final float INV_ATAN2_DIM_MINUS_1 = 1.0f / (ATAN2_DIM - 1);
static private class Atan2 {
static final float[] table = new float[ATAN2_COUNT];
static {
for (int i = 0; i < ATAN2_DIM; i++) {
for (int j = 0; j < ATAN2_DIM; j++) {
float x0 = (float)i / ATAN2_DIM;
float y0 = (float)j / ATAN2_DIM;
table[j * ATAN2_DIM + i] = (float)Math.atan2(y0, x0);
}
}
}
}
/** Returns atan2 in radians from a lookup table. */
static public final float atan2 (float y, float x) {
float add, mul;
if (x < 0) {
if (y < 0) {
y = -y;
mul = 1;
} else
mul = -1;
x = -x;
add = -PI;
} else {
if (y < 0) {
y = -y;
mul = -1;
} else
mul = 1;
add = 0;
}
float invDiv = 1 / ((x < y ? y : x) * INV_ATAN2_DIM_MINUS_1);
int xi = (int)(x * invDiv);
int yi = (int)(y * invDiv);
return (Atan2.table[yi * ATAN2_DIM + xi] + add) * mul;
}
// ---
static public Random random = new Random();
/** Returns a random number between 0 (inclusive) and the specified value (inclusive). */
static public final int random (int range) {
return random.nextInt(range + 1);
}
/** Returns a random number between start (inclusive) and end (inclusive). */
static public final int random (int start, int end) {
return start + random.nextInt(end - start + 1);
}
/** Returns a random boolean value. */
static public final boolean randomBoolean () {
return random.nextBoolean();
}
/** Returns random number between 0.0 (inclusive) and 1.0 (exclusive). */
static public final float random () {
return random.nextFloat();
}
/** Returns a random number between 0 (inclusive) and the specified value (exclusive). */
static public final float random (float range) {
return random.nextFloat() * range;
}
/** Returns a random number between start (inclusive) and end (exclusive). */
static public final float random (float start, float end) {
return start + random.nextFloat() * (end - start);
}
// ---
/** Returns the next power of two. Returns the specified value if the value is already a power of two. */
static public int nextPowerOfTwo (int value) {
if (value == 0) return 1;
value--;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return value + 1;
}
static public boolean isPowerOfTwo (int value) {
return value != 0 && (value & value - 1) == 0;
}
// ---
static public int clamp (int value, int min, int max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
static public short clamp (short value, short min, short max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
static public float clamp (float value, float min, float max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
// ---
static private final int BIG_ENOUGH_INT = 16 * 1024;
static private final double BIG_ENOUGH_FLOOR = BIG_ENOUGH_INT;
static private final double CEIL = 0.9999999;
static private final double BIG_ENOUGH_CEIL = Double.longBitsToDouble(Double.doubleToLongBits(BIG_ENOUGH_INT + 1) - 1);
static private final double BIG_ENOUGH_ROUND = BIG_ENOUGH_INT + 0.5f;
/** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats from
* -(2^14) to (Float.MAX_VALUE - 2^14). */
static public int floor (float x) {
return (int)(x + BIG_ENOUGH_FLOOR) - BIG_ENOUGH_INT;
}
/** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats that are
* positive. Note this method simply casts the float to int. */
static public int floorPositive (float x) {
return (int)x;
}
/** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats from
* -(2^14) to (Float.MAX_VALUE - 2^14). */
static public int ceil (float x) {
return (int)(x + BIG_ENOUGH_CEIL) - BIG_ENOUGH_INT;
}
/** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats that
* are positive. */
static public int ceilPositive (float x) {
return (int)(x + CEIL);
}
/** Returns the closest integer to the specified float. This method will only properly round floats from -(2^14) to
* (Float.MAX_VALUE - 2^14). */
static public int round (float x) {
return (int)(x + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT;
}
/** Returns the closest integer to the specified float. This method will only properly round floats that are positive. */
static public int roundPositive (float x) {
return (int)(x + 0.5f);
}
}

View File

@ -25,6 +25,7 @@ import org.oscim.core.PointD;
import org.oscim.core.PointF;
import org.oscim.core.Tile;
import org.oscim.utils.FastMath;
import org.oscim.utils.Interpolation;
import org.oscim.utils.Matrix4;
import android.opengl.Matrix;
@ -33,8 +34,6 @@ import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
/**
* A MapPosition stores the latitude and longitude coordinate of a MapView
@ -78,7 +77,6 @@ public class MapViewPosition {
public float mTilt;
private final AnimationHandler mHandler;
private final Scroller mScroller;
MapViewPosition(MapView mapView) {
mMapView = mapView;
@ -89,13 +87,6 @@ public class MapViewPosition {
mAbsScale = 1;
mHandler = new AnimationHandler(this);
mScroller = new Scroller(mapView.getContext(), new LinearInterpolator() {
@Override
public float getInterpolation(float input) {
return (float) Math.sqrt(input);
}
});
}
private final Matrix4 mProjMatrix = new Matrix4();
@ -739,20 +730,48 @@ public class MapViewPosition {
mHandler.start(mDuration);
}
synchronized boolean fling(long millisLeft){
float delta = (mDuration - millisLeft) / mDuration;
float adv = Interpolation.exp5Out.apply(delta);
//adv *= Interpolation.
//float adv = delta;
float dx = mVelocityX * adv;
float dy = mVelocityY * adv;
if (dx != 0 || dy != 0){
moveMap((float)(dx - mScrollX), (float)(dy - mScrollY));
mMapView.redrawMap(true);
mScrollX = dx;
mScrollY = dy;
}
return true;
}
private float mVelocityX;
private float mVelocityY;
public synchronized void animateFling(int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY) {
mScrollX = 0;
mScrollY = 0;
mScroller.fling(0, 0, velocityX, velocityY, minX, maxX, minY, maxY);
mDuration = 300;
mVelocityX = velocityX * (mDuration / 1000);
mVelocityY = velocityY * (mDuration / 1000);
FastMath.clamp(mVelocityX, minX, maxX);
FastMath.clamp(mVelocityY, minY, maxY);
// mScroller.fling(0, 0, velocityX, velocityY, minX, maxX, minY, maxY);
mAnimFling = true;
mAnimMove = false;
mAnimScale = false;
//mMapView.mGLView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mDuration = 250;
mHandler.start(mDuration);
}
@ -770,26 +789,6 @@ public class MapViewPosition {
//scroll();
}
synchronized boolean scroll() {
if (mScroller.isFinished()) {
return false;
}
mScroller.computeScrollOffset();
double dx = mScroller.getCurrX();
double dy = mScroller.getCurrY();
int mx = (int) (dx - mScrollX);
int my = (int) (dy - mScrollY);
if (mx >= 1 || my >= 1 || mx <= -1 || my <= -1) {
moveMap(mx, my);
mScrollX = dx;
mScrollY = dy;
}
return true;
}
void onTick(long millisLeft) {
boolean changed = false;
@ -818,7 +817,7 @@ public class MapViewPosition {
updatePosition();
}
if (mAnimFling && scroll())
if (mAnimFling && fling(millisLeft))
changed = true;
if (changed)

View File

@ -382,8 +382,8 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
if (mWasMulti)
return true;
int w = Tile.TILE_SIZE * 6;
int h = Tile.TILE_SIZE * 6;
int w = Tile.TILE_SIZE * 3;
int h = Tile.TILE_SIZE * 3;
//if (mMapView.enablePagedFling) {
// double a = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
@ -399,8 +399,10 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
//} else {
float s = (200 / mMapView.dpi);
mMapPosition.animateFling(Math.round(velocityX * s), Math.round(velocityY * s), -w, w, -h,
h);
mMapPosition.animateFling(
Math.round(velocityX * s),
Math.round(velocityY * s),
-w, w, -h, h);
return true;
}