NSAffineTransform é uma classe do AppKit (macOS) que representa uma transformação afim em gráficos bidimensionais. Ela encapsula uma matriz 3×3 que descreve uma combinação de translação, escala, rotação e cisalhamento de coordenadas. De acordo com a Documentação da Apple (2026), NSAffineTransform é amplamente usado no Core Graphics para transformar caminhos, pontos e contextos gráficos no macOS.
Pontos Principais
NSAffineTransform é uma classe do framework AppKit, disponível apenas no macOS. Ela representa uma transformação afim no espaço bidimensional através de uma matriz 3×3. Ao contrário do CGAffineTransform do Core Graphics (que está disponível no iOS), NSAffineTransform é um invólucro orientado a objetos sobre a struct CGAffineTransform, adicionando métodos convenientes para trabalhar com NSBezierPath, NSPoint e NSSize.
Uma transformação afim é uma transformação do plano que preserva a relação “o ponto está em uma linha” e o paralelismo das linhas. Em outras palavras, após uma transformação afim, linhas paralelas permanecem paralelas e linhas retas permanecem retas. No entanto, distâncias, ângulos e áreas podem mudar: escala, rotação e cisalhamento são casos especiais de transformações afins.
No iOS, o equivalente do NSAffineTransform é a struct CGAffineTransform do Core Graphics. Ambas as APIs são baseadas no mesmo modelo matemático — uma matriz de transformação afim 3×3 onde a última linha é sempre [0, 0, 1]. A diferença é que NSAffineTransform é uma classe (com retain/release em Objective-C), enquanto CGAffineTransform é uma struct (tipo valor) em Swift e C.
NSAffineTransform suporta quatro tipos básicos de transformações: translate (translação), scale (escala), rotate (rotação) e shear (cisalhamento). Cada tipo é representado por um método separado e pode ser aplicado a um objeto de transformação existente ou usado para criar um novo.
| Operação | Método NSAffineTransform | Parâmetros | Efeito visual |
|---|---|---|---|
| Translate | translateXBy:yBy: | deltaX, deltaY | Desloca o objeto ao longo dos eixos X e Y |
| Scale | scaleBy: / scaleXBy:yBy: | factor / scaleX, scaleY | Aumenta ou reduz o tamanho |
| Rotate | rotateByDegrees: / rotateByRadians: | ângulo em graus ou radianos | Gira em torno da origem |
| Shear | Através de setTransformStruct | componentes m12, m21 da matriz | Inclina o objeto ao longo de um eixo |
Translate adiciona um deslocamento às coordenadas de todos os pontos de um objeto. Os parâmetros deltaX e deltaY definem a quantidade de deslocamento horizontal e vertical, respectivamente. Um valor positivo de deltaX desloca para a direita, deltaY para cima. Translate não altera a forma ou o tamanho do objeto — apenas sua posição.
Scale multiplica as coordenadas dos pontos por um fator dado. Com escala uniforme (um único parâmetro), o objeto aumenta ou diminui proporcionalmente. Com escala não uniforme, a forma é distorcida. Um fator de 1,0 mantém o tamanho inalterado, maior que 1,0 aumenta, de 0,0 a 1,0 reduz. Valores negativos criam um reflexo espelhado.
Rotate gira o objeto em torno da origem por um ângulo dado. Um ângulo de rotação positivo corresponde à rotação anti-horária. rotateByDegrees aceita graus (0–360), rotateByRadians aceita radianos (0–2π). A rotação é sempre realizada em relação ao ponto (0, 0), portanto, para girar em torno de um ponto arbitrário, é necessário combinar rotate com translate.
A transformação afim no NSAffineTransform é representada por uma matriz 3×3 onde a última linha é sempre [0, 0, 1]. Esta é a representação matemática padrão que permite representar uma combinação de transformações como um produto de matrizes. A estrutura da matriz é definida através de NSAffineTransformStruct, que contém seis componentes significativos: m11, m12, m21, m22, tX, tY.
Os componentes m11, m12, m21, m22 são responsáveis pela escala, rotação e cisalhamento. Os componentes tX e tY são responsáveis pela translação. Na configuração padrão (matriz identidade), m11 = 1, m22 = 1, e os demais são 0. Para obter os valores atuais da matriz, usa-se transformStruct — a propriedade do NSAffineTransform que retorna uma estrutura NSAffineTransformStruct.
A multiplicação de matrizes é uma operação não comutativa. Isso significa que a ordem de aplicação das transformações importa: translate + rotate dá um resultado diferente de rotate + translate. Ao combinar, NSAffineTransform multiplica a nova matriz à esquerda pela matriz atual: newMatrix = operation × currentMatrix. Portanto, a última transformação adicionada é aplicada primeiro.
NSAffineTransform permite combinar múltiplas transformações em um único objeto. Cada chamada a translateXBy:yBy:, scaleBy: ou rotateByDegrees: modifica a matriz interna — multiplica a matriz atual pela matriz da transformação correspondente. Isso permite criar uma transformação complexa a partir de uma sequência de operações simples.
Para inverter uma transformação combinada, usa-se o método invert. A inversa cria uma nova transformação afim que cancela a original: se você aplicar a transformação original a um ponto e depois a invertida, o ponto retorna à sua posição original. A inversão é útil para cancelar uma transformação de contexto antes de desenhar elementos de UI que não devem ser transformados.
Para verificar se uma transformação é identidade (não altera coordenadas), usa-se a propriedade isIdentity. A transformação identidade é uma matriz unitária — multiplicar por ela deixa as coordenadas do ponto inalteradas. Um novo objeto NSAffineTransform é criado como uma transformação identidade. Esta propriedade é útil para otimização: se a transformação é identidade, sua aplicação pode ser ignorada.
NSAffineTransform pode ser aplicado a quatro tipos de objetos: NSPoint, NSSize, NSBezierPath e o contexto gráfico NSGraphicsContext. Para cada alvo existe um método separado: transformPoint:, transformSize:, transformBezierPath: e set.
O método transformPoint: multiplica a matriz de transformação pelo vetor de coordenadas do ponto (x, y, 1), retornando a nova posição do ponto. transformSize: funciona de forma semelhante, mas não leva em conta os componentes tX e tY — a translação não é aplicada, apenas escala, rotação e cisalhamento. Isso é útil para transformar vetores e tamanhos que não devem ser deslocados.
O método transformBezierPath: cria um novo objeto NSBezierPath, cada ponto do qual é transformado de acordo com a matriz do NSAffineTransform. O caminho original não é modificado — uma cópia com coordenadas transformadas é criada. Esta é uma operação cara para caminhos complexos com um grande número de nós.
O método set aplica a transformação ao contexto gráfico atual (NSGraphicsContext), modificando sua CTM (Current Transformation Matrix). Após chamar set, todo o desenho subsequente neste contexto será transformado. Para transformações temporárias, use saveGraphicsState / restoreGraphicsState antes e depois de set.
Vejamos exemplos práticos do uso de NSAffineTransform em uma aplicação macOS para transformar objetos gráficos.
Este exemplo cria um NSAffineTransform que combina translação, rotação e escala. Primeiro, o objeto é deslocado por (100, 50), depois girado 45 graus e, finalmente, escalado 1,5 vezes. A ordem importa: girar após transladar gira em relação à nova origem.
import AppKit
let transform = NSAffineTransform()
transform.translateXBy(100, yBy: 50)
transform.rotateByDegrees(45)
transform.scaleBy(1.5)
// Aplicando ao ponto
let point = NSPoint(x: 10, y: 20)
let transformedPoint = transform.transform(point)
// Aplicando ao tamanho
let size = NSSize(width: 100, height: 50)
let transformedSize = transform.transform(size)
Este exemplo demonstra a aplicação de NSAffineTransform a um contexto gráfico através de set e concat. Após aplicar a transformação, todo o desenho subsequente é realizado no sistema de coordenadas transformado. Salvar o estado gráfico através de saveGraphicsState permite retornar à 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()
// Desenhando no 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 exemplo demonstra como criar uma cópia de um NSBezierPath com coordenadas transformadas. O caminho original permanece inalterado, e a cópia transformada pode ser desenhada separadamente — isso é útil para criar elementos repetidos em diferentes posições.
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
}
Perguntas Frequentes
NSAffineTransform é uma classe do AppKit (apenas macOS), enquanto CGAffineTransform é uma struct do Core Graphics (iOS e macOS). NSAffineTransform é um invólucro orientado a objetos e fornece métodos para trabalhar com NSBezierPath. CGAffineTransform é uma struct leve de tipo valor usada com CGPath.
Para girar em torno do centro, execute três passos: 1) transladar para o centro do objeto (deslocar a origem para o centro), 2) girar pelo ângulo desejado, 3) transladar de volta pelo vetor negativo do centro. A combinação translação—rotação—translação dá uma rotação em torno de um ponto arbitrário, em vez de em torno da origem.
Não, NSAffineTransform está disponível apenas no macOS como parte do AppKit. No iOS, usa-se a struct CGAffineTransform do Core Graphics, que fornece capacidades semelhantes: CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation e CGAffineTransformConcat.
Use o método invert, que retorna a transformação inversa. Se você multiplicar a transformação original pela inversa, obtém uma matriz unitária (transformação identidade). Para aplicação temporária, chame saveGraphicsState antes de set e restoreGraphicsState depois.
Use escala negativa: transform.scaleXBy(-1, yBy: 1) cria um reflexo horizontal, enquanto scaleXBy(1, yBy: -1) cria um reflexo vertical. Para refletir em relação a um eixo arbitrário, combine translate (deslocamento ao eixo), scale com -1 e translate inverso.
Resumo
invert cancela qualquer transformação afimVamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também