NSAffineTransform — 개요, 변환 유형 및 적용 방법

저자: IT Sectr 게시일: 2026-07-22 읽는 시간: 9 분

NSAffineTransform은 2차원 그래픽에서 어파인 변환을 나타내는 AppKit(macOS)의 클래스입니다. 좌표의 이동, 크기 조정, 회전 및 기울이기의 조합을 설명하는 3×3 행렬을 캡슐화합니다. Apple 문서(2026)에 따르면, NSAffineTransform은 Core Graphics에서 macOS의 경로, 점 및 그래픽 컨텍스트를 변환하는 데 널리 사용됩니다.

핵심 사항

  • NSAffineTransform은 macOS에서 3×3 행렬로 어파인 변환을 위한 AppKit 클래스입니다
  • 어파인 변환은 선의 평행성을 유지하지만 거리와 각도를 변경할 수 있습니다
  • 기본 작업: translate(이동), scale(크기 조정), rotate(회전), shear(기울이기)
  • 변환은 행렬 곱셈을 통해 결합됩니다 — 작업 순서가 결과에 영향을 미칩니다
  • NSAffineTransform은 점, 크기, 경로 및 Core Graphics 컨텍스트에 적용됩니다

NSAffineTransform이란?

NSAffineTransform은 AppKit 프레임워크의 클래스로, macOS에서만 사용할 수 있습니다. 3×3 행렬을 통해 2차원 공간에서 어파인 변환을 나타냅니다. Core Graphics의 CGAffineTransform(iOS에서 사용 가능)과 달리, NSAffineTransform은 CGAffineTransform 구조체의 객체 지향 래퍼로, NSBezierPath, NSPoint 및 NSSize 작업을 위한 편리한 메서드를 추가합니다.

어파인 변환은 “점이 선 위에 있다”는 관계와 선의 평행성을 유지하는 평면의 변환입니다. 다시 말해, 어파인 변환 후에도 평행선은 평행을 유지하고 직선은 직선을 유지합니다. 그러나 거리, 각도 및 면적은 변경될 수 있습니다. 크기 조정, 회전 및 기울이기는 어파인 변환의 특수한 경우입니다.

iOS에서 NSAffineTransform에 해당하는 것은 Core Graphics의 CGAffineTransform 구조체입니다. 두 API 모두 동일한 수학적 모델을 기반으로 합니다 — 마지막 행이 항상 [0, 0, 1]인 3×3 어파인 변환 행렬입니다. 차이점은 NSAffineTransform은 클래스(Objective-C에서 retain/release 사용)이고, CGAffineTransform은 Swift와 C의 구조체(값 유형)라는 점입니다.

어파인 변환의 유형

NSAffineTransform은 translate(이동), scale(크기 조정), rotate(회전), shear(기울이기)의 네 가지 기본 변환 유형을 지원합니다. 각 유형은 별도의 메서드로 표현되며 기존 변환 객체에 적용하거나 새 변환을 만드는 데 사용할 수 있습니다.

작업NSAffineTransform 메서드매개변수시각적 효과
TranslatetranslateXBy:yBy:deltaX, deltaYX축과 Y축을 따라 객체 이동
ScalescaleBy: / scaleXBy:yBy:factor / scaleX, scaleY크기 확대 또는 축소
RotaterotateByDegrees: / rotateByRadians:도 또는 라디안 각도원점을 중심으로 회전
ShearsetTransformStruct를 통해행렬의 m12, m21 구성 요소축을 따라 객체 기울이기

Translate — 이동

Translate는 객체의 모든 점 좌표에 오프셋을 추가합니다. deltaX 및 deltaY 매개변수는 각각 수평 및 수직 이동량을 설정합니다. 양수 deltaX 값은 오른쪽으로, deltaY는 위쪽으로 이동합니다. Translate는 객체의 모양이나 크기를 변경하지 않습니다 — 위치만 변경합니다.

Scale — 크기 조정

Scale은 점의 좌표에 지정된 계수를 곱합니다. 균일한 크기 조정(단일 매개변수)에서는 객체가 비례적으로 확대 또는 축소됩니다. 비균일 크기 조정에서는 모양이 왜곡됩니다. 계수 1.0은 크기를 변경하지 않고, 1.0보다 크면 확대, 0.0에서 1.0 사이면 축소합니다. 음수 값은 거울 반사를 만듭니다.

Rotate — 회전

Rotate는 지정된 각도로 원점을 중심으로 객체를 회전합니다. 양수 회전 각도는 시계 반대 방향 회전에 해당합니다. rotateByDegrees는 도(0–360)를, rotateByRadians는 라디안(0–2π)을 받습니다. 회전은 항상 점(0, 0)을 기준으로 수행되므로, 임의의 점을 중심으로 회전하려면 rotate와 translate를 결합해야 합니다.

3×3 행렬 표현

NSAffineTransform의 어파인 변환은 마지막 행이 항상 [0, 0, 1]인 3×3 행렬로 표현됩니다. 이는 변환의 조합을 행렬의 곱으로 표현할 수 있는 표준 수학적 표현입니다. 행렬 구조는 NSAffineTransformStruct를 통해 정의되며, m11, m12, m21, m22, tX, tY의 6가지 중요한 구성 요소를 포함합니다.

m11, m12, m21, m22 구성 요소는 크기 조정, 회전 및 기울이기를 담당합니다. tXtY 구성 요소는 이동을 담당합니다. 표준 구성(단위 행렬)에서 m11 = 1, m22 = 1이고 나머지는 0입니다. 현재 행렬 값을 얻으려면 transformStruct — NSAffineTransformStruct 구조체를 반환하는 NSAffineTransform의 속성을 사용합니다.

행렬 곱셈은 비가환 연산입니다. 즉, 변환 적용 순서가 중요합니다: translate + rotaterotate + translate와 다른 결과를 제공합니다. 결합할 때 NSAffineTransform은 새 행렬을 왼쪽에서 현재 행렬에 곱합니다: newMatrix = operation × currentMatrix. 따라서 마지막에 추가된 변환이 먼저 적용됩니다.

변환 결합

NSAffineTransform은 단일 객체에 여러 변환을 결합할 수 있습니다. translateXBy:yBy:, scaleBy: 또는 rotateByDegrees:를 호출할 때마다 내부 행렬이 수정됩니다 — 현재 행렬에 해당 변환의 행렬을 곱합니다. 이를 통해 간단한 작업의 시퀀스로 복잡한 변환을 만들 수 있습니다.

결합된 변환을 반전하려면 invert 메서드를 사용합니다. 역변환은 원래 변환을 취소하는 새로운 어파인 변환을 만듭니다. 점에 원래 변환을 적용한 다음 역변환을 적용하면 점이 원래 위치로 돌아갑니다. 반전은 변환되지 않아야 하는 UI 요소를 그리기 전에 컨텍스트 변환을 취소하는 데 유용합니다.

변환이 항등(좌표를 변경하지 않음)인지 확인하려면 isIdentity 속성을 사용합니다. 항등 변환은 단위 행렬입니다 — 곱해도 점의 좌표가 변경되지 않습니다. 새 NSAffineTransform 객체는 항등 변환으로 생성됩니다. 이 속성은 최적화에 유용합니다. 변환이 항등이면 적용을 건너뛸 수 있습니다.

객체 및 컨텍스트에 적용

NSAffineTransform은 NSPoint, NSSize, NSBezierPath 및 NSGraphicsContext 그래픽 컨텍스트의 네 가지 유형의 객체에 적용할 수 있습니다. 각 대상에 대해 별도의 메서드가 있습니다: transformPoint:, transformSize:, transformBezierPath:set.

점 및 크기 변환

메서드 transformPoint:는 변환 행렬에 점의 좌표 벡터(x, y, 1)를 곱하여 점의 새 위치를 반환합니다. transformSize:는 비슷하게 작동하지만 tX 및 tY 구성 요소를 고려하지 않습니다 — 이동은 적용되지 않고 크기 조정, 회전 및 기울이기만 적용됩니다. 이는 이동되지 않아야 하는 벡터 및 크기 변환에 유용합니다.

NSBezierPath 경로 변환

메서드 transformBezierPath:는 각 점이 NSAffineTransform 행렬에 따라 변환된 새 NSBezierPath 객체를 만듭니다. 원래 경로는 수정되지 않습니다 — 변환된 좌표를 가진 복사본이 생성됩니다. 이는 많은 노드가 있는 복잡한 경로의 경우 비용이 많이 드는 작업입니다.

그래픽 컨텍스트에 적용

메서드 set은 현재 그래픽 컨텍스트(NSGraphicsContext)에 변환을 적용하여 CTM(현재 변환 행렬)을 수정합니다. set을 호출한 후 이 컨텍스트에서 이후의 모든 그리기가 변환됩니다. 임시 변환의 경우 set 전후에 saveGraphicsState/restoreGraphicsState를 사용합니다.

Swift 코드 예제

