2

私はあなたができる多くの異なるジェスチャー入力を備えたiPhoneアプリに取り組んでいます。現在、1本の指での選択/ドラッグ、2本の指でのスクロール、2本の指でのピンチズームイン/ズームアウトがあります。2本の指の回転(指がその間のポイントを回転させる)を追加したいのですが、正しく機能させる方法がわかりません。他のすべてのジェスチャは線形であったため、ほとんどドットまたはクロス積を使用するだけでした。

各指の前の2点間の傾きを保存する必要があると考えています。ベクトル間の角度が90に近い場合、回転する可能性があります。次の指の移動角度も90に近く、1本の指のベクトルの方向が正に変化し、負に変化した場合は、回転があります。問題は、このジェスチャと他のジェスチャを明確に区別する必要があることです。上記のジェスチャは十分に削除されていません。

助言がありますか?

編集:これが私がベクトル分析の方法でそれを行った方法です(ピクセルのマッチングに関する以下の提案とは対照的に、ここではベクトル構造体を使用していることに注意してください、各関数が何をするかを推測できるはずです):

//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");
}

画像操作または直接回転/ズームを行うだけの場合は、上記のアプローチで問題ないことに注意してください。ただし、あなたが私のようで、ジェスチャーを使用して読み込みに時間がかかるものを引き起こしている場合は、そのジェスチャーが連続して数回アクティブ化されるまで、アクションの実行を避けたいと思う可能性があります。それぞれのコードと私のコードの違いはまだ完全に分離されていないため、ズームの束で回転が発生したり、その逆が発生したりすることがあります。

4

2 に答える 2

3

私は以前、2本の指の間の以前の距離と現在の距離、および以前の線と現在の線の間の角度を見つけることによってそれを行いました。次に、その距離デルタと角度シータの経験的なしきい値をいくつか選択しました。これは、私にとってはかなりうまくいきました。

距離がしきい値よりも大きく、角度がしきい値よりも小さかった場合は、画像を拡大縮小しました。そうでなければ私はそれを回転させました。2本指のスクロールは見分けやすいようです。

ところで、実際に値を保存している場合、タッチには以前のポイント値がすでに保存されています。

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]];
于 2009-08-20T03:31:08.930 に答える
2

2本の指、両方とも移動し、反対方向。どのジェスチャーがこれと矛盾しますか?

ピンチ/ズームは近づくと思いますが、ピンチ/ズームは中心点から離れる方向に移動し始めますが(各線から後方にトレースすると、線は平行になり、閉じます)、回転には最初は平行線があります(後方にトレースします)。それは互いに遠く離れており、それらの線は(距離を保持しながら)常に勾配を変更します。

編集:ご存知のとおり、これらは両方とも同じアルゴリズムで解決できます。

線を計算するのではなく、各指の下のピクセルを計算します。指が動いた場合は、最初の2つのピクセルが2本の指の下にくるように画像を移動します。

これにより、スクロールを含むすべての2本指のアクションが解決されます。

2本指のスクロールまたはズームは、他の操作も実行するため、時々少しぐらつくように見える場合がありますが、これはマップアプリが機能しているように見えます(回転がない場合を除く)。

于 2009-08-19T23:44:17.480 に答える