NSAffineTransform — What It Is, Types of Transformations, and How to Apply Them

Author: IT Sectr Published: 2026-07-22 Reading time: 9 min

NSAffineTransform is a class from AppKit (macOS) that represents an affine transformation in two-dimensional graphics. It encapsulates a 3×3 matrix that describes a combination of translation, scaling, rotation, and shearing of coordinates. According to Apple Documentation (2026), NSAffineTransform is widely used in Core Graphics for transforming paths, points, and graphics contexts on macOS.

Key Takeaways

  • NSAffineTransform is an AppKit class for affine transformations on macOS with a 3×3 matrix
  • Affine transformation preserves line parallelism but can change distances and angles
  • Basic operations: translate (shift), scale (scaling), rotate (rotation), shear (skew)
  • Transformations are combined through matrix multiplication — the order of operations affects the result
  • NSAffineTransform is applied to points, sizes, paths, and the Core Graphics context

What is NSAffineTransform?

NSAffineTransform is a class from the AppKit framework, available only on macOS. It represents an affine transformation in two-dimensional space through a 3×3 matrix. Unlike CGAffineTransform from Core Graphics (which is available on iOS), NSAffineTransform is an object-oriented wrapper around the CGAffineTransform struct, adding convenient methods for working with NSBezierPath, NSPoint, and NSSize.

Affine transformation is a transformation of the plane that preserves the relation “point lies on a line” and parallelism of lines. In other words, after an affine transformation, parallel lines remain parallel and straight lines remain straight. However, distances, angles, and areas may change: scaling, rotation, and shear are special cases of affine transformations.

On iOS, the equivalent of NSAffineTransform is the CGAffineTransform struct from Core Graphics. Both APIs are based on the same mathematical model — a 3×3 affine transformation matrix where the last row is always [0, 0, 1]. The difference is that NSAffineTransform is a class (with retain/release in Objective-C), while CGAffineTransform is a struct (value type) in Swift and C.

Types of Affine Transformations

NSAffineTransform supports four basic types of transformations: translate (movement), scale (scaling), rotate (rotation), and shear (skew). Each type is represented by a separate method and can be applied to an existing transformation object or used to create a new one.

OperationNSAffineTransform MethodParametersVisual Effect
TranslatetranslateXBy:yBy:deltaX, deltaYShifts the object along the X and Y axes
ScalescaleBy: / scaleXBy:yBy:factor / scaleX, scaleYEnlarges or reduces the size
RotaterotateByDegrees: / rotateByRadians:angle in degrees or radiansRotates around the origin
ShearVia setTransformStructm12, m21 matrix componentsSkews the object along an axis

Translate — Translation

Translate adds an offset to the coordinates of all points of an object. The deltaX and deltaY parameters set the amount of horizontal and vertical shift respectively. A positive deltaX value shifts to the right, deltaY shifts up. Translate does not change the shape or size of the object — only its position.

Scale — Scaling

Scale multiplies point coordinates by a given factor. With uniform scaling (single parameter), the object enlarges or reduces proportionally. With non-uniform scaling, the shape is distorted. A factor of 1.0 leaves the size unchanged, greater than 1.0 enlarges, from 0.0 to 1.0 reduces. Negative values create a mirror reflection.

Rotate — Rotation

Rotate rotates the object around the origin by a given angle. A positive rotation angle corresponds to counterclockwise rotation. rotateByDegrees accepts degrees (0–360), rotateByRadians accepts radians (0–2π). Rotation is always performed relative to point (0, 0), so to rotate around an arbitrary point, you need to combine rotate with translate.

3×3 Matrix Representation

Affine transformation in NSAffineTransform is represented by a 3×3 matrix where the last row is always [0, 0, 1]. This is the standard mathematical representation that allows a combination of transformations to be represented as a product of matrices. The matrix structure is defined through NSAffineTransformStruct, which contains six significant components: m11, m12, m21, m22, tX, tY.

The m11, m12, m21, m22 components are responsible for scaling, rotation, and shear. The tX and tY components are responsible for translation. In the standard configuration (identity matrix), m11 = 1, m22 = 1, and the rest equal 0. To get the current matrix values, use transformStruct — the NSAffineTransform property that returns an NSAffineTransformStruct structure.

Matrix multiplication is a non-commutative operation. This means that the order of applying transformations matters: translate + rotate gives a different result than rotate + translate. When combining, NSAffineTransform multiplies the new matrix on the left by the current matrix: newMatrix = operation × currentMatrix. Therefore, the last added transformation is applied first.

Composing Transformations

NSAffineTransform allows combining multiple transformations in a single object. Each call to translateXBy:yBy:, scaleBy:, or rotateByDegrees: modifies the internal matrix — it multiplies the current matrix by the matrix of the corresponding transformation. This allows creating a complex transformation from a sequence of simple operations.

For inverting a combined transformation, use the invert method. The inverse creates a new affine transformation that cancels the original: if you apply the original transformation to a point and then the inverted one, the point returns to its original position. Inversion is useful for canceling a context transformation before drawing UI elements that should not be transformed.

To check whether a transformation is identity (does not change coordinates), use the isIdentity property. The identity transformation is a unit matrix — multiplying by it leaves the point coordinates unchanged. A new NSAffineTransform object is created as an identity transformation. This property is useful for optimization: if the transformation is identity, applying it can be skipped.

Applying to Objects and Context

NSAffineTransform can be applied to four types of objects: NSPoint, NSSize, NSBezierPath, and the NSGraphicsContext. For each target there is a separate method: transformPoint:, transformSize:, transformBezierPath:, and set.

Transforming Points and Sizes

The method transformPoint: multiplies the transformation matrix by the point coordinate vector (x, y, 1), returning the new position of the point. transformSize: works similarly but does not account for the tX and tY components — translation is not applied, only scaling, rotation, and shear. This is useful for transforming vectors and sizes that should not be shifted.

Transforming NSBezierPath Paths

The method transformBezierPath: creates a new NSBezierPath object, each point of which is transformed according to the NSAffineTransform matrix. The original path is not modified — a copy with transformed coordinates is created. This is an expensive operation for complex paths with a large number of nodes.

Applying to the Graphics Context

The method set applies the transformation to the current graphics context (NSGraphicsContext), modifying its CTM (Current Transformation Matrix). After calling set, all subsequent drawing in this context will be transformed. For temporary transformations, use saveGraphicsState / restoreGraphicsState before and after set.

Swift Code Examples

Let’s look at practical examples of using NSAffineTransform in a macOS application for transforming graphic objects.

Creating and Combining Transformations

This example creates an NSAffineTransform that combines translation, rotation, and scaling. First, the object is shifted by (100, 50), then rotated by 45 degrees, and finally scaled by 1.5 times. The order matters: rotate after translate rotates relative to the new origin.

swift
import AppKit

let transform = NSAffineTransform()
transform.translateXBy(100, yBy: 50)
transform.rotateByDegrees(45)
transform.scaleBy(1.5)

// Applying to point
let point = NSPoint(x: 10, y: 20)
let transformedPoint = transform.transform(point)

// Applying to size
let size = NSSize(width: 100, height: 50)
let transformedSize = transform.transform(size)

Transforming the Context for Drawing

This example demonstrates applying NSAffineTransform to a graphics context via set and concat. After applying the transformation, all subsequent drawing is performed in the transformed coordinate system. Saving the graphics state via saveGraphicsState allows returning to the original matrix.

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

    // Drawing in transformed coordinate system
    let path = NSBezierPath(roundedRect: NSRect(
        x: -50, y: -50,
        width: 100, height: 100
    ), xRadius: 10, yRadius: 10)
    NSColor.blue.setFill()
    path.fill()

    ctx.restoreGraphicsState()
}

Transforming an NSBezierPath

This example demonstrates creating a copy of an NSBezierPath with transformed coordinates. The original path remains unchanged, and the transformed copy can be drawn separately — this is useful for creating repeating elements in different 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
}

Frequently Asked Questions

What is the difference between NSAffineTransform and CGAffineTransform?

NSAffineTransform is a class from AppKit (macOS only), while CGAffineTransform is a struct from Core Graphics (iOS and macOS). NSAffineTransform is an object-oriented wrapper and provides methods for working with NSBezierPath. CGAffineTransform is a lightweight value-type struct used with CGPath.

How do I rotate an object around its center?

To rotate around the center, perform three steps: 1) translate to the object’s center (shift the origin to the center), 2) rotate by the desired angle, 3) translate back by the negative center vector. The translate—rotate—translate combination gives rotation around an arbitrary point, rather than around the origin.

Can I use NSAffineTransform on iOS?

No, NSAffineTransform is only available on macOS as part of AppKit. On iOS, use the CGAffineTransform struct from Core Graphics, which provides similar capabilities: CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation, and CGAffineTransformConcat.

How do I cancel a transformation?

Use the invert method, which returns the inverse transformation. If you multiply the original transformation by the inverted one, you get a unit matrix (identity transformation). For temporary application, call saveGraphicsState before set and restoreGraphicsState after.

How do I create a mirror reflection?

Use negative scaling: transform.scaleXBy(-1, yBy: 1) creates a horizontal reflection, while scaleXBy(1, yBy: -1) creates a vertical one. To reflect relative to an arbitrary axis, combine translate (shift to the axis), scale with -1, and inverse translate.

Summary

  • NSAffineTransform is an AppKit class for affine transformations with a 3×3 matrix on macOS
  • Four basic types: translate (shift), scale (scaling), rotate (rotation), and shear (skew)
  • The 3×3 matrix contains six significant components: m11, m12, m21, m22, tX, tY
  • The order of combining transformations affects the result — matrix multiplication is non-commutative
  • Applied to NSPoint, NSSize, NSBezierPath, and the graphics context through CTM
  • Inversion via the invert method cancels any affine transformation
  • On iOS, the equivalent is the CGAffineTransform struct from Core Graphics

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also