NSAffineTransform — ce que c'est, types de transformations et comment les appliquer

Auteur : IT Sectr Publié le : 2026-07-22 Temps de lecture : 9 min

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 AppKit pour les transformations affines sur macOS avec une matrice 3×3
  • Transformation affine préserve le parallélisme des lignes mais peut modifier les distances et les angles
  • Opérations de base : translate (translation), scale (échelle), rotate (rotation), shear (cisaillement)
  • Les transformations se combinent par multiplication matricielle — l'ordre des opérations affecte le résultat
  • NSAffineTransform s'applique aux points, aux tailles, aux chemins et au contexte Core Graphics

Qu'est-ce que NSAffineTransform ?

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.

Types de transformations affines

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érationMéthode NSAffineTransformParamètresEffet visuel
TranslatetranslateXBy:yBy:deltaX, deltaYDéplace l'objet le long des axes X et Y
ScalescaleBy: / scaleXBy:yBy:factor / scaleX, scaleYAgrandit ou réduit la taille
RotaterotateByDegrees: / rotateByRadians:angle en degrés ou radiansTourne autour de l'origine
ShearVia setTransformStructcomposants m12, m21 de la matriceIncline l'objet le long d'un axe

Translate — Translation

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 — Mise à l'échelle

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 — Rotation

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.

Représentation matricielle 3×3

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.

Composition des transformations

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.

Application aux objets et au contexte

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.

Transformation des points et des tailles

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.

Transformation des chemins NSBezierPath

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.

Application au contexte graphique

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.

Exemples de code Swift

Examinons des exemples pratiques d'utilisation de NSAffineTransform dans une application macOS pour transformer des objets graphiques.

Création et composition de transformations

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.

swift
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)

Transformation du contexte pour le dessin

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.

swift
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()
}

Transformation d'un NSBezierPath

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.

swift
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

Quelle est la différence entre NSAffineTransform et CGAffineTransform ?

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.

Comment faire pivoter un objet autour de son centre ?

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.

Puis-je utiliser NSAffineTransform sur iOS ?

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.

Comment annuler une transformation ?

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.

Comment créer un reflet miroir ?

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é

  • NSAffineTransform est une classe AppKit pour les transformations affines avec matrice 3×3 sur macOS
  • Quatre types de base : translate (translation), scale (échelle), rotate (rotation) et shear (cisaillement)
  • La matrice 3×3 contient six composants significatifs : m11, m12, m21, m22, tX, tY
  • L'ordre de combinaison des transformations affecte le résultat — la multiplication matricielle est non commutative
  • S'applique à NSPoint, NSSize, NSBezierPath et au contexte graphique via CTM
  • Inversion via la méthode invert annule toute transformation affine
  • Sur iOS, l'équivalent est la structure CGAffineTransform de Core Graphics

Nous 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.

Discuter du projet

Lisez aussi