我正在研究一個iPhone應用程序,其中包含許多可以做的不同手勢輸入。目前有單指選擇/拖動,雙指滾動和兩指捏放大/縮小。我想添加兩個手指旋轉(你的手指在它們之間旋轉一個點),但我無法弄清楚如何讓它正常工作。所有其他手勢都是線性的,因此它們只是使用點或交叉產品的問題,非常多。iPhone上的雙指旋轉手勢?
我在想我必須在每個手指的前兩個點之間存儲斜率,並且如果矢量之間的角度接近90°,那麼存在旋轉的可能性。如果下一個手指移動角度也接近90°,並且一個手指上的矢量方向改變爲正向並且負向改變,那麼您將進行旋轉。問題是,我需要在這個手勢和其他手勢之間有一個非常乾淨的區別 - 上面的內容還不夠深入。
有什麼建議嗎?編輯:這是我做矢量分析的方式(與下面關於匹配像素的建議相反,請注意我在這裏使用我的Vector結構,你應該能夠猜到每個函數的作用):
//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");
}
你應該注意到,如果你只是在做圖像處理或直接旋轉/縮放,那麼上述方法應該沒問題。但是,如果您像我一樣,並且您正在使用手勢來導致需要花費時間加載的內容,那麼您可能會希望避免執行此操作,直到連續激活了該手勢幾次。每個代碼與我的代碼之間的區別仍然不是完全獨立的,所以偶爾會在一堆縮放中獲得旋轉,反之亦然。
啊,距離是缺失的環節。我不敢相信我沒有想到這一點。我只專注於矢量的角度和方向,但距離真的是我認爲最大的區別。我已經知道以前的觸摸(用於縮放),但感謝您指出。 – Eli 2009-08-20 15:07:23