46 votes

Transformation affine en une étape pour la rotation autour d'un point ?

Comment puis-je réaliser une transformation affine Core Graphics pour une rotation autour d'un point x,y d'un angle a, en utilisant seulement un appel unique à CGAffineTransformMake() plus les fonctions trigonométriques math.h telles que sin(), cos(), etc. et aucun autre appel CG.

Les autres réponses semblent concerner l'utilisation de plusieurs transformations empilées ou de transformations en plusieurs étapes pour déplacer, faire pivoter et déplacer, en utilisant plusieurs appels Core Graphics. Ces réponses ne répondent pas à mes besoins spécifiques.

132voto

landweber Points 885

Une rotation d'angle a autour du point (x,y) correspond à la transformation affine :

CGAffineTransform transform = CGAffineTransformMake(cos(a),sin(a),-sin(a),cos(a),x-x*cos(a)+y*sin(a),y-x*sin(a)-y*cos(a));

Il se peut que vous deviez insérer -a au lieu de a, selon que vous souhaitez que la rotation se fasse dans le sens des aiguilles d'une montre ou dans le sens inverse. De même, vous devrez peut-être saisir -y au lieu de y selon que votre système de coordonnées est à l'envers ou non.

De plus, vous pouvez accomplir exactement la même chose en trois lignes de code en utilisant :

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, a);
transform = CGAffineTransformTranslate(transform,-x,-y);

Si vous l'appliquiez à une vue, vous pourriez aussi simplement utiliser une transformation de rotation via CGAffineTransformMakeRotation(a), à condition de définir la propriété anchorPoint du calque de la vue pour refléter le point autour duquel vous souhaitez effectuer la rotation. Cependant, il semble que vous ne soyez pas intéressé par l'application de cette méthode à une vue.

Enfin, si vous appliquez cette transformation à un espace 2D non euclidien, il se peut que vous ne souhaitiez pas du tout une transformation affine. Les transformations affines sont des isométries de l'espace euclidien, ce qui signifie qu'elles préservent la distance euclidienne standard, ainsi que les angles. Si votre espace n'est pas euclidien, alors la transformation que vous voulez peut ne pas être affine, ou si elle l'est, la matrice pour la rotation peut ne pas être aussi simple que ce que j'ai écrit ci-dessus avec sin et cos. Par exemple, si vous êtes dans un espace hyperbolique, vous devrez peut-être utiliser les fonctions trigonométriques hyperboliques sinh et cosh, ainsi que des signes + et - différents dans la formule.

P.S. Je voulais aussi rappeler à tous ceux qui ont lu jusqu'ici que "affine" se prononce avec un "a" court comme dans "ask", et non un "a" long comme dans "able". J'ai même entendu des employés d'Apple le prononcer de façon erronée lors de leurs interventions à la WWDC.

9voto

Ming Chu Points 430

Pour Swift 4

print(x, y) // where x,y is the point to rotate around
let degrees = 45.0
let transform = CGAffineTransform(translationX: x, y: y)
    .rotated(by: degrees * .pi / 180)
    .translatedBy(x: -x, y: -y)

4voto

valvoline Points 2358

Pour ceux qui, comme moi, se battent à la recherche d'une solution complète pour faire pivoter une image et la mettre à l'échelle correctement, afin de remplir le cadre qui la contient, après quelques heures, c'est la solution la plus complète et la plus parfaite que j'ai obtenue.

L'astuce consiste ici à translater le point de référence, avant toute transformation (échelle et rotation). Après cela, vous devez concaténer les deux transformations afin d'obtenir une transformation affine complète.

J'ai regroupé toute la solution dans une sous-classe de CIFilter que vous pouvez résumé ici .

En suivant la partie pertinente du code :

CGFloat a = _inputDegree.floatValue;
CGFloat x = _inputImage.extent.size.width/2.0;
CGFloat y = _inputImage.extent.size.height/2.0;

CGFloat scale = [self calculateScaleForAngle:GLKMathRadiansToDegrees(a)];

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, a);
transform = CGAffineTransformTranslate(transform,-x,-y);

CGAffineTransform transform2 = CGAffineTransformMakeTranslation(x, y);
transform2 = CGAffineTransformScale(transform2, scale, scale);
transform2 = CGAffineTransformTranslate(transform2,-x,-y);

CGAffineTransform concate   = CGAffineTransformConcat(transform2, transform);

2voto

Peter Schorn Points 509

Voici quelques méthodes pratiques pour effectuer une rotation autour d'un point d'ancrage :

extension CGAffineTransform {

    init(rotationAngle: CGFloat, anchor: CGPoint) {
        self.init(
            a: cos(rotationAngle),
            b: sin(rotationAngle),
            c: -sin(rotationAngle),
            d: cos(rotationAngle),
            tx: anchor.x - anchor.x * cos(rotationAngle) + anchor.y * sin(rotationAngle),
            ty: anchor.y - anchor.x * sin(rotationAngle) - anchor.y * cos(rotationAngle)
        )
    }

    func rotated(by angle: CGFloat, anchor: CGPoint) -> Self {
        let transform = Self(rotationAngle: angle, anchor: anchor)
        return self.concatenating(transform)
    }

}

0voto

Lemonsanver Points 903

Utilisez le calque et le point d'ancrage de la vue, par exemple.

view.layer.anchorPoint = CGPoint(x:0,y:1.0)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X