start to improve gesture detection:

#21, #28
This commit is contained in:
Hannes Janetzek 2014-01-28 01:56:26 +01:00
parent bda080f34f
commit 0bc0d59446
2 changed files with 96 additions and 84 deletions

View File

@ -17,9 +17,12 @@
package org.oscim.layers; package org.oscim.layers;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.event.Gesture;
import org.oscim.event.GestureListener;
import org.oscim.event.MotionEvent; import org.oscim.event.MotionEvent;
import org.oscim.map.Map; import org.oscim.map.Map;
import org.oscim.map.Viewport; import org.oscim.map.Viewport;
import org.oscim.utils.FastMath;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -33,8 +36,8 @@ import org.slf4j.LoggerFactory;
* http://en.wikipedia.org/wiki/Viterbi_algorithm * http://en.wikipedia.org/wiki/Viterbi_algorithm
*/ */
public class MapEventLayer extends Layer implements Map.InputListener { public class MapEventLayer extends Layer implements Map.InputListener, GestureListener {
private static final boolean debug = false;
static final Logger log = LoggerFactory.getLogger(MapEventLayer.class); static final Logger log = LoggerFactory.getLogger(MapEventLayer.class);
private float mSumScale; private float mSumScale;
@ -44,7 +47,6 @@ public class MapEventLayer extends Layer implements Map.InputListener {
private boolean mBeginRotate; private boolean mBeginRotate;
private boolean mBeginTilt; private boolean mBeginTilt;
private boolean mDoubleTap; private boolean mDoubleTap;
private boolean mWasMulti;
private float mPrevX; private float mPrevX;
private float mPrevY; private float mPrevY;
@ -58,11 +60,16 @@ public class MapEventLayer extends Layer implements Map.InputListener {
private float mFocusX; private float mFocusX;
private float mFocusY; private float mFocusY;
private long mStartMove;
protected static final int JUMP_THRESHOLD = 100; protected static final int JUMP_THRESHOLD = 100;
protected static final double PINCH_ZOOM_THRESHOLD = 5; protected static final double PINCH_ZOOM_THRESHOLD = 5;
protected static final double PINCH_ROTATE_THRESHOLD = 0.02; protected static final double PINCH_ROTATE_THRESHOLD = 0.02;
protected static final float PINCH_TILT_THRESHOLD = 1f; protected static final float PINCH_TILT_THRESHOLD = 1f;
/** ms since start of move to reduce fling scroll */
protected static final float FLING_THREHSHOLD = 100;
private final Viewport mMapPosition; private final Viewport mMapPosition;
private final VelocityTracker mTracker; private final VelocityTracker mTracker;
@ -81,6 +88,7 @@ public class MapEventLayer extends Layer implements Map.InputListener {
private boolean mEnableTilt = true; private boolean mEnableTilt = true;
private boolean mEnableMove = true; private boolean mEnableMove = true;
private boolean mEnableZoom = true; private boolean mEnableZoom = true;
private boolean mDown;
public void enableRotation(boolean enable) { public void enableRotation(boolean enable) {
mEnableRotation = enable; mEnableRotation = enable;
@ -107,30 +115,57 @@ public class MapEventLayer extends Layer implements Map.InputListener {
int action = getAction(e); int action = getAction(e);
if (action == MotionEvent.ACTION_DOWN) { if (action == MotionEvent.ACTION_DOWN) {
mMap.getAnimator().cancel();
mBeginRotate = false; mBeginRotate = false;
mBeginTilt = false; mBeginTilt = false;
mBeginScale = false; mBeginScale = false;
mDoubleTap = false; mDoubleTap = false;
mWasMulti = false; mStartMove = -1;
mPrevX = e.getX(0); mPrevX = e.getX(0);
mPrevY = e.getY(0); mPrevY = e.getY(0);
mDown = true;
mTracker.start(mPrevX, mPrevY, e.getTime());
return true; return true;
} else if (action == MotionEvent.ACTION_MOVE) { }
if (!mDown) {
// no down event received
return false;
}
if (action == MotionEvent.ACTION_MOVE) {
return onActionMove(e); return onActionMove(e);
} else if (action == MotionEvent.ACTION_UP) { }
onFling(mTracker.getVelocityX(), mTracker.getVelocityY()); if (action == MotionEvent.ACTION_UP) {
mDown = false;
if (mStartMove < 0)
return true; return true;
} else if (action == MotionEvent.ACTION_CANCEL) {
float vx = mTracker.getVelocityX();
float vy = mTracker.getVelocityY();
// reduce velocity for short moves
float tx = e.getTime() - mStartMove;
if (tx < FLING_THREHSHOLD) {
float s = tx / FLING_THREHSHOLD;
vx = vx * (s * s);
vy = vy * (s * s);
}
doFling(vx, vy);
return true;
}
if (action == MotionEvent.ACTION_CANCEL) {
mDoubleTap = false; mDoubleTap = false;
mStartMove = -1;
mDown = false;
return true; return true;
} else if (action == MotionEvent.ACTION_POINTER_DOWN) { }
mWasMulti = true; if (action == MotionEvent.ACTION_POINTER_DOWN) {
mStartMove = -1;
updateMulti(e); updateMulti(e);
return true; return true;
} else if (action == MotionEvent.ACTION_POINTER_UP) { }
if (action == MotionEvent.ACTION_POINTER_UP) {
updateMulti(e); updateMulti(e);
return true; return true;
} }
@ -152,41 +187,43 @@ public class MapEventLayer extends Layer implements Map.InputListener {
float width = mMap.getWidth(); float width = mMap.getWidth();
float height = mMap.getHeight(); float height = mMap.getHeight();
mTracker.update(x1, y1, e.getTime()); if (e.getPointerCount() < 2) {
mPrevX = x1;
// return if detect a new gesture, as indicated by a large jump mPrevY = y1;
if (Math.abs(mx) > JUMP_THRESHOLD || Math.abs(my) > JUMP_THRESHOLD)
return true;
// double-tap + hold // double-tap + hold
if (mDoubleTap) { if (mDoubleTap) {
if (debug)
log.debug("tap scale: " + mx + " " + my);
mMapPosition.scaleMap(1 - my / (height / 8), 0, 0); mMapPosition.scaleMap(1 - my / (height / 8), 0, 0);
mMap.updateMap(true); mMap.updateMap(true);
mStartMove = -1;
mPrevX = x1;
mPrevY = y1;
return true; return true;
} }
if (e.getPointerCount() < 2) {
if (!mEnableMove) if (!mEnableMove)
return true; return true;
if (mx > 1 || mx < -1 || my > 1 || my < -1) { if (mStartMove < 0) {
mMapPosition.moveMap(mx, my); if (FastMath.withinSquaredDist(mx, my, 100)) {
mMap.updateMap(true); mPrevX -= mx;
mPrevY -= my;
mPrevX = x1;
mPrevY = y1;
}
return true; return true;
} }
mStartMove = e.getTime();
mTracker.start(x1, y1, mStartMove);
return true;
}
mMapPosition.moveMap(mx, my);
mTracker.update(x1, y1, e.getTime());
mMap.updateMap(true);
return true;
}
mStartMove = -1;
float x2 = e.getX(1); float x2 = e.getX(1);
float y2 = e.getY(1); float y2 = e.getY(1);
float dx = (x1 - x2); float dx = (x1 - x2);
float dy = (y1 - y2); float dy = (y1 - y2);
float slope = 0; float slope = 0;
@ -202,7 +239,6 @@ public class MapEventLayer extends Layer implements Map.InputListener {
double r = rad - mAngle; double r = rad - mAngle;
boolean startScale = (Math.abs(deltaPinchWidth) > PINCH_ZOOM_THRESHOLD); boolean startScale = (Math.abs(deltaPinchWidth) > PINCH_ZOOM_THRESHOLD);
boolean changed = false; boolean changed = false;
if (mEnableZoom && !mBeginTilt && (mBeginScale || startScale)) { if (mEnableZoom && !mBeginTilt && (mBeginScale || startScale)) {
@ -263,16 +299,16 @@ public class MapEventLayer extends Layer implements Map.InputListener {
mAngle = rad; mAngle = rad;
} }
if (changed) { if (!changed)
return true;
mMap.updateMap(true); mMap.updateMap(true);
mPrevPinchWidth = pinchWidth; mPrevPinchWidth = pinchWidth;
mPrevX2 = x2;
mPrevY2 = y2;
}
mPrevX = x1; mPrevX = x1;
mPrevY = y1; mPrevY = y1;
mPrevX2 = x2;
mPrevY2 = y2;
return true; return true;
} }
@ -280,10 +316,10 @@ public class MapEventLayer extends Layer implements Map.InputListener {
private void updateMulti(MotionEvent e) { private void updateMulti(MotionEvent e) {
int cnt = e.getPointerCount(); int cnt = e.getPointerCount();
if (cnt == 2) {
mPrevX = e.getX(0); mPrevX = e.getX(0);
mPrevY = e.getY(0); mPrevY = e.getY(0);
if (cnt == 2) {
mPrevX2 = e.getX(1); mPrevX2 = e.getX(1);
mPrevY2 = e.getY(1); mPrevY2 = e.getY(1);
double dx = mPrevX - mPrevX2; double dx = mPrevX - mPrevX2;
@ -295,9 +331,7 @@ public class MapEventLayer extends Layer implements Map.InputListener {
} }
} }
private boolean onFling(float velocityX, float velocityY) { private boolean doFling(float velocityX, float velocityY) {
if (mWasMulti)
return true;
int w = Tile.SIZE * 3; int w = Tile.SIZE * 3;
int h = Tile.SIZE * 3; int h = Tile.SIZE * 3;
@ -308,43 +342,17 @@ public class MapEventLayer extends Layer implements Map.InputListener {
return true; return true;
} }
//@Override @Override
//public boolean onDoubleTap(MotionEvent e) { public boolean onGesture(Gesture g, MotionEvent e) {
// if (g instanceof Gesture.DoubleTap) {
// mDoubleTap = true; //mMapPosition.animateZoom(2);
// //mMapPosition.animateZoom(2); // avoid onLongPress
//
// if (debug)
// printState("onDoubleTap");
//
// // avoid onLongPress
// mMap.getLayers().cancelGesture(); // mMap.getLayers().cancelGesture();
// mDoubleTap = true;
// return true; return true;
//} }
// return false;
//@Override }
//public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
// final float distanceY) {
//
// if (e2.getPointerCount() == 1) {
// mMapPosition.moveMap(-distanceX, -distanceY);
// mMap.updateMap(true);
// return true;
// }
//
// return false;
//}
//
//
//private void printState(String action) {
// log.debug(action
// + " " + mDoubleTap
// + " " + mBeginScale
// + " " + mBeginRotate
// + " " + mBeginTilt);
//}
/******************************************************************************* /*******************************************************************************
* Copyright 2011 See libgdx AUTHORS file. * Copyright 2011 See libgdx AUTHORS file.

View File

@ -274,4 +274,8 @@ public class MapAnimator {
mViewport.scaleMap((float) (newScale / mPos.scale), mViewport.scaleMap((float) (newScale / mPos.scale),
(float) mPivot.x, (float) mPivot.y); (float) mPivot.x, (float) mPivot.y);
} }
public synchronized void cancel() {
mState = ANIM_NONE;
}
} }