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 (ماتریس تبدیل جاری) آن را تغییر میدهد. پس از فراخوانی 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 استفاده کنید که تبدیل معکوس را بازمیگرداند. اگر تبدیل اصلی را در تبدیل معکوس ضرب کنیم، ماتریس واحد (تبدیل همانی) حاصل میشود. برای اعمال موقتی، قبل از set از saveGraphicsState و بعد از آن از restoreGraphicsState استفاده کنید.
از مقیاس منفی استفاده کنید: transform.scaleXBy(-1, yBy: 1) بازتاب افقی و scaleXBy(1, yBy: -1) بازتاب عمودی ایجاد میکند. برای بازتاب نسبت به یک محور دلخواه، translate (انتقال به محور)، scale با 1- و translate معکوس را ترکیب کنید.
نتیجهگیری
invert هر تبدیل افینی را لغو میکندما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید