Sublass de UIGestureRecognizer, limiter les mouvement

MAGEMAGE Membre
J'ai suivi l'épisode 121 WWDC 2010 (Advanced Gesture Recognition) qui montre comment faire une subclass de UIGestureRecognizer.

J'ai deux petit soucis, que je vais séparer en deux fils différents, soucis n° 2:

J'aimerai pouvoir faire une rotation, une translation, mais pas d'homothétie et ainsi garder toujours la même taille de l'objet.
je suppose que je dois modifier quelque chose dans les x / y / z ou  a / b / tx / ty, mais malgré quelques tentatives, je ne modifie jamais les bons paramètres.
J'ai aussi regardé la doc (CGAffineTransform, mais je dois dire que c'est un peu du chinois ces matrices..

Merci pour vos pistes

Réponses

  • CéroceCéroce Membre, Modérateur
    mars 2011 modifié #2
    Ne cherche pas à  calculer les coefficients, utilise CGAffineTransform, c'est bien plus simple.

    Il y a deux choses à  savoir:
    - la multiplication de matrices n'est pas commutative: A x B n'est pas égal à  B x A. Ceci implique que l'ordre dans lequel on modifie la matrice de transformation importe.
    - les transformations des coordonnées se font par rapport à  l'origine du repère.

    Comme, par défaut, le repère a son origine dans le coin supérieur gauche, il faut:
    - initialiser la matrice de transformation avec la matrice identité
    - lui appliquer la translation
    - lui appliquer la rotation
    - lui appliquer la translation inverse
    - multiplier les coordonnées par cette matrice.

    Le centre de la rotation étant le point à  mi chemin entre les deux doigts, il faudra utiliser ses coordonnées pour la translation.
  • MAGEMAGE Membre
    05:30 modifié #3
    C'est bien ce que fini par faire le code proposé :
    return CGAffineTransformMake(a/D, -b/D, b/D, a/D, tx/D, ty/D);
    

    J'aimerai tout ça, mais sans le scale

    ps : je posterai bien le code, mais je ne suis pas certain d'en avoir le droit. Les WWDC sont maintenant disponibles pour tous, mais ne faut-il pas être dev tout de même pour y avoir accès ?
  • CéroceCéroce Membre, Modérateur
    05:30 modifié #4
    Le facteur 1/D représente l'échelle. Il suffit de le retirer.
  • MAGEMAGE Membre
    05:30 modifié #5
    Non, c'est pas ça  :(

    Avec le code, ça t'aide, Céroce ?

    - (CGAffineTransform)incrementalTransformWithTouches:(NSSet *)touches<br />{<br />	NSArray *sortedTouches = [[touches allObjects] sortedArrayUsingSelector:@selector(compareAddress:)];<br />	NSInteger numTouches = [sortedTouches count];<br />	<br />	// No touches<br />	if (numTouches == 0) {<br />		return CGAffineTransformIdentity;<br />	}<br />	<br />	// Single touch<br />	if (numTouches == 1) {<br />		<br />		UITouch *touch = [sortedTouches objectAtIndex:0];<br />		CGPoint beginPoint = *(CGPoint *)CFDictionaryGetValue(touchBeginPoints, touch);<br />		CGPoint currentPoint = [touch locationInView:self.view.superview];<br />		return CGAffineTransformMakeTranslation(currentPoint.x - beginPoint.x, currentPoint.y - beginPoint.y);<br />&nbsp; &nbsp; }<br />	<br />	// if two or more touches, go with the first two (sorted by adress)<br />	UITouch *touch1 = [sortedTouches objectAtIndex:0];<br />	UITouch *touch2 = [sortedTouches objectAtIndex:1];<br />	<br />	CGPoint beginPoint1 = *(CGPoint *)CFDictionaryGetValue(touchBeginPoints, touch1);<br />	CGPoint currentPoint1 = [touch1 locationInView:self.view.superview];<br />	CGPoint beginPoint2 = *(CGPoint *)CFDictionaryGetValue(touchBeginPoints, touch2);<br />	CGPoint currentPoint2 = [touch2 locationInView:self.view.superview];<br />	<br />	double layerX = self.view.center.x;<br />	double layerY = self.view.center.y;<br />	<br />	double x1 = beginPoint1.x - layerX;<br />&nbsp; &nbsp; double y1 = beginPoint1.y - layerY;<br />	double x2 = beginPoint2.x - layerX;<br />	double y2 = beginPoint2.y - layerY;<br />	double x3 = currentPoint1.x - layerX;<br />	double y3 = currentPoint1.y - layerY;<br />	double x4 = currentPoint2.x - layerX;<br />&nbsp; &nbsp; double y4 = currentPoint2.y - layerY;<br /><br />	<br />	double D = (y1-y2)*(y1-y2) + (x1-x2)*(x1-x2);<br />	if (D &lt; 0.1) {<br />&nbsp; &nbsp; &nbsp; &nbsp; return CGAffineTransformMakeTranslation(x3-x1, y3-y1);<br />&nbsp; &nbsp; }<br />	<br />	double a = (y1-y2)*(y3-y4) + (x1-x2)*(x3-x4);<br />	double b = (y1-y2)*(x3-x4) - (x1-x2)*(y3-y4);<br />	double tx = (y1*x2 - x1*y2)*(y4-y3) - (x1*x2 + y1*y2)*(x3+x4) + x3*(y2*y2 + x2*x2) + x4*(y1*y1 + x1*x1);<br />	double ty = (x1*x2 + y1*y2)*(-y4-y3) + (y1*x2 - x1*y2)*(x3-x4) + y3*(y2*y2 + x2*x2) + y4*(y1*y1 + x1*x1);<br />	<br />&nbsp; &nbsp; return CGAffineTransformMake(a/D, -b/D, b/D, a/D, tx/D, ty/D);<br />}
    
  • CéroceCéroce Membre, Modérateur
    05:30 modifié #6
    Non, désolé mais je n'ai pas le temps. Voici quelques pistes.

    Calcul de l'échelle
    Utilise le théorème de Pythagore pour déterminer la distance entre beginPoint1 et beginPoint2.
    De même pour la ditance entre currentPoint1 et currentPoint2.
    Echelle = distanceAprès/distanceAvant


    Calcul de la rotation

    Utilise les fonctions trigonométriques (par exemple, acos() et signe du sinus) pour déterminer l'angle entre beginPoint1 et beginPoint2.
    De même entre currentPoint1 et currentPoint2.
    La différence d'angle te donne la rotation à  appliquer.

    Calcul de la translation

    Il faut faire en sorte que le point médian entre beginPoint1 et beginPoint2 arrive au point médian entre currentPoint1 et currentPoint2.
    À mon avis, le plus simple est de préparer une matrice avec les deux transformations précédentes et l'appliquer au point médian.
    Le décalage de coordonnées donne la translation à  appliquer.

    Bon, je ne garantis pas à  100%, mais voilà  l'esprit. Je te conseille de faire fonctionner les trois transformations indépendamment avant de les combiner.
  • MAGEMAGE Membre
    05:30 modifié #7
    Merci pour tes pistes, mais j'aurai bien aimé comprendre ces matrices.

    (Sinon, j'essayerai de combiner rotation + translation ; et ça je dois savoir faire)
  • MAGEMAGE Membre
    05:30 modifié #8
    Bon, j'ai fini par tout refaire simplement avec UIGestureRecognizer sans forcément sublasser. ça fonctionne la même chose en plus.

    J'aimerai avoir une information sur le déplacement de mon objet, mais le soucis c'est que touchesMoved n'est plus appelé.
    Je suppose que que c'est un problème de delegate.

    Donc comment faire pour que lorsque je déplace ma UIView, je puisse détecter aussi sa position, même avec des UIGestureRecognizer ?
  • MAGEMAGE Membre
    05:30 modifié #9
    Arf ! Merci de ne pas n'avoir tapé sur les doigts  B)
    Vu que j'avais implémanté panGesture, c'est là  et pas dans le touchmoved qu'il fallait que je passe..
  • AliGatorAliGator Membre, Modérateur
    05:30 modifié #10
    dans 1301339053:

    Arf ! Merci de ne pas n'avoir tapé sur les doigts  B)
    Il est encore temps dis dis ?  :D
  • MAGEMAGE Membre
    05:30 modifié #11
    Il te faudra attendre la prochaine fois... que je balance une question dont la réponse est 5 lignes plus bas dans mon code mais que personne ne peut deviner  :P
Connectez-vous ou Inscrivez-vous pour répondre.