私はあなたができる多くの異なるジェスチャー入力を備えた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(¤tDifference );
//Find the distance between the two previous points and the two current points.
float previousDistance = getMagnitudeOfVector(&previousDifference);
float currentDistance = getMagnitudeOfVector(¤tDifference );
//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");
}
画像操作または直接回転/ズームを行うだけの場合は、上記のアプローチで問題ないことに注意してください。ただし、あなたが私のようで、ジェスチャーを使用して読み込みに時間がかかるものを引き起こしている場合は、そのジェスチャーが連続して数回アクティブ化されるまで、アクションの実行を避けたいと思う可能性があります。それぞれのコードと私のコードの違いはまだ完全に分離されていないため、ズームの束で回転が発生したり、その逆が発生したりすることがあります。