NSAffineTransform est une classe d'AppKit (macOS) qui représente une transformation affine en graphique bidimensionnel. Elle encapsule une matrice 3×3 qui décrit une combinaison de translation, d'échelle, de rotation et de cisaillement des coordonnées. Selon la Documentation Apple (2026), NSAffineTransform est largement utilisé dans Core Graphics pour transformer les chemins, les points et les contextes graphiques sur macOS.
Points clés
NSAffineTransform est une classe du framework AppKit, disponible uniquement sur macOS. Elle représente une transformation affine dans l'espace bidimensionnel via une matrice 3×3. Contrairement à CGAffineTransform de Core Graphics (disponible sur iOS), NSAffineTransform est un wrapper orienté objet autour de la structure CGAffineTransform, ajoutant des méthodes pratiques pour travailler avec NSBezierPath, NSPoint et NSSize.
Une transformation affine est une transformation du plan qui préserve la relation « le point est sur une ligne » et le parallélisme des lignes. En d'autres termes, après une transformation affine, les lignes parallèles restent parallèles et les lignes droites restent droites. Cependant, les distances, les angles et les surfaces peuvent changer : l'échelle, la rotation et le cisaillement sont des cas particuliers de transformations affines.
Sur iOS, l'équivalent de NSAffineTransform est la structure CGAffineTransform de Core Graphics. Les deux API sont basées sur le même modèle mathématique — une matrice de transformation affine 3×3 dont la dernière ligne est toujours [0, 0, 1]. La différence est que NSAffineTransform est une classe (avec retain/release en Objective-C), tandis que CGAffineTransform est une structure (type valeur) en Swift et C.
NSAffineTransform prend en charge quatre types de base de transformations : translate (translation), scale (échelle), rotate (rotation) et shear (cisaillement). Chaque type est représenté par une méthode distincte et peut être appliqué à un objet de transformation existant ou utilisé pour en créer un nouveau.
| Opération | Méthode NSAffineTransform | Paramètres | Effet visuel |
|---|---|---|---|
| Translate | translateXBy:yBy: | deltaX, deltaY | Déplace l'objet le long des axes X et Y |
| Scale | scaleBy: / scaleXBy:yBy: | factor / scaleX, scaleY | Agrandit ou réduit la taille |
| Rotate | rotateByDegrees: / rotateByRadians: | angle en degrés ou radians | Tourne autour de l'origine |
| Shear | Via setTransformStruct | composants m12, m21 de la matrice | Incline l'objet le long d'un axe |
Translate ajoute un décalage aux coordonnées de tous les points d'un objet. Les paramètres deltaX et deltaY définissent respectivement la quantité de décalage horizontal et vertical. Une valeur positive de deltaX décale vers la droite, deltaY vers le haut. Translate ne modifie ni la forme ni la taille de l'objet — seulement sa position.
Scale multiplie les coordonnées des points par un facteur donné. Avec une échelle uniforme (un seul paramètre), l'objet s'agrandit ou se réduit proportionnellement. Avec une échelle non uniforme, la forme est déformée. Un facteur de 1,0 laisse la taille inchangée, supérieur à 1,0 agrandit, de 0,0 à 1,0 réduit. Les valeurs négatives créent un reflet miroir.
Rotate fait tourner l'objet autour de l'origine d'un angle donné. Un angle de rotation positif correspond à une rotation antihoraire. rotateByDegrees accepte les degrés (0–360), rotateByRadians accepte les radians (0–2π). La rotation est toujours effectuée par rapport au point (0, 0). Pour tourner autour d'un point arbitraire, il faut combiner rotate avec translate.
La transformation affine dans NSAffineTransform est représentée par une matrice 3×3 dont la dernière ligne est toujours [0, 0, 1]. C'est la représentation mathématique standard qui permet de représenter une combinaison de transformations comme un produit de matrices. La structure de la matrice est définie via NSAffineTransformStruct, qui contient six composants significatifs : m11, m12, m21, m22, tX, tY.
Les composants m11, m12, m21, m22 sont responsables de l'échelle, de la rotation et du cisaillement. Les composants tX et tY sont responsables de la translation. Dans la configuration standard (matrice identité), m11 = 1, m22 = 1, et les autres sont à 0. Pour obtenir les valeurs actuelles de la matrice, on utilise transformStruct — la propriété de NSAffineTransform qui retourne une structure NSAffineTransformStruct.
La multiplication matricielle est une opération non commutative. Cela signifie que l'ordre d'application des transformations est important : translate + rotate donne un résultat différent de rotate + translate. Lors de la combinaison, NSAffineTransform multiplie la nouvelle matrice à gauche par la matrice actuelle : newMatrix = operation × currentMatrix. Par conséquent, la dernière transformation ajoutée est appliquée en premier.
NSAffineTransform permet de combiner plusieurs transformations en un seul objet. Chaque appel à translateXBy:yBy:, scaleBy: ou rotateByDegrees: modifie la matrice interne — multiplie la matrice actuelle par la matrice de la transformation correspondante. Cela permet de créer une transformation complexe à partir d'une séquence d'opérations simples.
Pour inverser une transformation combinée, on utilise la méthode invert. L'inverse crée une nouvelle transformation affine qui annule l'originale : si vous appliquez la transformation originale à un point, puis l'inverse, le point revient à sa position d'origine. L'inversion est utile pour annuler une transformation de contexte avant de dessiner des éléments d'interface qui ne doivent pas être transformés.
Pour vérifier si une transformation est identité (ne modifie pas les coordonnées), utilisez la propriété isIdentity. La transformation identité est une matrice unité — la multiplier laisse les coordonnées du point inchangées. Un nouvel objet NSAffineTransform est créé comme une transformation identité. Cette propriété est utile pour l'optimisation : si la transformation est identité, son application peut être ignorée.
NSAffineTransform peut être appliqué à quatre types d'objets : NSPoint, NSSize, NSBezierPath et le contexte graphique NSGraphicsContext. Pour chaque cible, il existe une méthode distincte : transformPoint:, transformSize:, transformBezierPath: et set.
La méthode transformPoint: multiplie la matrice de transformation par le vecteur de coordonnées du point (x, y, 1), retournant la nouvelle position du point. transformSize: fonctionne de manière similaire mais ne prend pas en compte les composants tX et tY — la translation n'est pas appliquée, seulement l'échelle, la rotation et le cisaillement. Ceci est utile pour transformer des vecteurs et des tailles qui ne doivent pas être déplacés.
La méthode transformBezierPath: crée un nouvel objet NSBezierPath dont chaque point est transformé selon la matrice NSAffineTransform. Le chemin d'origine n'est pas modifié — une copie avec des coordonnées transformées est créée. C'est une opération coûteuse pour les chemins complexes avec un grand nombre de nœuds.
La méthode set applique la transformation au contexte graphique actuel (NSGraphicsContext), modifiant sa CTM (Current Transformation Matrix). Après avoir appelé set, tout dessin ultérieur dans ce contexte sera transformé. Pour les transformations temporaires, utilisez saveGraphicsState / restoreGraphicsState avant et après set.
Examinons des exemples pratiques d'utilisation de NSAffineTransform dans une application macOS pour transformer des objets graphiques.
Cet exemple crée un NSAffineTransform combinant translation, rotation et échelle. D'abord, l'objet est déplacé de (100, 50), puis tourné de 45 degrés, et enfin mis à l'échelle par 1,5. L'ordre est important : tourner après avoir translaté tourne par rapport à la nouvelle origine.
import AppKit
let transform = NSAffineTransform()
transform.translateXBy(100, yBy: 50)
transform.rotateByDegrees(45)
transform.scaleBy(1.5)
// Application au point
let point = NSPoint(x: 10, y: 20)
let transformedPoint = transform.transform(point)
// Application à la taille
let size = NSSize(width: 100, height: 50)
let transformedSize = transform.transform(size)
Cet exemple montre l'application de NSAffineTransform à un contexte graphique via set et concat. Après application de la transformation, tout le dessin ultérieur est effectué dans le système de coordonnées transformé. La sauvegarde de l'état graphique via saveGraphicsState permet de revenir à la matrice d'origine.
func drawWithTransform(in rect: NSRect) {
guard let ctx = NSGraphicsContext.current
else { return }
ctx.saveGraphicsState()
let xfm = NSAffineTransform()
xfm.translateXBy(rect.midX, yBy: rect.midY)
xfm.rotateByDegrees(30)
xfm.scaleBy(0.8)
xfm.concat()
// Dessin dans le système de coordonnées transformé
let path = NSBezierPath(roundedRect: NSRect(
x: -50, y: -50,
width: 100, height: 100
), xRadius: 10, yRadius: 10)
NSColor.blue.setFill()
path.fill()
ctx.restoreGraphicsState()
}
Cet exemple montre la création d'une copie d'un NSBezierPath avec des coordonnées transformées. Le chemin d'origine reste inchangé et la copie transformée peut être dessinée séparément — ceci est utile pour créer des éléments répétés à différentes positions.
func createTransformedTriangle() -> NSBezierPath {
let triangle = NSBezierPath()
triangle.move(to: NSPoint(x: 0, y: 0))
triangle.line(to: NSPoint(x: 100, y: 0))
triangle.line(to: NSPoint(x: 50, y: 100))
triangle.close()
let xfm = NSAffineTransform()
xfm.translateXBy(200, yBy: 100)
xfm.scaleXBy(1.5, yBy: 1.5)
xfm.rotateByDegrees(45)
let transformed = xfm.transform(triangle)
return transformed
}
Questions fréquentes
NSAffineTransform est une classe d'AppKit (macOS uniquement), tandis que CGAffineTransform est une structure de Core Graphics (iOS et macOS). NSAffineTransform est un wrapper orienté objet et fournit des méthodes pour travailler avec NSBezierPath. CGAffineTransform est une structure légère de type valeur utilisée avec CGPath.
Pour pivoter autour du centre, effectuez trois étapes : 1) translater vers le centre de l'objet (déplacer l'origine au centre), 2) pivoter de l'angle souhaité, 3) translater en arrière par le vecteur négatif du centre. La combinaison translation—rotation—translation donne une rotation autour d'un point arbitraire, plutôt qu'autour de l'origine.
Non, NSAffineTransform est disponible uniquement sur macOS dans AppKit. Sur iOS, on utilise la structure CGAffineTransform de Core Graphics, qui offre des capacités similaires : CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation et CGAffineTransformConcat.
Utilisez la méthode invert, qui retourne la transformation inverse. Si vous multipliez la transformation originale par l'inverse, vous obtenez une matrice unité (transformation identité). Pour une application temporaire, appelez saveGraphicsState avant set et restoreGraphicsState après.
Utilisez une échelle négative : transform.scaleXBy(-1, yBy: 1) crée un reflet horizontal, tandis que scaleXBy(1, yBy: -1) crée un reflet vertical. Pour un reflet par rapport à un axe arbitraire, combinez translate (déplacement vers l'axe), scale avec -1 et translate inverse.
Résumé
invert annule toute transformation affineNous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi