NSAffineTransform es una clase de AppKit (macOS) que representa una transformación afín en gráficos bidimensionales. Encapsula una matriz 3×3 que describe una combinación de traslación, escalado, rotación y corte de coordenadas. Según la Documentación de Apple (2026), NSAffineTransform se usa ampliamente en Core Graphics para transformar rutas, puntos y contextos gráficos en macOS.
Puntos Clave
NSAffineTransform es una clase del framework AppKit, disponible solo en macOS. Representa una transformación afín en el espacio bidimensional a través de una matriz 3×3. A diferencia de CGAffineTransform de Core Graphics (que está disponible en iOS), NSAffineTransform es un envoltorio orientado a objetos sobre la estructura CGAffineTransform, añadiendo métodos convenientes para trabajar con NSBezierPath, NSPoint y NSSize.
Una transformación afín es una transformación del plano que conserva la relación “el punto está en una línea” y el paralelismo de las líneas. En otras palabras, después de una transformación afín, las líneas paralelas permanecen paralelas y las líneas rectas permanecen rectas. Sin embargo, las distancias, los ángulos y las áreas pueden cambiar: el escalado, la rotación y el corte son casos especiales de transformaciones afines.
En iOS, el equivalente de NSAffineTransform es la estructura CGAffineTransform de Core Graphics. Ambas API se basan en el mismo modelo matemático — una matriz de transformación afín 3×3 donde la última fila es siempre [0, 0, 1]. La diferencia es que NSAffineTransform es una clase (con retain/release en Objective-C), mientras que CGAffineTransform es una estructura (tipo valor) en Swift y C.
NSAffineTransform admite cuatro tipos básicos de transformaciones: translate (traslación), scale (escalado), rotate (rotación) y shear (corte). Cada tipo está representado por un método separado y puede aplicarse a un objeto de transformación existente o usarse para crear uno nuevo.
| Operación | Método de NSAffineTransform | Parámetros | Efecto visual |
|---|---|---|---|
| Translate | translateXBy:yBy: | deltaX, deltaY | Desplaza el objeto a lo largo de los ejes X e Y |
| Scale | scaleBy: / scaleXBy:yBy: | factor / scaleX, scaleY | Aumenta o reduce el tamaño |
| Rotate | rotateByDegrees: / rotateByRadians: | ángulo en grados o radianes | Rota alrededor del origen |
| Shear | Mediante setTransformStruct | componentes m12, m21 de la matriz | Inclina el objeto a lo largo de un eje |
Translate añade un desplazamiento a las coordenadas de todos los puntos de un objeto. Los parámetros deltaX y deltaY establecen la cantidad de desplazamiento horizontal y vertical respectivamente. Un valor positivo de deltaX desplaza a la derecha, deltaY hacia arriba. Translate no cambia la forma ni el tamaño del objeto — solo su posición.
Scale multiplica las coordenadas de los puntos por un factor dado. Con el escalado uniforme (un solo parámetro), el objeto aumenta o disminuye proporcionalmente. Con el escalado no uniforme, la forma se distorsiona. Un factor de 1.0 deja el tamaño sin cambios, mayor de 1.0 aumenta, de 0.0 a 1.0 reduce. Los valores negativos crean un reflejo especular.
Rotate rota el objeto alrededor del origen en un ángulo dado. Un ángulo de rotación positivo corresponde a la rotación en sentido antihorario. rotateByDegrees acepta grados (0–360), rotateByRadians acepta radianes (0–2π). La rotación siempre se realiza con respecto al punto (0, 0), por lo que para rotar alrededor de un punto arbitrario, es necesario combinar rotate con translate.
La transformación afín en NSAffineTransform se representa mediante una matriz 3×3 donde la última fila es siempre [0, 0, 1]. Esta es la representación matemática estándar que permite representar una combinación de transformaciones como un producto de matrices. La estructura de la matriz se define a través de NSAffineTransformStruct, que contiene seis componentes significativos: m11, m12, m21, m22, tX, tY.
Los componentes m11, m12, m21, m22 son responsables del escalado, la rotación y el corte. Los componentes tX y tY son responsables de la traslación. En la configuración estándar (matriz identidad), m11 = 1, m22 = 1, y el resto son 0. Para obtener los valores actuales de la matriz, se usa transformStruct — la propiedad de NSAffineTransform que devuelve una estructura NSAffineTransformStruct.
La multiplicación de matrices es una operación no conmutativa. Esto significa que el orden de aplicación de las transformaciones importa: translate + rotate da un resultado diferente que rotate + translate. Al combinar, NSAffineTransform multiplica la nueva matriz a la izquierda por la matriz actual: newMatrix = operation × currentMatrix. Por lo tanto, la última transformación añadida se aplica primero.
NSAffineTransform permite combinar múltiples transformaciones en un solo objeto. Cada llamada a translateXBy:yBy:, scaleBy: o rotateByDegrees: modifica la matriz interna — multiplica la matriz actual por la matriz de la transformación correspondiente. Esto permite crear una transformación compleja a partir de una secuencia de operaciones simples.
Para invertir una transformación combinada, se usa el método invert. La inversa crea una nueva transformación afín que cancela la original: si aplicas la transformación original a un punto y luego la invertida, el punto vuelve a su posición original. La inversión es útil para cancelar una transformación del contexto antes de dibujar elementos de la interfaz que no deben transformarse.
Para comprobar si una transformación es identidad (no cambia las coordenadas), se usa la propiedad isIdentity. La transformación identidad es una matriz unitaria — multiplicar por ella deja las coordenadas del punto sin cambios. Un nuevo objeto NSAffineTransform se crea como una transformación identidad. Esta propiedad es útil para la optimización: si la transformación es identidad, se puede omitir su aplicación.
NSAffineTransform puede aplicarse a cuatro tipos de objetos: NSPoint, NSSize, NSBezierPath y el contexto gráfico NSGraphicsContext. Para cada objetivo existe un método separado: transformPoint:, transformSize:, transformBezierPath: y set.
El método transformPoint: multiplica la matriz de transformación por el vector de coordenadas del punto (x, y, 1), devolviendo la nueva posición del punto. transformSize: funciona de manera similar pero no tiene en cuenta los componentes tX y tY — la traslación no se aplica, solo el escalado, la rotación y el corte. Esto es útil para transformar vectores y tamaños que no deben desplazarse.
El método transformBezierPath: crea un nuevo objeto NSBezierPath, cada punto del cual se transforma según la matriz de NSAffineTransform. La ruta original no se modifica — se crea una copia con coordenadas transformadas. Esta es una operación costosa para rutas complejas con un gran número de nodos.
El método set aplica la transformación al contexto gráfico actual (NSGraphicsContext), modificando su CTM (Current Transformation Matrix). Después de llamar a set, todo el dibujo posterior en este contexto se transformará. Para transformaciones temporales, usa saveGraphicsState / restoreGraphicsState antes y después de set.
Veamos ejemplos prácticos del uso de NSAffineTransform en una aplicación de macOS para transformar objetos gráficos.
Este ejemplo crea un NSAffineTransform que combina traslación, rotación y escalado. Primero, el objeto se desplaza por (100, 50), luego se rota 45 grados y finalmente se escala 1.5 veces. El orden importa: rotar después de trasladar rota con respecto al nuevo origen.
import AppKit
let transform = NSAffineTransform()
transform.translateXBy(100, yBy: 50)
transform.rotateByDegrees(45)
transform.scaleBy(1.5)
// Aplicando al punto
let point = NSPoint(x: 10, y: 20)
let transformedPoint = transform.transform(point)
// Aplicando al tamaño
let size = NSSize(width: 100, height: 50)
let transformedSize = transform.transform(size)
Este ejemplo demuestra la aplicación de NSAffineTransform a un contexto gráfico mediante set y concat. Después de aplicar la transformación, todo el dibujo subsiguiente se realiza en el sistema de coordenadas transformado. Guardar el estado gráfico mediante saveGraphicsState permite volver a la matriz original.
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()
// Dibujando en el sistema de coordenadas transformado
let path = NSBezierPath(roundedRect: NSRect(
x: -50, y: -50,
width: 100, height: 100
), xRadius: 10, yRadius: 10)
NSColor.blue.setFill()
path.fill()
ctx.restoreGraphicsState()
}
Este ejemplo demuestra cómo crear una copia de un NSBezierPath con coordenadas transformadas. La ruta original permanece sin cambios, y la copia transformada puede dibujarse por separado — esto es útil para crear elementos repetidos en diferentes posiciones.
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
}
Preguntas Frecuentes
NSAffineTransform es una clase de AppKit (solo macOS), mientras que CGAffineTransform es una estructura de Core Graphics (iOS y macOS). NSAffineTransform es un envoltorio orientado a objetos y proporciona métodos para trabajar con NSBezierPath. CGAffineTransform es una estructura ligera de tipo valor utilizada con CGPath.
Para rotar alrededor del centro, realiza tres pasos: 1) trasladar al centro del objeto (desplazar el origen al centro), 2) rotar el ángulo deseado, 3) trasladar de vuelta por el vector negativo del centro. La combinación traslación—rotación—traslación da una rotación alrededor de un punto arbitrario, en lugar de alrededor del origen.
No, NSAffineTransform solo está disponible en macOS como parte de AppKit. En iOS se usa la estructura CGAffineTransform de Core Graphics, que proporciona capacidades similares: CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation y CGAffineTransformConcat.
Usa el método invert, que devuelve la transformación inversa. Si multiplicas la transformación original por la invertida, obtienes una matriz unitaria (transformación identidad). Para una aplicación temporal, llama a saveGraphicsState antes de set y restoreGraphicsState después.
Usa escalado negativo: transform.scaleXBy(-1, yBy: 1) crea un reflejo horizontal, mientras que scaleXBy(1, yBy: -1) crea uno vertical. Para reflejar con respecto a un eje arbitrario, combina translate (desplazamiento al eje), scale con -1 y translate inverso.
Resumen
invert cancela cualquier transformación afínDesarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también