2009-08-19 4 views
1

나는 할 수있는 제스처 입력이 많은 iPhone 앱을 만들고 있습니다. 현재는 단일 손가락 선택/끌기, 두 손가락 스크롤 및 두 손가락 집기 확대/축소가 있습니다. 두 손가락 회전을 추가하고 싶습니다. (손가락이 그들 사이에 포인트를 회전 시키지만) 제대로 작동하도록하는 방법을 알 수는 없습니다. 다른 모든 제스처는 선형 이었기 때문에 점이나 십자가를 사용하는 문제였습니다.아이폰에서 두 손가락 회전 동작?

각 손가락의 이전 두 점 사이에 기울기를 저장해야한다고 생각합니다. 벡터 사이의 각도가 90 근처에 있으면 회전 할 가능성이 있습니다. 다음 손가락 동작 각도가 90 근처에 있고 한 손가락의 벡터 방향이 긍정적으로 바뀌고 부정적으로 바뀌면 회전이 발생합니다. 문제는,이 제스처와 다른 것들 사이의 명확한 구별이 필요하다는 것입니다. 위의 내용은 충분히 제거되지 않았습니다.

제안 사항?

EDIT : 다음은 벡터 분석 방식으로 수행 한 방법입니다 (픽셀 일치에 대한 아래의 제안과는 달리 여기에서 벡터 구조체를 사용하므로 각 기능이 무엇인지 추측 할 수 있음).

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

이미지 조작이나 직접 회전/확대/축소를 수행하는 경우 위의 방법을 사용하는 것이 좋습니다. 그러나 나와 같은 사람이라면 제스처를 사용하여로드하는 데 시간이 걸리는 작업을 유발할 수 있습니다. 그러면 제스처가 몇 번 활성화 될 때까지 작업을하지 않으려 고 할 수 있습니다. 각 코드와의 차이점은 여전히 ​​완벽하게 구분되어 있지 않으므로 가끔은 여러 번 확대해서 볼 수 있습니다.

답변

2

두 손가락 사이의 이전 거리와 현재 거리, 이전 거리와 현재 거리 사이의 각도를 구 했었습니다. 그런 다음 델타와 각도 세타에 대한 몇 가지 경험적 한계점을 골랐고, 그것은 나를 위해 잘 해결되었습니다.

거리가 내 임계 값보다 크고 각도가 내 임계 값보다 작은 경우 이미지 크기를 조정했습니다. 그렇지 않으면 나는 그것을 회전시켰다. 두 손가락 스크롤이 구별하기 쉽습니다.

BTW 실제로 값을 저장하는 경우 터치는 이전에 저장된 포인트 값을 저장합니다.

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]]; 
+0

아, 거리는 누락 된 링크입니다. 나는 그것에 대해 생각하지 않았다는 것을 믿을 수 없다. 저는 벡터의 각도와 방향에만 초점을 맞추고 있었지만, 실제로는 거리가 가장 큰 차이라고 생각합니다. 그리고 나는 이전의 터치 (확대를 위해 사용됨)에 대해 이미 알고 있었지만 그것을 지적 해 주셔서 감사합니다. – Eli

2

두 손가락, 움직이는 방향, 반대 방향 (ish) 방향. 어떤 몸짓이 이것과 충돌 하는가?

꼬집음/확대/축소 핀치/줌이 중심점에서 벗어나기 시작하는 반면 (각 선에서 뒤로 추적하면 선이 평행하고 가까운 경우), 회전은 처음에는 평행선을 갖게됩니다 (거꾸로 따라 가면서) 멀리 떨어져있을 것이고, 그 선들은 지속적으로 기울기를 바꿀 것입니다 (거리를 유지하면서).

편집 : 알고 계실 겁니다. 둘 다 같은 알고리즘으로 해결할 수 있습니다.

줄을 계산하는 대신 각 손가락 아래에 픽셀을 계산하십시오. 손가락이 움직이면 두 개의 초기 픽셀이 두 손가락 아래에 있도록 이미지를 이동합니다.

스크롤을 포함한 두 손가락 동작을 모두 해결합니다.

두 손가락 스크롤 또는 확대/축소가 다른 작업도 수행하기 때문에 조금 흔들릴 수 있지만지도 앱이 작동하는 것처럼 보입니다 (회전하지 않은 것 제외).

+0

픽셀 아이디어가 마음에 드네요. 이미지 조작으로 잘 작동합니다. 저는 게임을하고 있습니다. 회전 동작은 레벨을 다른 관점으로 회전시킵니다. 일부 리소스 로딩 등이 필요하기 때문에 직접 구별이 될 수 없습니다. 이미지 케이스의 좋은 아이디어에 +1. – Eli

관련 문제