NSAffineTransform — що це, види трансформацій та як застосовувати

Автор: IT Sectr Опубліковано: 2026-07-22 Час читання: 9 хв

NSAffineTransform — це клас із AppKit (macOS), що представляє афінне перетворення у двовимірній графіці. Він інкапсулює матрицю 3×3, яка описує комбінацію переміщення, масштабування, повороту та зсуву координат. За даними Apple Documentation (2026), NSAffineTransform широко використовується в Core Graphics для трансформації шляхів, точок і графічних контекстів на macOS.

Головне

  • NSAffineTransform — клас AppKit для афінних перетворень на macOS з матрицею 3×3
  • Афінне перетворення зберігає паралельність ліній, але може змінювати відстані та кути
  • Основні операції: translate (зсув), scale (масштаб), rotate (поворот), shear (зсув)
  • Перетворення комбінуються через множення матриць — порядок операцій впливає на результат
  • NSAffineTransform застосовується до точок, розмірів, шляхів і графічного контексту Core Graphics

Що таке NSAffineTransform?

NSAffineTransform — це клас із фреймворку AppKit, доступний лише на macOS. Він представляє афінне перетворення у двовимірному просторі через матрицю 3×3. На відміну від CGAffineTransform із Core Graphics (який доступний на iOS), NSAffineTransform є об'єктно-орієнтованою обгорткою над структурою CGAffineTransform, додаючи зручні методи для роботи з NSBezierPath, NSPoint та NSSize.

Афінне перетворення — це таке перетворення площини, яке зберігає відношення «точка лежить на прямій» і паралельність прямих. Іншими словами, після афінного перетворення паралельні лінії залишаються паралельними, а прямі — прямими. Однак відстані, кути та площі можуть змінюватися: масштабування, поворот і зсув є окремими випадками афінних перетворень.

На iOS аналогом NSAffineTransform є структура CGAffineTransform із Core Graphics. Обидва API засновані на одній математичній моделі — матриці афінного перетворення 3×3, де останній рядок завжди [0, 0, 1]. Відмінність у тому, що NSAffineTransform — це клас (із retain/release в Objective-C), а CGAffineTransform — це структура (значущий тип) у Swift та C.

Типи афінних перетворень

NSAffineTransform підтримує чотири базових типи перетворень: translate (переміщення), scale (масштабування), rotate (поворот) та shear (зсув/нахил). Кожен тип представлений окремим методом і може бути застосований як до існуючого об'єкта трансформації, так і використаний для створення нового.

ОпераціяМетод NSAffineTransformПараметриВізуальний ефект
TranslatetranslateXBy:yBy:deltaX, deltaYЗміщення об'єкта по осях X та Y
ScalescaleBy: / scaleXBy:yBy:factor / scaleX, scaleYЗбільшення або зменшення розмірів
RotaterotateByDegrees: / rotateByRadians:кут у градусах або радіанахПоворот навколо початку координат
ShearЧерез setTransformStructкомпоненти матриці 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 представляється матрицею 3×3, де останній рядок завжди [0, 0, 1]. Це стандартне математичне представлення, що дозволяє представляти комбінацію перетворень як добуток матриць. Структура матриці визначається через NSAffineTransformStruct, що містить шість значущих компонентів: m11, m12, m21, m22, tX, tY.

Компоненти m11, m12, m21, m22 відповідають за масштабування, поворот та зсув. Компоненти tX та tY — за переміщення. У стандартній конфігурації (одинична матриця) m11 = 1, m22 = 1, інші дорівнюють 0. Для отримання поточних значень матриці використовується transformStruct — властивість NSAffineTransform, що повертає структуру NSAffineTransformStruct.

Множення матриць — некомутативна операція. Це означає, що порядок застосування перетворень має значення: translate + rotate дає інший результат, ніж rotate + 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: створює новий об'єкт NSBezierPath, кожна точка якого трансформована відповідно до матриці NSAffineTransform. Вихідний шлях не змінюється — створюється копія з трансформованими координатами. Це дорога операція для складних шляхів з великою кількістю вузлів.

Застосування до графічного контексту

Метод set застосовує перетворення до поточного графічного контексту (NSGraphicsContext), модифікуючи його CTM (Current Transformation Matrix). Після виклику set вся подальша відмальовка в цьому контексті буде трансформуватися. Для тимчасової трансформації використовуйте saveGraphicsState / restoreGraphicsState до та після set.

Приклади коду на Swift

Розглянемо практичні приклади використання NSAffineTransform у macOS-додатку для трансформації графічних об'єктів.

Створення та комбінування перетворень

Приклад створює NSAffineTransform, що комбінує зсув, поворот та масштабування. Спочатку об'єкт зміщується на (100, 50), потім повертається на 45 градусів і, нарешті, збільшується в 1.5 раза. Важливий порядок: поворот після translate буде відносно нового початку координат.

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)

Трансформація контексту для відмальовки

Приклад показує застосування NSAffineTransform до графічного контексту через set та concat. Після застосування трансформації вся подальша відмальовка виконується в трансформованій системі координат. Збереження стану графіки через 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 — легковагова value-тип структура, що використовується з CGPath.

Як повернути об'єкт навколо його центру?

Для повороту навколо центру виконайте три кроки: 1) translate на центр об'єкта (зміщення початку координат у центр), 2) rotate на потрібний кут, 3) translate назад на від'ємний вектор центру. Комбінація translate—rotate—translate дає обертання навколо довільної точки, а не навколо початку координат.

Чи можна використовувати NSAffineTransform на iOS?

Ні, NSAffineTransform доступний лише на macOS у складі AppKit. На iOS використовується структура CGAffineTransform із Core Graphics, яка надає аналогічні можливості: CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation та CGAffineTransformConcat.

Як скасувати перетворення?

Використовуйте метод invert, який повертає обернене перетворення. Якщо помножити вихідне перетворення на інвертоване, вийде одинична матриця (тотожне перетворення). Для тимчасового застосування викличте saveGraphicsState до set та restoreGraphicsState після.

Як створити дзеркальне відображення?

Використовуйте від'ємний масштаб: transform.scaleXBy(-1, yBy: 1) створює відображення по горизонталі, а scaleXBy(1, yBy: -1) — по вертикалі. Для відображення відносно довільної осі скомбінуйте translate (зміщення на вісь), scale з -1 та зворотний translate.

Підсумки

  • NSAffineTransform — клас AppKit для афінних перетворень з матрицею 3×3 на macOS
  • Чотири базових типи: translate (зсув), scale (масштаб), rotate (поворот) та shear (нахил)
  • Матриця 3×3 містить шість значущих компонентів: m11, m12, m21, m22, tX, tY
  • Порядок комбінування перетворень впливає на результат — множення матриць некомутативне
  • Застосовується до NSPoint, NSSize, NSBezierPath та графічного контексту через CTM
  • Інверсія через метод invert скасовує дію будь-якого афінного перетворення
  • На iOS аналогом є структура CGAffineTransform із Core Graphics

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також