NSAffineTransform — co to jest, rodzaje transformacji i jak stosować

Autor: IT Sectr Opublikowano: 2026-07-22 Czas czytania: 9 min

NSAffineTransform — to klasa z AppKit (macOS), reprezentująca przekształcenie afiniczne w grafice dwuwymiarowej. Hermetyzuje macierz 3×3, która opisuje kombinację przesunięcia, skalowania, obrotu i pochylenia współrzędnych. Według Apple Documentation (2026), NSAffineTransform jest szeroko używany w Core Graphics do transformacji ścieżek, punktów i kontekstów graficznych na macOS.

Główne

  • NSAffineTransform — klasa AppKit do przekształceń afinicznych na macOS z macierzą 3×3
  • Przekształcenie afiniczne zachowuje równoległość linii, ale może zmieniać odległości i kąty
  • Główne operacje: translate (przesunięcie), scale (skalowanie), rotate (obrót), shear (pochylenie)
  • Przekształcenia łączy się przez mnożenie macierzy — kolejność operacji wpływa na wynik
  • NSAffineTransform stosuje się do punktów, rozmiarów, ścieżek i kontekstu graficznego Core Graphics

Czym jest NSAffineTransform?

NSAffineTransform — to klasa z frameworku AppKit, dostępna tylko na macOS. Reprezentuje przekształcenie afiniczne w przestrzeni dwuwymiarowej poprzez macierz 3×3. W przeciwieństwie do CGAffineTransform z Core Graphics (który jest dostępny na iOS), NSAffineTransform jest obiektowo zorientowanym opakowaniem struktury CGAffineTransform, dodającym wygodne metody do pracy z NSBezierPath, NSPoint i NSSize.

Przekształcenie afiniczne — to takie przekształcenie płaszczyzny, które zachowuje relację „punkt leży na prostej” i równoległość prostych. Innymi słowy, po przekształceniu afinicznym linie równoległe pozostają równoległe, a proste — prostymi. Jednak odległości, kąty i pola mogą się zmieniać: skalowanie, obrót i pochylenie są szczególnymi przypadkami przekształceń afinicznych.

Na iOS odpowiednikiem NSAffineTransform jest struktura CGAffineTransform z Core Graphics. Oba API opierają się na tym samym modelu matematycznym — macierzy przekształcenia afinicznego 3×3, gdzie ostatni wiersz to zawsze [0, 0, 1]. Różnica polega na tym, że NSAffineTransform to klasa (z retain/release w Objective-C), a CGAffineTransform to struktura (typ wartościowy) w Swift i C.

Rodzaje przekształceń afinicznych

NSAffineTransform obsługuje cztery podstawowe typy przekształceń: translate (przesunięcie), scale (skalowanie), rotate (obrót) i shear (pochylenie). Każdy typ jest reprezentowany przez osobną metodę i może być zastosowany zarówno do istniejącego obiektu transformacji, jak i użyty do utworzenia nowego.

OperacjaMetoda NSAffineTransformParametryEfekt wizualny
TranslatetranslateXBy:yBy:deltaX, deltaYPrzesunięcie obiektu wzdłuż osi X i Y
ScalescaleBy: / scaleXBy:yBy:factor / scaleX, scaleYZwiększenie lub zmniejszenie rozmiarów
RotaterotateByDegrees: / rotateByRadians:kąt w stopniach lub radianachObrót wokół początku układu współrzędnych
ShearPrzez setTransformStructskładowe m12, m21 macierzyPochylenie obiektu wzdłuż osi

Translate — przesunięcie

Translate dodaje przesunięcie do współrzędnych wszystkich punktów obiektu. Parametry deltaX i deltaY określają wielkość przesunięcia odpowiednio w poziomie i pionie. Dodatnia wartość deltaX przesuwa w prawo, deltaY — w górę. Translate nie zmienia kształtu ani rozmiaru obiektu — tylko jego położenie.

Scale — skalowanie

Scale mnoży współrzędne punktów przez zadany współczynnik. Przy równomiernym skalowaniu (jeden parametr) obiekt zwiększa się lub zmniejsza proporcjonalnie. Przy nierównomiernym — kształt ulega zniekształceniu. Współczynnik 1.0 pozostawia rozmiar bez zmian, większy niż 1.0 — zwiększa, od 0.0 do 1.0 — zmniejsza. Wartości ujemne tworzą odbicie lustrzane.

Rotate — obrót

