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. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης