我正在研究一个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