Pergunta

Eu estou trabalhando em um aplicativo para iPhone com um monte de diferentes entradas gesto que você pode fazer. Actualmente, existe um único dedo selecionar / arrasto, dois dedos de rolagem e zoom-in dois dedos pitada / zoom-out. Quero acrescentar em dois rotação dedo (os dedos girar um ponto entre eles), mas eu não consigo descobrir como obtê-lo para a direita trabalho. Todos os outros gestos foram lineares para que eles eram apenas uma questão de usar o ponto ou produto cruzado, muito bonito.

Eu estou pensando que eu tenho que armazenar o declive entre os dois últimos pontos de cada dedo, e se o ângulo entre os vetores está perto de 90, em seguida, há a possibilidade de uma rotação. Se o próximo ângulo de movimento do dedo também está perto de 90, ea direção do vetor em um dedo mudou positivamente e mudou de forma negativa, então você tem uma rotação. O problema é que eu preciso de uma distinção muito clara entre esse gesto e os outros -. E o acima não está distante o suficiente

Todas as sugestões?

EDIT: Aqui está como eu fiz isso de uma maneira análise vetorial (ao contrário da sugestão abaixo sobre pixels correspondentes, nota que eu uso o meu struct Vector aqui, você deve ser capaz de adivinhar o que cada função faz):

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

Você deve ter notado que, se você está apenas fazendo manipulação de imagem ou rotação direta / zoom, em seguida, a abordagem acima deve ser fino. No entanto, se você é como eu e você estiver usando um gesto para causa algo que leva tempo para carregar, então é provável que você vai querer evitar fazer a ação até que esse gesto foi activada algumas vezes em uma fileira. A diferença entre cada um com meu código ainda não está perfeitamente separado, portanto, ocasionalmente, em um monte de zooms você vai ter uma rotação, ou vice-versa.

Foi útil?

Solução

Eu tenho feito isso antes, encontrando as distâncias anteriores e atuais entre os dois dedos, e o ângulo entre as linhas anteriores e atuais. Então eu peguei alguns limites empíricos para que delta distância eo ângulo theta, e que tem funcionado muito bem para mim.

Se a distância era maior do que o meu limite, e o ângulo era menor do que o meu limite, eu dimensionado a imagem. Caso contrário, eu girado ele. 2 dedos de rolagem parece fácil distinguir.

BTW, caso você esteja realmente armazenar os valores, os toques têm valores dos pontos anteriores já armazenados.

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

Outras dicas

Dois dedos, ambos em movimento, opposit (ish) direções. O gesto conflitos com isso?

Aperte / zoom Acho que chega perto, mas que pitada / zoom vai começar a passar de um ponto central (se você traçar para trás de cada linha, as linhas serão paralelo e próximo), rotação terá inicialmente linhas paralelas ( rastreamento para trás) que será muito longe um do outro e essas linhas vai mudar constantemente inclinação (mantendo distância).

edit:. Você sabe - ambos os quais poderiam ser resolvidos com o mesmo algoritmo

Ao invés de calcular linhas, calcular o pixel em cada dedo. Se os dedos se movem, traduzir a imagem para que os dois pixels iniciais ainda estão sob os dois dedos.

Isto resolve todas as ações de dois dedos, incluindo rolagem.

com dois dedos de rolagem ou zoom pode parecer um pouco instável, por vezes, uma vez que irá fazer outras operações, bem como, mas isso é como o mapa aplicativo parece funcionar (excluindo a rotação que ele não tem).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top