NSAffineTransform è una classe di AppKit (macOS) che rappresenta una trasformazione affine nella grafica bidimensionale. Incapsula una matrice 3×3 che descrive una combinazione di traslazione, scala, rotazione e taglio delle coordinate. Secondo la Documentazione Apple (2026), NSAffineTransform è ampiamente utilizzato in Core Graphics per trasformare percorsi, punti e contesti grafici su macOS.
Punti Chiave
NSAffineTransform è una classe del framework AppKit, disponibile solo su macOS. Rappresenta una trasformazione affine nello spazio bidimensionale attraverso una matrice 3×3. A differenza di CGAffineTransform di Core Graphics (disponibile su iOS), NSAffineTransform è un wrapper orientato agli oggetti attorno alla struttura CGAffineTransform, aggiungendo metodi convenienti per lavorare con NSBezierPath, NSPoint e NSSize.
Una trasformazione affine è una trasformazione del piano che preserva la relazione “il punto giace su una linea” e il parallelismo delle linee. In altre parole, dopo una trasformazione affine, le linee parallele rimangono parallele e le linee rette rimangono rette. Tuttavia, distanze, angoli e aree possono cambiare: scala, rotazione e taglio sono casi speciali di trasformazioni affini.
Su iOS, l'equivalente di NSAffineTransform è la struttura CGAffineTransform di Core Graphics. Entrambe le API si basano sullo stesso modello matematico — una matrice di trasformazione affine 3×3 in cui l'ultima riga è sempre [0, 0, 1]. La differenza è che NSAffineTransform è una classe (con retain/release in Objective-C), mentre CGAffineTransform è una struttura (tipo valore) in Swift e C.
NSAffineTransform supporta quattro tipi fondamentali di trasformazioni: translate (traslazione), scale (scala), rotate (rotazione) e shear (taglio). Ogni tipo è rappresentato da un metodo separato e può essere applicato a un oggetto di trasformazione esistente o utilizzato per crearne uno nuovo.
| Operazione | Metodo NSAffineTransform | Parametri | Effetto visivo |
|---|---|---|---|
| Translate | translateXBy:yBy: | deltaX, deltaY | Sposta l'oggetto lungo gli assi X e Y |
| Scale | scaleBy: / scaleXBy:yBy: | factor / scaleX, scaleY | Ingrandisce o riduce le dimensioni |
| Rotate | rotateByDegrees: / rotateByRadians: | angolo in gradi o radianti | Ruota attorno all'origine |
| Shear | Tramite setTransformStruct | componenti m12, m21 della matrice | Inclina l'oggetto lungo un asse |
Translate aggiunge un offset alle coordinate di tutti i punti di un oggetto. I parametri deltaX e deltaY impostano rispettivamente la quantità di spostamento orizzontale e verticale. Un valore positivo di deltaX sposta a destra, deltaY verso l'alto. Translate non modifica la forma o le dimensioni dell'oggetto — solo la sua posizione.
Scale moltiplica le coordinate dei punti per un dato fattore. Con la scala uniforme (un singolo parametro), l'oggetto si ingrandisce o si riduce proporzionalmente. Con la scala non uniforme, la forma viene distorta. Un fattore di 1,0 lascia le dimensioni invariate, maggiore di 1,0 ingrandisce, da 0,0 a 1,0 riduce. I valori negativi creano un riflesso speculare.
Rotate ruota l'oggetto attorno all'origine di un dato angolo. Un angolo di rotazione positivo corrisponde a una rotazione antioraria. rotateByDegrees accetta gradi (0–360), rotateByRadians accetta radianti (0–2π). La rotazione viene sempre eseguita rispetto al punto (0, 0), quindi per ruotare attorno a un punto arbitrario, è necessario combinare rotate con translate.
La trasformazione affine in NSAffineTransform è rappresentata da una matrice 3×3 in cui l'ultima riga è sempre [0, 0, 1]. Questa è la rappresentazione matematica standard che consente di rappresentare una combinazione di trasformazioni come prodotto di matrici. La struttura della matrice è definita tramite NSAffineTransformStruct, che contiene sei componenti significativi: m11, m12, m21, m22, tX, tY.
I componenti m11, m12, m21, m22 sono responsabili di scala, rotazione e taglio. I componenti tX e tY sono responsabili della traslazione. Nella configurazione standard (matrice identità), m11 = 1, m22 = 1 e gli altri sono 0. Per ottenere i valori correnti della matrice, si usa transformStruct — la proprietà di NSAffineTransform che restituisce una struttura NSAffineTransformStruct.
La moltiplicazione di matrici è un'operazione non commutativa. Ciò significa che l'ordine di applicazione delle trasformazioni è importante: translate + rotate dà un risultato diverso da rotate + translate. Durante la combinazione, NSAffineTransform moltiplica la nuova matrice a sinistra per la matrice corrente: newMatrix = operation × currentMatrix. Pertanto, l'ultima trasformazione aggiunta viene applicata per prima.
NSAffineTransform consente di combinare più trasformazioni in un singolo oggetto. Ogni chiamata a translateXBy:yBy:, scaleBy: o rotateByDegrees: modifica la matrice interna — moltiplica la matrice corrente per la matrice della trasformazione corrispondente. Ciò consente di creare una trasformazione complessa da una sequenza di operazioni semplici.
Per invertire una trasformazione combinata, si usa il metodo invert. L'inversa crea una nuova trasformazione affine che annulla quella originale: se si applica la trasformazione originale a un punto e poi l'inversa, il punto torna alla sua posizione originale. L'inversione è utile per annullare una trasformazione del contesto prima di disegnare elementi UI che non devono essere trasformati.
Per verificare se una trasformazione è identità (non modifica le coordinate), si usa la proprietà isIdentity. La trasformazione identità è una matrice unitaria — moltiplicare per essa lascia invariate le coordinate del punto. Un nuovo oggetto NSAffineTransform viene creato come trasformazione identità. Questa proprietà è utile per l'ottimizzazione: se la trasformazione è identità, la sua applicazione può essere saltata.
NSAffineTransform può essere applicato a quattro tipi di oggetti: NSPoint, NSSize, NSBezierPath e il contesto grafico NSGraphicsContext. Per ogni destinazione esiste un metodo separato: transformPoint:, transformSize:, transformBezierPath: e set.
Il metodo transformPoint: moltiplica la matrice di trasformazione per il vettore di coordinate del punto (x, y, 1), restituendo la nuova posizione del punto. transformSize: funziona in modo simile ma non tiene conto dei componenti tX e tY — la traslazione non viene applicata, solo scala, rotazione e taglio. Ciò è utile per trasformare vettori e dimensioni che non devono essere spostati.
Il metodo transformBezierPath: crea un nuovo oggetto NSBezierPath, ogni punto del quale viene trasformato secondo la matrice NSAffineTransform. Il percorso originale non viene modificato — viene creata una copia con coordinate trasformate. Questa è un'operazione costosa per percorsi complessi con un gran numero di nodi.
Il metodo set applica la trasformazione al contesto grafico corrente (NSGraphicsContext), modificando la sua CTM (Current Transformation Matrix). Dopo aver chiamato set, tutto il disegno successivo in questo contesto verrà trasformato. Per trasformazioni temporanee, usa saveGraphicsState / restoreGraphicsState prima e dopo set.
Vediamo esempi pratici di utilizzo di NSAffineTransform in un'applicazione macOS per trasformare oggetti grafici.
Questo esempio crea un NSAffineTransform che combina traslazione, rotazione e scala. Prima, l'oggetto viene spostato di (100, 50), poi ruotato di 45 gradi e infine scalato di 1,5 volte. L'ordine è importante: ruotare dopo aver traslato ruota rispetto alla nuova origine.
import AppKit
let transform = NSAffineTransform()
transform.translateXBy(100, yBy: 50)
transform.rotateByDegrees(45)
transform.scaleBy(1.5)
// Applicazione al punto
let point = NSPoint(x: 10, y: 20)
let transformedPoint = transform.transform(point)
// Applicazione alla dimensione
let size = NSSize(width: 100, height: 50)
let transformedSize = transform.transform(size)
Questo esempio dimostra l'applicazione di NSAffineTransform a un contesto grafico tramite set e concat. Dopo aver applicato la trasformazione, tutto il disegno successivo viene eseguito nel sistema di coordinate trasformato. Salvare lo stato grafico tramite saveGraphicsState consente di tornare alla matrice originale.
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()
// Disegno nel sistema di coordinate trasformato
let path = NSBezierPath(roundedRect: NSRect(
x: -50, y: -50,
width: 100, height: 100
), xRadius: 10, yRadius: 10)
NSColor.blue.setFill()
path.fill()
ctx.restoreGraphicsState()
}
Questo esempio dimostra la creazione di una copia di un NSBezierPath con coordinate trasformate. Il percorso originale rimane invariato e la copia trasformata può essere disegnata separatamente — questo è utile per creare elementi ripetuti in posizioni diverse.
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
}
Domande frequenti
NSAffineTransform è una classe di AppKit (solo macOS), mentre CGAffineTransform è una struttura di Core Graphics (iOS e macOS). NSAffineTransform è un wrapper orientato agli oggetti e fornisce metodi per lavorare con NSBezierPath. CGAffineTransform è una struttura leggera di tipo valore utilizzata con CGPath.
Per ruotare attorno al centro, esegui tre passaggi: 1) traslare al centro dell'oggetto (spostare l'origine al centro), 2) ruotare dell'angolo desiderato, 3) traslare indietro per il vettore centro negativo. La combinazione traslazione—rotazione—traslazione dà una rotazione attorno a un punto arbitrario, anziché attorno all'origine.
No, NSAffineTransform è disponibile solo su macOS come parte di AppKit. Su iOS viene utilizzata la struttura CGAffineTransform di Core Graphics, che fornisce funzionalità simili: CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation e CGAffineTransformConcat.
Usa il metodo invert, che restituisce la trasformazione inversa. Se moltiplichi la trasformazione originale per l'inversa, ottieni una matrice unitaria (trasformazione identità). Per un'applicazione temporanea, chiama saveGraphicsState prima di set e restoreGraphicsState dopo.
Usa scala negativa: transform.scaleXBy(-1, yBy: 1) crea un riflesso orizzontale, mentre scaleXBy(1, yBy: -1) crea un riflesso verticale. Per riflettere rispetto a un asse arbitrario, combina translate (spostamento sull'asse), scale con -1 e translate inverso.
Riepilogo
invert annulla qualsiasi trasformazione affineSvilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche