iPhone上的双指旋转手势? [英] Two-finger rotation gesture on the iPhone?

查看:163
本文介绍了iPhone上的双指旋转手势?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一款iPhone应用,你可以做很多不同的手势输入。目前有单指选择/拖动,两个手指滚动和两个手指捏缩放/缩小。我想添加两个手指旋转(你的手指在它们之间旋转一个点),但我无法弄清楚如何让它正常工作。所有其他手势都是线性的,所以它们只是使用点或交叉产品的问题。

I'm working on an iPhone app with a lot of different gesture inputs that you can do. Currently there is single finger select / drag, two finger scroll, and two finger pinch zoom-in / zoom-out. I want to add in two finger rotation (your fingers rotate a point in between them), but I can't figure out how to get it to work right. All the other gestures were linear so they were only a matter of using the dot or cross product, pretty much.

我在想我必须存储斜率在每个手指的前两个点之间,并且如果矢量之间的角度接近90°,则存在旋转的可能性。如果下一个手指移动角度也接近90°,并且一个手指上的矢量方向发生了正变化并且发生了负面变化,那么你就有了一个旋转。问题是,我需要在这个手势和其他手势之间做一个非常清晰的区分 - 而且上面的内容还不够远。

I'm thinking I've got to store the slope between the previous two points of each finger, and if the angle between the vectors is near 90, then there is the possibility of a rotation. If the next finger movement angle is also near 90, and the direction of the vector on one finger changed positively and changed negatively, then you've got a rotation. The problem is, I need a really clean distinction between this gesture and the other ones - and the above isn't far enough removed.

有什么建议吗?

编辑:这是我用矢量分析方式做的事情(与下面关于匹配像素的建议相反,请注意我在这里使用我的Vector结构,你应该能够猜到每个函数的作用):

Here's how I did it in a vector analysis manner (as opposed to the suggestion below about matching pixels, note that I use my Vector struct in here, you should be able to guess what each function does):

//First, find the vector formed by the first touch's previous and current positions.
struct Vector2f firstChange = getSubtractedVector([theseTouches get:0], [lastTouches get:0]);
//We're going to store whether or not we should scroll.
BOOL scroll = NO;

//If there was only one touch, then we'll scroll no matter what.
if ([theseTouches count] <= 1)
{
    scroll = YES;
}
//Otherwise, we might scroll, scale, or rotate.
else
{
    //In the case of multiple touches, we need to test the slope between the two touches.
    //If they're going in roughly the same direction, we should scroll. If not, zoom.
    struct Vector2f secondChange = getSubtractedVector([theseTouches get:1], [lastTouches get:1]);

    //Get the dot product of the two change vectors.
    float dotChanges = getDotProduct(&firstChange, &secondChange);

    //Get the 2D cross product of the two normalized change vectors.
    struct Vector2f normalFirst = getNormalizedVector(&firstChange);
    struct Vector2f normalSecond = getNormalizedVector(&secondChange);
    float crossChanges = getCrossProduct(&normalFirst, &normalSecond);

    //If the two vectors have a cross product that is less than cosf(30), then we know the angle between them is 30 degrees or less.
    if (fabsf(crossChanges) <= SCROLL_MAX_CROSS && dotChanges > 0)
    {
        scroll = YES;
    }
    //Otherwise, they're in different directions so we should zoom or rotate.
    else
    {
        //Store the vectors represented by the two sets of touches.
        struct Vector2f previousDifference = getSubtractedVector([lastTouches  get:1], [lastTouches  get:0]);
        struct Vector2f currentDifference  = getSubtractedVector([theseTouches get:1], [theseTouches get:0]);

        //Also find the normals of the two vectors.
        struct Vector2f previousNormal = getNormalizedVector(&previousDifference);
        struct Vector2f currentNormal  = getNormalizedVector(&currentDifference );

        //Find the distance between the two previous points and the two current points.
        float previousDistance = getMagnitudeOfVector(&previousDifference);
        float currentDistance  = getMagnitudeOfVector(&currentDifference );

        //Find the angles between the two previous points and the two current points.
        float angleBetween = atan2(previousNormal.y,previousNormal.x) - atan2(currentNormal.y,currentNormal.x);

        //If we had a short change in distance and the angle between touches is a big one, rotate.
        if ( fabsf(previousDistance - currentDistance) <= ROTATE_MIN_DISTANCE && fabsf(angleBetween) >= ROTATE_MAX_ANGLE)
        {
            if (angleBetween > 0)
            {
                printf("Rotate right.\n");
            }
            else
            {
                printf("Rotate left.\n");
            }
        }
        else
        {
            //Get the dot product of the differences of the two points and the two vectors.
            struct Vector2f differenceChange = getSubtracted(&secondChange, &firstChange);
            float dotDifference = getDot(&previousDifference, &differenceChange);
            if (dotDifference > 0)
            {
                printf("Zoom in.\n");
            }
            else
            {
                printf("Zoom out.\n");
            }
        }
    }
}

if (scroll)
{
    prinf("Scroll.\n");
}

你应该注意,如果你只是做图像处理或直接旋转/缩放,那么上面的方法应该没问题。但是,如果你像我一样并且你正在使用手势来导致需要花费时间来加载的东西,那么在你连续几次激活该手势之前,你很可能会想要避免这样做。每个与我的代码之间的差异仍然不完全分开,所以偶尔在一堆缩放中你会得到一个旋转,反之亦然。

You should note that if you're just doing image manipulation or direct rotation / zooming, then the above approach should be fine. However, if you're like me and you're using a gesture to cause something that takes time to load, then it's likely that you'll want to avoid doing the action until that gesture has been activated a few times in a row. The difference between each with my code is still not perfectly separate, so occasionally in a bunch of zooms you'll get a rotation, or vise versa.

推荐答案

我之前通过找到两个手指之间的前一个和当前距离以及前一个线和当前线之间的角度来做到这一点。
然后我为那个距离增量和角度θ选择了一些经验阈值,这对我来说非常好。

I've done that before by finding the previous and current distances between the two fingers, and the angle between the previous and current lines. Then I picked some empirical thresholds for that distance delta and angle theta, and that has worked out pretty well for me.

如果距离大于我的距离阈值,角度小于我的阈值,我缩放图像。否则我旋转它。
2手指滚动似乎很容易区分。

If the distance was greater than my threshold, and the angle was less than my threshold, I scaled the image. Otherwise I rotated it. 2 finger scroll seems easy to distinguish.

如果您实际存储的是BTW,则触摸已经存储了之前的点值。

BTW in case you are actually storing the values, the touches have previous point values already stored.

CGPoint previousPoint1 = [self scalePoint:[touch1 previousLocationInView:nil]];
CGPoint previousPoint2 = [self scalePoint:[touch2 previousLocationInView:nil]];
CGPoint currentPoint1 = [self scalePoint:[touch1 locationInView:nil]];
CGPoint currentPoint2 = [self scalePoint:[touch2 locationInView:nil]];

这篇关于iPhone上的双指旋转手势?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