문제

나는 당신이 할 수있는 다양한 제스처 입력을 가진 iPhone 앱에서 작업하고 있습니다. 현재 단일 손가락 선택 / 드래그, 두 개의 손가락 스크롤 및 두 개의 손가락 핀치 확대 / 축소 / 축소가 있습니다. 나는 두 개의 손가락 회전을 추가하고 싶지만 (손가락이 그들 사이에서 지점을 회전시킨다), 나는 그것을 올바르게 작동시키는 방법을 알 수 없다. 다른 모든 제스처는 선형 이었으므로 도트 또는 크로스 제품을 사용하는 문제 일뿐입니다.

나는 각 손가락의 이전 두 지점 사이에 경사를 저장해야한다고 생각하며, 벡터 사이의 각도가 90에 가깝면 회전 가능성이 있습니다. 다음 손가락 이동 각도가 90에 가깝고 한 손가락의 벡터 방향이 긍정적으로 변하고 부정적인 변화가 있으면 회전이 발생하면 회전이 발생합니다. 문제는이 제스처와 다른 제스처를 정말 깨끗하게 구별해야한다는 것입니다. 위의 내용은 충분히 제거되지 않습니다.

제안이 있습니까?

편집 : 벡터 분석 방식으로 수행 한 방법은 다음과 같습니다 (픽셀 일치하는 것과 반대로 여기에서 내 벡터 구조를 사용하는 것에 대한 제안과는 달리 각 기능이 무엇을하는지 추측 할 수 있어야합니다).

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

이미지 조작 또는 직접 회전 / 확대 / 축소를하는 경우 위의 접근 방식이 적합해야합니다. 그러나 당신이 나와 같고 제스처를 사용하여로드하는 데 시간이 걸리는 무언가를 일으키는 경우, 그 제스처가 몇 번 연속으로 활성화 될 때까지 행동을 피하고 싶을 것입니다. 내 코드와의 각각의 차이는 여전히 완벽하게 분리되어 있지 않으므로 때로는 많은 줌에서 회전 또는 Vise Versa를 얻을 수 있습니다.

도움이 되었습니까?

해결책

나는 두 손가락 사이의 이전 및 현재 거리를 찾아서 이전 선과 현재 라인 사이의 각도를 찾아서 그렇게했습니다. 그런 다음 그 거리 델타와 각도 세타에 대한 경험적 임계 값을 선택했는데, 그것은 나에게 잘 작동했습니다.

거리가 내 임계 값보다 크고 각도가 임계 값보다 작 으면 이미지를 축소했습니다. 그렇지 않으면 회전했습니다. 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]];

다른 팁

두 손가락, 모두 움직이고 반대 (ISH) 방향. 이것과 어떤 제스처가 충돌합니까?

핀치/줌이 가까워 지지만 핀치/줌은 중심점에서 멀어지기 시작하지만 (각 라인에서 뒤로 추적하면 라인이 평행하고 닫히면), 회전은 처음에는 평행 선이 있습니다 (뒤로 트레이드). 그것은 서로 멀리 떨어져있을 것이며 그 선은 끊임없이 경사를 바꿀 것입니다 (유지하는 동안).

편집 : 당신은 알고 있습니다. 이들 중에는 동일한 알고리즘으로 해결 될 수 있습니다.

선을 계산하는 대신 각 손가락 아래 픽셀을 계산하십시오. 손가락이 움직이면 두 개의 초기 픽셀이 여전히 두 손가락 아래에 있도록 이미지를 번역하십시오.

이것은 두루마리를 포함한 두 손가락 동작을 해결합니다.

두 손가락 스크롤 또는 줌은 다른 작업을 수행하기 때문에 때때로 약간 흔들리게 보일 수 있지만, 이것이 맵 앱이 작동하는 방식 (회전이없는 회전 제외)입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top