Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get degrees of rotation from a two-finger multi-touch event?

I have an ImageView that you can use to do a one-finger pan, or a two finger scale. It works fine. I've extended it to handle rotation, and its behaviour is causing some confusion.

When there's a multi-touch event this method gets called, which should return an angle of rotation in degrees. It is not doing what I expect.

private int fingersAngle(MotionEvent event)
{
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    int degrees = (int)(Math.toDegrees(Math.atan2(y, x)));
    return degrees;
}

As I rotate the two fingers I'd expect outputs like...

158 166 168 169 174 176 179 181 etc

But what I actually get is more like this:

158 166 -179 179 -179 179 -179

The problem seems to be with signs. How does this method know whether it's 180 or -180, or 90 or -270? The image often rotates the wrong way, and then suddenly jumps and starts rotating the opposite way. Even worse, the direction it initially rotates is effectively random.

I'm testing the app using a Nexus One, but also see the same problem on an Advent Vega tablet. Both devices work ok with Google Maps in 3D to rotate the screen (if a bit jumpy sometimes) so the evidence doesn't suggest a hardware limitation.

A secondary problem is that when the two fingers are approximately vertically or horizontally aligned the angle simply doesn't change, so the rotation "sticks" for about 10-20 degrees top/bottom/left/right.

Currently I'm doing a check to see if the angle has suddenly changed a huge amount, and if so, to subtract it from 360. Ugly as hell, but it helps a little.

Hopefully one of you has seen this before and knows how to extract the angular rotation from a multi-touch gesture.

Some things in Android are so easy it's amazing, but stuff like this is seriously painful.

like image 425
Ollie C Avatar asked Jun 15 '11 18:06

Ollie C


2 Answers

To make this work like users expect, you must keep some state.

An arc-tangent will only tell you the angle between two points—an instantaneous snapshot of the system. But you are performing an animation—something that happens over time.

So, I think that you are on the right track with your "ugly" solution that tries to detect large changes in the angle. What you really should be tracking over time is the position of each finger.

Suppose a user is using their thumb and index finger to gesture. You need to make sure that their digits are consistently represented, e.g. the thumb is always represented by (x0, y0), and the index finger by (x1, y1).

It's likely that the device has some rule how each coordinate is reported. For example, maybe it will always report the upper-left coordinate in the "0" slot of the event, and the lower-right coordinate in the "1" slot. But if the user moves their thumb from lower-right to upper-left, you must make sure that you are still treating it as (x1, y1) in your angle formula, even though the device is now reporting it as (x0, y0) in the event. Otherwise, the image will appear to quickly flip 180°, back and forth.

If the device doesn't track fingers for you, you'll have to come up with a heuristic for guessing. A simple, "which of the previous coordinates is closer to the current coordinate" would be a good place to start, but I could see the need for something fancier if the resolution of events is poor.

like image 177
erickson Avatar answered Oct 15 '22 16:10

erickson


I've never met this problem but my guess is that the use of atan2 forces your angles from -180 to +180.

But the rotation you want to apply to your image should be from 0 to 360.

Easiest solution would probably be to add 180 to your degrees variable before returning it.

EDIT : Since you added in the comments that there is randomness involved, I think that depending on the device you are working with you could be encountering the infamous HTC(and others early) multitouch bug : http://www.youtube.com/watch?v=Ds5qZ_3XRzI This shows it for the nexus one but the hero and some motorola had the same problems.

like image 44
Yahel Avatar answered Oct 15 '22 16:10

Yahel