Rotate obraca obiekt wokół początku układu współrzędnych o zadany kąt. Dodatni kąt obrotu odpowiada obrotowi przeciwnie do ruchu wskazówek zegara. rotateByDegrees przyjmuje stopnie (0–360), rotateByRadians — radiany (0–2π). Obrót jest zawsze wykonywany względem punktu (0, 0), dlatego do obrotu wokół dowolnego punktu należy połączyć rotate z translate.

Reprezentacja macierzowa 3×3

Przekształcenie afiniczne w NSAffineTransform jest reprezentowane przez macierz 3×3, gdzie ostatni wiersz to zawsze [0, 0, 1]. Jest to standardowa reprezentacja matematyczna, umożliwiająca przedstawienie kombinacji przekształceń jako iloczynu macierzy. Struktura macierzy jest określana przez NSAffineTransformStruct, która zawiera sześć znaczących składników: m11, m12, m21, m22, tX, tY.

Składniki m11, m12, m21, m22 odpowiadają za skalowanie, obrót i pochylenie. Składniki tX i tY — za przesunięcie. W standardowej konfiguracji (macierz jednostkowa) m11 = 1, m22 = 1, pozostałe są równe 0. Do pobrania bieżących wartości macierzy używa się transformStruct — właściwości NSAffineTransform zwracającej strukturę NSAffineTransformStruct.

Mnożenie macierzy jest operacją nieprzemienną. Oznacza to, że kolejność stosowania przekształceń ma znaczenie: translate + rotate daje inny wynik niż rotate + translate. Podczas łączenia NSAffineTransform mnoży nową macierz z lewej strony przez bieżącą: newMatrix = operation × currentMatrix. Dlatego ostatnie dodane przekształcenie jest stosowane jako pierwsze.

Łączenie przekształceń

NSAffineTransform pozwala łączyć wiele przekształceń w jednym obiekcie. Każde wywołanie translateXBy:yBy:, scaleBy: lub rotateByDegrees: modyfikuje wewnętrzną macierz — mnoży bieżącą macierz przez macierz odpowiedniego przekształcenia. Umożliwia to utworzenie złożonego przekształcenia z sekwencji prostych operacji.

Do odwracania złożonego przekształcenia używa się metody invert. Inwersja tworzy nowe przekształcenie afiniczne, które anuluje oryginalne: jeśli zastosujemy do punktu oryginalne przekształcenie, a następnie odwrócone, punkt powróci do początkowego położenia. Inwersja jest przydatna do cofnięcia transformacji kontekstu przed rysowaniem elementów UI, które nie powinny być przekształcone.

Sprawdzenie, czy przekształcenie jest tożsamościowe (nie zmienia współrzędnych), można wykonać przez właściwość isIdentity. Przekształcenie tożsamościowe to macierz jednostkowa, przy mnożeniu przez którą współrzędne punktu nie ulegają zmianie. Nowy obiekt NSAffineTransform jest tworzony jako przekształcenie tożsamościowe. Ta właściwość jest przydatna do optymalizacji: jeśli przekształcenie jest tożsamościowe, można pominąć jego zastosowanie.

Zastosowanie do obiektów i kontekstu

NSAffineTransform może być zastosowany do czterech typów obiektów: NSPoint, NSSize, NSBezierPath i kontekstu graficznego NSGraphicsContext. Dla każdego celu istnieje osobna metoda: transformPoint:, transformSize:, transformBezierPath: i set.

Transformacja punktów i rozmiarów

Metoda transformPoint: mnoży macierz przekształcenia przez wektor współrzędnych punktu (x, y, 1), zwracając nowe położenie punktu. transformSize: działa analogicznie, ale nie uwzględnia składników tX i tY — przesunięcie nie jest stosowane, tylko skalowanie, obrót i pochylenie. Jest to przydatne do transformacji wektorów i rozmiarów, które nie powinny być przesuwane.

Transformacja ścieżek NSBezierPath

Metoda transformBezierPath: tworzy nowy obiekt NSBezierPath, którego każdy punkt jest przekształcony zgodnie z macierzą NSAffineTransform. Oryginalna ścieżka nie ulega zmianie — tworzona jest kopia z przekształconymi współrzędnymi. Jest to kosztowna operacja dla złożonych ścieżek z dużą liczbą węzłów.

Zastosowanie do kontekstu graficznego

Metoda set stosuje przekształcenie do bieżącego kontekstu graficznego (NSGraphicsContext), modyfikując jego CTM (Current Transformation Matrix). Po wywołaniu set całe późniejsze rysowanie w tym kontekście będzie przekształcane. Do tymczasowego przekształcenia użyj saveGraphicsState / restoreGraphicsState przed i po set.

Przykłady kodu w Swift

Rozważmy praktyczne przykłady użycia NSAffineTransform w aplikacji macOS do transformacji obiektów graficznych.

Tworzenie i łączenie przekształceń

Przykład tworzy NSAffineTransform łączący przesunięcie, obrót i skalowanie. Najpierw obiekt jest przesuwany o (100, 50), następnie obracany o 45 stopni, a na końcu zwiększany 1.5 raza. Kolejność ma znaczenie: rotate po translate powoduje obrót względem nowego początku układu współrzędnych.

swift
import AppKit

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

// Zastosowanie do punktu
let point = NSPoint(x: 10, y: 20)
let transformedPoint = transform.transform(point)

// Zastosowanie do rozmiaru
let size = NSSize(width: 100, height: 50)
let transformedSize = transform.transform(size)

Transformacja kontekstu do rysowania

Przykład pokazuje zastosowanie NSAffineTransform do kontekstu graficznego przez set i concat. Po zastosowaniu transformacji całe późniejsze rysowanie odbywa się w przekształconym układzie współrzędnych. Zapisanie stanu grafiki przez saveGraphicsState umożliwia powrót do oryginalnej macierzy.

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

    // Rysowanie w przekształconym układzie współrzędnych
    let path = NSBezierPath(roundedRect: NSRect(
        x: -50, y: -50,
        width: 100, height: 100
    ), xRadius: 10, yRadius: 10)
    NSColor.blue.setFill()
    path.fill()

    ctx.restoreGraphicsState()
}

Transformacja ścieżki NSBezierPath

Przykład demonstruje tworzenie kopii NSBezierPath z przekształconymi współrzędnymi. Oryginalna ścieżka pozostaje bez zmian, a przekształcona kopia może być rysowana osobno — jest to przydatne do tworzenia powtarzających się elementów w różnych położeniach.

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
}

Często zadawane pytania

Czym różni się NSAffineTransform od CGAffineTransform?

NSAffineTransform — to klasa z AppKit (tylko macOS), a CGAffineTransform — to struktura z Core Graphics (iOS i macOS). NSAffineTransform jest obiektowo zorientowanym opakowaniem i udostępnia metody do pracy z NSBezierPath. CGAffineTransform to lekkostruktura typu wartościowego używana z CGPath.

Jak obrócić obiekt wokół jego środka?

Aby obrócić wokół środka, wykonaj trzy kroki: 1) translate do środka obiektu (przesunięcie początku układu do środka), 2) rotate o żądany kąt, 3) translate z powrotem o ujemny wektor środka. Kombinacja translate—rotate—translate daje obrót wokół dowolnego punktu, a nie wokół początku układu współrzędnych.

Czy można używać NSAffineTransform na iOS?

Nie, NSAffineTransform jest dostępny tylko na macOS w ramach AppKit. Na iOS używa się struktury CGAffineTransform z Core Graphics, która zapewnia analogiczne możliwości: CGAffineTransformMakeTranslation, CGAffineTransformMakeScale, CGAffineTransformMakeRotation i CGAffineTransformConcat.

Jak cofnąć przekształcenie?

Użyj metody invert, która zwraca odwrotne przekształcenie. Jeśli pomnożymy oryginalne przekształcenie przez odwrócone, otrzymamy macierz jednostkową (przekształcenie tożsamościowe). Do tymczasowego zastosowania wywołaj saveGraphicsState przed set i restoreGraphicsState po.

Jak utworzyć odbicie lustrzane?

Użyj ujemnej skali: transform.scaleXBy(-1, yBy: 1) tworzy odbicie w poziomie, a scaleXBy(1, yBy: -1) — w pionie. Do odbicia względem dowolnej osi połącz translate (przesunięcie na oś), scale z -1 i odwrotny translate.

Podsumowanie

  • NSAffineTransform — klasa AppKit do przekształceń afinicznych z macierzą 3×3 na macOS
  • Cztery podstawowe typy: translate (przesunięcie), scale (skalowanie), rotate (obrót) i shear (pochylenie)
  • Macierz 3×3 zawiera sześć znaczących składników: m11, m12, m21, m22, tX, tY
  • Kolejność łączenia przekształceń wpływa na wynik — mnożenie macierzy jest nieprzemienne
  • Stosuje się do NSPoint, NSSize, NSBezierPath i kontekstu graficznego przez CTM
  • Inwersja przez metodę invert anuluje działanie dowolnego przekształcenia afinicznego
  • Na iOS odpowiednikiem jest struktura CGAffineTransform z Core Graphics

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również