NSAffineTransform — ما هو، أنواع التحولات وكيفية تطبيقها

المؤلف: IT Sectr نُشر: 2026-07-22 وقت القراءة: 9 دق

NSAffineTransform هي فئة من AppKit (macOS) تمثل تحولاً أفينياً في الرسوم ثنائية الأبعاد. تقوم بتغليف مصفوفة 3×3 تصف مجموعة من الإزاحة، والقياس، والتدوير، والقص للإحداثيات. وفقاً لوثائق Apple (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. تعتمد كلتا الواجهتين على نفس النموذج الرياضي — مصفوفة تحول أفيني 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. يُنشئ المعكوس تحولاً أفينياً جديداً يلغي الأصلي: إذا طبقت التحول الأصلي على نقطة ثم المعكوس، تعود النقطة إلى موقعها الأصلي. العكس مفيد لإلغاء تحول السياق قبل رسم عناصر واجهة المستخدم التي لا ينبغي تحويلها.

للتحقق مما إذا كان التحول هو تحول الوحدة (لا يغير الإحداثيات)، استخدم الخاصية 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 مرة. الترتيب مهم: التدوير بعد الإزاحة يتم بالنسبة لنقطة الأصل الجديدة.

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) إزاحة إلى مركز الكائن (نقل نقطة الأصل إلى المركز)، 2) تدوير بالزاوية المطلوبة، 3) إزاحة للخلف بمتجه المركز السالب. مجموعة الإزاحة—التدوير—الإزاحة تعطي تدويراً حول نقطة عشوائية، وليس حول نقطة الأصل.

هل يمكنني استخدام NSAffineTransform على iOS؟

لا، 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 معكوس.

الخلاصة

  • 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 تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا