NSAffineTransform — је класа из AppKit-а (macOS) која представља афино преображај у дводимензионалној графици. Она инкапсулира матрицу 3×3 која описује комбинацију помијерања, скалирања, ротације и кошења координата. Према Apple Documentation (2026), NSAffineTransform се широко користи у Core Graphics за трансформацију путања, тачака и графичких контекста на macOS-у.
Главно
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 метода | Параметри | Визуелни ефекат |
|---|---|---|---|
| Translate | translateXBy:yBy: | deltaX, deltaY | Помијерање објекта дуж оса X и Y |
| Scale | scaleBy: / scaleXBy:yBy: | factor / scaleX, scaleY | Повећање или смањивање величина |
| Rotate | rotateByDegrees: / rotateByRadians: | угао у степенима или радијанима | Ротација око почетка координата |
| Shear | Путем setTransformStruct | компоненте m12, m21 матрице | Кошење објекта дуж осе |
Translate додаје помијерање координатама свих тачака објекта. Параметри deltaX и deltaY одређују величину помијерања хоризонтално и вертикално. Позитивна вриједност deltaX помиче удесно, deltaY — нагоре. Translate не мијења облик или величину објекта — само његов положај.
Scale множи координате тачака задатим фактором. Код равномјерног скалирања (један параметар) објекат се пропорционално повећава или смањује. Код неравномјерног скалирања облик се изобличује. Фактор 1.0 оставља величину непромијењеном, већи од 1.0 повећава, од 0.0 до 1.0 смањује. Негативне вриједности стварају огледало.
Rotate ротира објекат око почетка координата за задати угао. Позитиван угао ротације одговара ротацији супротно од казаљке на сату. rotateByDegrees прихвата степене (0–360), rotateByRadians — радијане (0–2π). Ротација се увијек извршава у односу на тачку (0, 0), па је за ротацију око произвољне тачке потребно комбиновати rotate са translate.
Афино преображај у 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 — помијерање се не примјењује, само скалирање, ротација и кошење. Ово је корисно за трансформацију вектора и величина које не треба да се помјерају.
Метода transformBezierPath: ствара нови NSBezierPath објекат, чија је свака тачка трансформисана у складу са NSAffineTransform матрицом. Оригинални пут се не мијења — ствара се копија са трансформисаним координатама. Ово је скупа операција за сложене путање са великим бројем чворова.
Метода set примјењује преображај на тренутни графички контекст (NSGraphicsContext), мијењајући његов CTM (Current Transformation Matrix). Након позива set, сва накнадна цртања у овом контексту биће трансформисана. За привремену трансформацију, користите saveGraphicsState / restoreGraphicsState прије и послије set.
Размотримо практичне примјере коришћења NSAffineTransform-а у macOS апликацији за трансформацију графичких објеката.
Примјер ствара NSAffineTransform који комбинује помијерање, ротацију и скалирање. Прво се објекат помиче за (100, 50), затим ротира за 45 степени и на крају повећава за 1.5 пута. Редослед је важан: rotate након translate даје ротацију у односу на нови почетак координата.
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 омогућава повратак на оригиналну матрицу.
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-а са трансформисаним координатама. Оригинални пут остаје непромијењен, а трансформисана копија може се цртати одвојено — ово је корисно за стварање елемената који се понављају на различитим положајима.
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 — је класа из AppKit-а (само macOS), а CGAffineTransform — је структура из Core Graphics-а (iOS и macOS). NSAffineTransform је објектно-оријентисано омотање и пружа методе за рад са NSBezierPath-ом. CGAffineTransform је лагана структура вриједносног типа која се користи са CGPath-ом.
За ротацију око центра, извршите три корака: 1) translate на центар објекта (помијерање почетка координата у центар), 2) rotate за жељени угао, 3) translate назад за негативни вектор центра. Комбинација translate—rotate—translate даје ротацију око произвољне тачке, а не око почетка координата.
Не, 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.
Резиме
invert поништава дјеловање било ког афиног преображајаРазвићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође