Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate gesture distance in Android

Tags:

java

android

I'm trying to find a way to calculate the distance traveled during a Gesture. I can get the distance between two points using MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP or MotionEvent.ACTION_MOVE. But that doesn't account for moving in say, a circle. It would calculate 0 because you moved all the way back around. I'm looking for total distance traveled, preferably in pixels so I can manipulate it further, if needed.

like image 584
netwokz Avatar asked Sep 24 '12 05:09

netwokz


People also ask

How does Android calculate distance walked?

Using the motion sensor, time how long is the user "walking" (obviously, there's no easy way to determine if your user is actually walking or just shaking the phone). Multiply this with your user's pace factor and you get a pretty rough idea of how much walking has your user done.

What is touch gestures in Android?

A "touch gesture" occurs when a user places one or more fingers on the touch screen, and your application interprets that pattern of touches as a particular gesture. There are correspondingly two phases to gesture detection: Gather data about touch events.


2 Answers

You can use the historic stuff of the MotionEvent. Based on the example of the API Doc you could do something like so (for simplicity my example doesn't deal with multi-touch):

On ACTION_MOVE and ACTION_UP do this, where startX, startY would be the last known coordinates, e.g. from last ACTION_DOWN event.

float getDistance(float startX, float startY, MotionEvent ev) {
    float distanceSum = 0;
    final int historySize = ev.getHistorySize();
    for (int h = 0; h < historySize; h++) {
        // historical point
        float hx = ev.getHistoricalX(0, h);
        float hy = ev.getHistoricalY(0, h);
        // distance between startX,startY and historical point
        float dx = (hx - startX);
        float dy = (hy - startY);
        distanceSum += Math.sqrt(dx * dx + dy * dy);
        // make historical point the start point for next loop iteration
        startX = hx;
        startY = hy;
    }
    // add distance from last historical point to event's point
    float dx = (ev.getX(0) - startX);
    float dy = (ev.getY(0) - startY);
    distanceSum += Math.sqrt(dx * dx + dy * dy);
    return distanceSum;
}

example image

like image 132
Ridcully Avatar answered Oct 18 '22 09:10

Ridcully


A first order approximation would be to sum up the local length of every tiny piece of movement detected :

On ACTION_DOWN

total = 0;
xPrec = ev.getX();
yPrec = ev.getY();

On ACTION_MOVE

final float dx = ev.getX() - xPrec;
final float dy = ev.getY() - yPrec;
final float dl = sqrt(dx * dx + dy * dy);
total += dl;
xPrec = ev.getX();
yPrec = ev.getY();

On ACTION_UP you can do whatever you want with total which contains the total approximated length of your path.

If you read the official documentation about MotionEvent http://developer.android.com/reference/android/view/MotionEvent.html you will see a section entitled Batching which explains that one given motion event can batch together multiple movement samples. For the best first order approximation you need to consume all those samples using getHistorySize, getHistoricalX, getHistoricalY. Don't forget to process the most recent sample which stands in getX and getY.

If you need a better approximation I suggest you to read about the problem of curve fitting http://en.wikipedia.org/wiki/Curve_fitting, but as the frequency of touch events is quite fast you may not need to do so and get satisfied with a first order approximation.

like image 2
ovmjm Avatar answered Oct 18 '22 10:10

ovmjm