그래픽 객체를 변환하기 위한 macOS 애플리케이션에서 NSAffineTransform 사용의 실제 예제를 살펴보겠습니다.

변환 생성 및 결합

이 예제는 이동, 회전 및 크기 조정을 결합한 NSAffineTransform을 만듭니다. 먼저 객체가 (100, 50)만큼 이동되고, 그 다음 45도 회전되고, 마지막으로 1.5배 확대됩니다. 순서가 중요합니다: 이동 후 회전은 새 원점을 기준으로 회전합니다.

swift
import AppKit

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

// 포인트에 적용
let point = NSPoint(x: 10, y: 20)
let transformedPoint = transform.transform(point)

// 크기에 적용
let size = NSSize(width: 100, height: 50)
let transformedSize = transform.transform(size)

그리기를 위한 컨텍스트 변환

이 예제는 setconcat을 통해 그래픽 컨텍스트에 NSAffineTransform을 적용하는 방법을 보여줍니다. 변환을 적용한 후 이후의 모든 그리기는 변환된 좌표계에서 수행됩니다. saveGraphicsState를 통한 그래픽 상태 저장으로 원래 행렬로 돌아갈 수 있습니다.

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

    // 변환된 좌표계에서 그리기
    let path = NSBezierPath(roundedRect: NSRect(
        x: -50, y: -50,
        width: 100, height: 100
    ), xRadius: 10, yRadius: 10)
    NSColor.blue.setFill()
    path.fill()

    ctx.restoreGraphicsState()
}

NSBezierPath 변환

이 예제는 변환된 좌표를 가진 NSBezierPath의 복사본 생성을 보여줍니다. 원래 경로는 변경되지 않고, 변환된 복사본은 별도로 그릴 수 있습니다 — 이는 다른 위치에 반복 요소를 만드는 데 유용합니다.

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
}

자주 묻는 질문

NSAffineTransform과 CGAffineTransform의 차이점은 무엇인가요?

NSAffineTransform은 AppKit(macOS만 해당)의 클래스이고, CGAffineTransform은 Core Graphics(iOS 및 macOS)의 구조체입니다. NSAffineTransform은 객체 지향 래퍼이며 NSBezierPath 작업을 위한 메서드를 제공합니다. CGAffineTransform은 CGPath와 함께 사용되는 경량 값 유형 구조체입니다.

객체를 중심을 기준으로 회전하려면 어떻게 해야 하나요?

중심을 기준으로 회전하려면 세 단계를 수행합니다: 1) 객체의 중심으로 이동(원점을 중심으로 이동), 2) 원하는 각도로 회전, 3) 음수 중심 벡터만큼 다시 이동합니다. 이동—회전—이동 조합은 원점 대신 임의의 점을 중심으로 한 회전을 제공합니다.

iOS에서 NSAffineTransform을 사용할 수 있나요?

아니요, NSAffineTransform은 AppKit의 일부로 macOS에서만 사용할 수 있습니다. iOS에서는 Core Graphics의 CGAffineTransform 구조체를 사용하며, 이는 CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation 및 CGAffineTransformConcat과 같은 유사한 기능을 제공합니다.

변환을 취소하려면 어떻게 해야 하나요?

invert 메서드를 사용하면 역변환이 반환됩니다. 원래 변환에 역변환을 곱하면 단위 행렬(항등 변환)이 됩니다. 임시 적용의 경우 set 전에 saveGraphicsState를, 후에 restoreGraphicsState를 호출합니다.

거울 반사를 만들려면 어떻게 해야 하나요?

음수 크기 조정을 사용합니다: transform.scaleXBy(-1, yBy: 1)은 수평 반사를, scaleXBy(1, yBy: -1)은 수직 반사를 만듭니다. 임의의 축에 대한 반사의 경우 translate(축으로 이동), -1의 scale, 역 translate를 결합합니다.

요약

  • NSAffineTransform은 macOS에서 3×3 행렬로 어파인 변환을 위한 AppKit 클래스입니다
  • 네 가지 기본 유형: translate(이동), scale(크기 조정), rotate(회전), shear(기울이기)
  • 3×3 행렬은 6가지 중요한 구성 요소를 포함합니다: m11, m12, m21, m22, tX, tY
  • 변환 결합 순서가 결과에 영향을 미칩니다 — 행렬 곱셈은 비가환
  • NSPoint, NSSize, NSBezierPath 및 CTM을 통한 그래픽 컨텍스트에 적용
  • invert 메서드를 통한 반전으로 모든 어파인 변환 취소
  • iOS에서는 Core Graphics의 CGAffineTransform 구조체가 해당

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기