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 (ماتریس تبدیل جاری) آن را تغییر می‌دهد. پس از فراخوانی set، همه رسم‌های بعدی در این کنتکست تبدیل خواهند شد. برای تبدیل موقتی، از saveGraphicsState / restoreGraphicsState قبل و بعد از set استفاده کنید.

نمونه کد در Swift

به نمونه‌های عملی استفاده از NSAffineTransform در یک برنامه macOS برای تبدیل اشیای گرافیکی می‌پردازیم.

ایجاد و ترکیب تبدیل‌ها

مثال یک NSAffineTransform ایجاد می‌کند که انتقال، چرخش و مقیاس‌گیری را ترکیب می‌کند. ابتدا شیئِ به اندازه (100، 50) انتقال می‌یابد، سپس به میزان 45 درجه می‌چرخد و در نهایت 1.5 برابر بزرگ می‌شود. ترتیب مهم است: rotate پس از 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 یک ساختار سبک از نوع مقداری است که با CGPath استفاده می‌شود.

چگونه یک شیئِ را دور مرکزش بچرخانیم؟

برای چرخش دور مرکز، سه مرحله را انجام دهید: 1) translate به مرکز شیئِ (انتقال مبدا مختصات به مرکز)، 2) rotate به اندازه زاویه مورد نظر، 3) translate برگشت با بردار منفی مرکز. ترکیب translate—rotate—translate چرخش دور یک نقطه دلخواه را ایجاد می‌کند، نه دور مبدا مختصات.

آیا می‌توان از NSAffineTransform در iOS استفاده کرد؟

خیر، 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 معکوس را ترکیب کنید.

نتیجه‌گیری

  • 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 از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید