التحويلات الخطية والتآلفية

كتبه بركات يوم الإثنين, 12 أيلول 2016

تحدثنا في المقال السابق عن المعادلات الخطية والصيغة المتجهية وصيغة المصفوفات:

$$\begin{align*} x + 2y \\ 3x + 4y \end{align*} \Leftrightarrow x \begin{bmatrix} 1\\ 3 \end{bmatrix} + y \begin{bmatrix} 2\\ 4 \end{bmatrix} \Leftrightarrow \begin{bmatrix} 1 & 2\\ 3 & 4 \end{bmatrix} \begin{bmatrix} x\\ y \end{bmatrix}$$

كل هذه الصيغ مكافئة، إلا أن صيغة المصفوفات هي المعتمدة نظراً لكونها أبسط في الكتابة، وأسهل تمثيل في الكمبيوتر، بالإضافة لكون المعالجات الرسومية GPUs مجهزة لتسريع حسابات ضرب المتجهات بالمصفوفات.

المعادلة الخطية تعتبر دالة تأخذ متجه في بعد معين وتعيد متجه آخر في بعد آخر، $f : \mathbf{V} \to \mathbf{W}$، لكن غالباً تستخدم كلمة تحويل transform بدلاً من كلمة دالة مع المتجهات، وفي الرسوميات غالباً سنستخدم تحويلات تأخذ متجه في بعد وتعيد متجه في نفس البعد وتحديداً $f : \mathbb{R}^2 \to \mathbb{R}^2$ و $f : \mathbb{R}^3 \to \mathbb{R}^3$ وكذلك $f : \mathbb{R}^4 \to \mathbb{R}^4$.

مثال لتحويل $f : \mathbb{R}^2 \to \mathbb{R}^2$، حيث أن $\mathbf{x} \in \mathbb{R}^2$:

$$f(\mathbf{x}) = \begin{bmatrix} 1 & 2\\ 3 & 4 \end{bmatrix}\mathbf{x}$$

قيمتها عند $(5, 6)$:

$$f(\begin{bmatrix} 5\\ 6 \end{bmatrix}) = \begin{bmatrix} 1 & 2\\ 3 & 4 \end{bmatrix}\begin{bmatrix} 5\\ 6 \end{bmatrix} = \begin{bmatrix} 1\times 5 + 2 \times 6\\ 3\times 5 + 4 \times 6 \end{bmatrix} =\begin{bmatrix} 17\\ 39 \end{bmatrix}$$

يسمى التحويل تحويل خطي linear transform إذا كان يحقق العلاقة التالية:

$$\begin{align*} f(\mathbf{u} + \mathbf{v}) = f(\mathbf{u}) + f(\mathbf{v}) \\ f(a\mathbf{v}) = af(\mathbf{v}) \end{align*}$$

لأي $\mathbf{u}, \mathbf{v} \in \mathbb{R}^n$ ولأي $a \in \mathbb{R}$، والذي يميزه هو أن $f(\mathbf{0}) = \mathbf{0}$ خلافاً للتحويلات التآلفية كما سنرى لاحقاً، ذكرنا في المقال السابق أن المتجهات في الصيغة المتجهية وأعمدة المصفوفة تمثل الأساسات، فأي تغيير على هذه الأساسات تتعبه كل النقاط (المتجهات)، التحويلات الخطية يمكن وصفها بتأثيرها على الأساسات، فلا حاجة للنظر للنقاط وتطوير خوارزميات معقدة لإجراء التحويلات، بل كل مانحتاج للتركيز عليه هو الأساسات فقط.

هناك العديد من التحويلات الخطية التي يمكننا تأليفها، سنستخدم الصورة الثنائية الأبعاد التالية عندما نريد تمثيل التحويلات ومعاينة تأثيرها على النقاط الأربعة التي تشكل المربع الذي يحتوي الصورة:

Image

الصورة ستتضمن مصفوفة غرضها التوضيح وتمثل التحويل الخطي المطبق على النقاط، وهناك متجهين الأحمر $\mathbf{v}_0$ يمثل العمود الأول والمتجه الأخضر $\mathbf{v}_1$ يمثل العمود الثاني تلك المصوفة والمتجهات طبعاً ليست جزء من الصورة بل غرضها التوضيح فقط، نقاط مربع الصورة الأربعة حالياً كأنها مضروبة في مصفوفة الوحدة والتي تشكل أعمدها الإحداثي القياسي والتي لاتعمل شيء على الصورة، أنتبه أن كل مانقوم به يمكن تعميمه في الأبعاد الثلاثة، الاختلاف فقط أن المصفوفة ستكون $\mathbb{R}^{3\times3}$.

لتطبيق التحويلات على النقاط، فكل مانحتاج إليه هو المرور على النقاط في حلقة تكرار وضرب النقاط بالمصفوفة، شيء كالتالي:

Matrix2 m = ...;

for (i = 0 ; i < image.GetPointCount() ; ++i)
{
    Vector2 v = image.GetPoint(i);
    v = m * v;
    image.SetPoint(i, v);
}

نظراً لكون النقاط مستقله عن بعض، يمكننا أيضاً عمل هذه التحويلات على المعالج الرسومي GPU باستخدام المظللات shaders وهي برامج صغيرة تنفذ بالتوازي على مئات المعالجات، حيث نستفيد منها في تسريع تلك التحويلات نظراً لكون تلك التحويلات تنفذ بالتوازي، ولكون المعالجات الرسومية مجهزة بتعليمات لعمليات ضرب المتجهات بالمصفوفات، لكن هذا يتطلب استخدام أحد الواجهات البرمجية الخاصة بالرسوميات مثل OpenGL أو Direct3D.

التكبير والتصغير

أبسط وأهم تحويل خطي يمكننا عمله هو التكبير والتصغير، مثلاً هنا صغرنا الصورة للنصف:

Image

حيث أننا قمنا بضرب جميع النقاط الأربعة بتلك المصفوفة، ماعملته المصفوفة أنها صغرت الإحداثي حيث جعلت المتجهين $\mathbf{v}_0$ و $\mathbf{v}_1$ بنصف طولهما الأصلي، هذا التكبير يسمى تكبير متجانس حيث يكبر الإحداثيات بالتساوي، لكن يمكنك تكبير وتصغير متجهات الأساسات باستقلال عن بعض بحيث تجعل مثلاً الإحداثي الأفقي أكبر بمرة من العمودي، يمكن تعميم تحويل التكبير والتصغير بالتحويل التالي، حيث أن $\mathbf{v},\mathbf{s} \in \mathbb{R}^2$:

$$s(\mathbf{v}, \mathbf{s}) = \begin{bmatrix} s_0 & 0\\ 0 & s_1 \end{bmatrix}\mathbf{v}$$

لو كنت تصمم مثلاً محرر الصور وتريد إضافة ميزة التراجع عن التغييرات باستخدام الاختصار Ctrl+Z مثلاً، فيمكنك ضرب النقاط بعد التحويل بالمصفوفة التالية والتي تلغي التكبير:

$$s^{-1}(\mathbf{v}, \mathbf{s}) = \begin{bmatrix} 1/s_0 & 0\\ 0 & 1/s_1 \end{bmatrix}\mathbf{v}$$

بحيث تعيد متجهات الأساس لطولها الأصلي ومن ثم تصبح النقاط المضروبة بها في مكانها السابق، مثلاً لو كنت قد كبرت النقطتين $(1, 3)$ لثلاثة أضعاف وأصبحت $(3, 9)$، فإن ضربها بـ$1/3$ سيعيدها لأطوالها الأصلية $(3/3, 9/3) = (1, 3)$، طبعاً يمكننا تعميم الفكرة للاحداثيات الثلاثيات الأبعاد هكذا:

$$\begin{align*} s(\mathbf{v}, \mathbf{s}) &= \begin{bmatrix} s_0 & 0 & 0\\ 0 & s_1 & 0\\ 0 & 0 & s_2 \end{bmatrix}\mathbf{v} \in \mathbb{R}^3\\\\ s^{-1}(\mathbf{v}, \mathbf{s}) &= \begin{bmatrix} 1/s_0 & 0 & 0\\ 0 & 1/s_1 & 0\\ 0 & 0 & 1/s_2 \end{bmatrix}\mathbf{v} \in \mathbb{R}^3 \end{align*}$$

رياضياً، المصفوفة التي تلغي التأثير تسمى معكوس المصفوفة ويرمز لها $\mathbf{M}^{-1}$، لو ضربنا المتجه $\mathbf{v}$ بالمصفوفة $\mathbf{M}$، سينتج لنا متجه جديد ${\mathbf{v}}' = \mathbf{M}\mathbf{v}$، عند ضرب هذا المتجه الجديد بالمعكوس سنحصل على المتجه الأصلي قبل التحويل $\mathbf{v} = \mathbf{M}^{-1}{\mathbf{v}}'$.

يمكن حساب معكوس المصفوفات رياضياً وبرمجة دالة تسهل عليك إيجاد المعكوس لأي مصفوفة وهناك العديد من المصادر في الكتب والإنترنت حول إيجاد معكوس المصفوفات، يهم فقط المصفوفات ذات الأحجام $\mathbb{R}^{2\times2}$ و $\mathbb{R}^{3\times3}$ و $\mathbb{R}^{4\times4}$، لكن كوننا سنجري تحويلات محدودة، فيمكننا برمجة معكوس تلك التحويلات مسبقاً سواءً يدوياً أو عن طريق اشتقاقه هندسياً وبرمجة دالة تقوم بإيجاد معكوس التحويل فقط، مع قليل من الحيل الرياضية يمكننا الإستغناء تماماً عن الحاجة لحساب معكوس المصفوفة برمجياً، ولذلك لأن إيجاد المعكوس عملية مكلفة خصوصاً للمصفوفات ذات الحجم $\mathbb{R}^{4\times4}$، فالكثير من التطبيقات كالألعاب تجري عدد محدود من التحويلات قد لايتجاوز التكبير والتدوير والتحريك، فيمكننا الاستغناء عن برمجة دالة عامة الاستخدام لإيجاد معكوس المصفوفة، واسبتدالها بدالة سريعة لإيجاد معكوس التحويلات التي نستخدمها فقط، ومن ثم نزيد أداء البرنامج أو اللعبة.

التدوير

التحويل المهم الآخر هو التدوير، حيث نقوم بتدوير السطح بزاوية $\theta$، يمكن اشتقاق التدوير لو نظرنا إلى مثلث قائم الزاوية متساوي الضلعين داخل دائرة طول نصف قطرها 1:

Image

من هذه العلاقة ومن معرفتنا بالمثلثات نعرف أن النقطة $(x, y)$ تساوي $(\cos{\theta}, \sin{\theta})$ لأن:

$$\begin{align*} \cos{\theta} = \frac{x}{h = 1} \Leftrightarrow x = \cos{\theta} \\ \sin{\theta} = \frac{y}{h = 1} \Leftrightarrow y = \sin{\theta} \\ \end{align*}$$

هكذا يمكننا اشتقاق مصفوفة التدوير بالنظر إلى متجهات الأساس:

Image

يمكننا استخدام خصائص الدوال الزاوية وتبسيط $(\cos(\theta+{90}^{\circ}), \sin(\theta+{90}^{\circ}))$ إلى $(-\sin{\theta}, \cos{\theta})$ لتصبح مصفوفة الدوارن:

$$r(\mathbf{v}, \theta) = \begin{bmatrix} \cos{\theta} & -\sin{\theta}\\ \sin{\theta} & \cos{\theta} \end{bmatrix} \mathbf{v}$$

لتدوير الصورة ${30}^{\circ}$ درجة (انتبه أن معظم الدوال الزاوية في لغات البرمجة تستخدم الراديان):

Image

يمكننا عكس مصفوفة التدوير باستخدام WolframAlpha أو اشتقاقها عن طريق ملاحظة أن معكوس التحويل هو التدوير بالسالب $-\theta$، وباستخدام خصائص الدوال الزاوية:

$$\begin{align*} \cos(-\theta) &= \cos \theta \\ \sin(-\theta) &= -\sin\theta \\ \end{align*}$$

سنجد أن:

$$r^{-1}(\mathbf{v}, \theta) = \begin{bmatrix} \cos{\theta} & \sin{\theta}\\ -\sin{\theta} & \cos{\theta} \end{bmatrix} \mathbf{v}$$

لاحظ أن معكوس مصفوفة التدوير هو منقول المصفوفة، أي أن $\mathbf{M}^{-1} = \mathbf{M}^{T}$، وهذا في التدوير فقط.

في الإحداثي الثلاثي الأبعاد لايوجد لدينا إلا محور دوان واحد، بينما في الإحداثي الثلاثي الأبعاد لدينا ثلاثة محاور دوران ومن ثم ثلاثة دوال تدوير كلاً منها تدير على محور منفصل يمكننا اشتقاقها بنفس الطريقة:

$$ r_x(\mathbf{v}, \theta) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos \theta & -\sin \theta \\ 0 & \sin \theta & \cos \theta \\ \end{bmatrix}\mathbf{v}$$ $$r_y(\mathbf{v}, \theta) = \begin{bmatrix} \cos \theta & 0 & \sin \theta \\ 0 & 1 & 0 \\ -\sin \theta & 0 & \cos \theta \\ \end{bmatrix}\mathbf{v}$$ $$r_z(\mathbf{v}, \theta) = \begin{bmatrix} \cos \theta & -\sin \theta & 0 \\ \sin \theta & \cos \theta & 0\\ 0 & 0 & 1\\ \end{bmatrix}\mathbf{v}$$

حيث أن $\mathbf{v} \in \mathbb{R}^3$، ومعكوس تلك التحويلات هو أيضاً منقول تلك المصفوفات، سنتحدث لاحقاً عن تدوير أويلر بعدما نتحدث عن ضرب المصفوفات.

أنواع أخرى من التحويلات الخطية

يمكنك أيضاً أن تألف ماتريد من تحويلات باستخدام نفس الطريقة، وهي التركيز على الأساسات فقط، مثلاً التحويل التالي كثيراً ماسيتخدم في برامج تحويل الصور لعكس الصورة أفقياً:

Image

يمكنك أيضاً عكسها على أي محاور.

هذا تحويل آخر يسمى التمزيق shear:

Image

يمكنك كذلك تطبيقه على أي محور.

التحويلات التآلفية والتحريك

التحويلات السابقة كلها تحويلات خطية، التحويل الخطي كما أشرنا قيمة $f$ عند المتجه الصفري دوماً $f(\mathbf{0}) = \mathbf{0}$، هذا يعني أن التحويل الخطي لايكفي، فلتحريك translation نحتاج أن نستخدم التحويلات التآلفية affine transformations وهي تعميم للتحويلات الخطية، حيث أن كل تحويل تآلفي هو تحويل خطي لكن ليس العكس، ويكتب التحويل التآلفي عادةً:

$$f(\mathbf{v}) = \mathbf{M}\mathbf{v} + \mathbf{b} \in \mathbb{R}^n$$

حيث أن $\mathbf{b}$ هي التي تمكننا من الإزاحة، هنا قيمة $f(\mathbf{0}) = \mathbf{b}$.

كما ترى أن $\mathbf{b}$ متجه منفصل، لكن هناك حيلة أخرى تمكننا من التعبير عن التحريك بمصفوفة يمكننا دمجها ببعض تماماً كالتحويلات السابقة وهي الاحداثيات المتجانسة homogeneous coordinates.

فكرة الإحداثيات المتجانسة هي أن نضيف بعد إضافي إضافي للمصفوفة كالتالي:

$$t(\mathbf{v}, \mathbf{t}) = \begin{bmatrix} 1 & 0 & t_0\\ 0 & 1 & t_1\\ 0 & 0 & 1 \end{bmatrix}\begin{bmatrix} v_0\\ v_1\\ 1 \end{bmatrix} \in \mathbb{R}^3$$

لاحظ أن آخر صف في المتجه قيمة ثابتة ودوماً 1 في المتجه المرر والمتجه الناتج بعد التحويل طالما لم تغير الصف الأخير من المصفوفة، ستتضح الصورة أكثر لو حولت صيغة المصفوفة إلى صيغة المعادلة الخطية العادية: $$\begin{matrix} 1x &+& 0y &+& t_0(1) &= &x + t_0\\ 0x &+& 1y &+& t_1(1) &= &y + t_1\\ 0x &+& 0y &+& 1(1) &= &1 \end{matrix}$$

الواحد في الصف الأخير سنتجاهله عند رسم الصورة على الشاشة، مثال للتحريك:

Image

عكس التحريك هو التحريك بالإتجاه السالب:

$$t^{-1}(\mathbf{v}, \mathbf{t}) = \begin{bmatrix} 1 & 0 & -t_0\\ 0 & 1 & -t_1\\ 0 & 0 & 1 \end{bmatrix}\begin{bmatrix} v_0\\ v_1\\ 1 \end{bmatrix} \in \mathbb{R}^3$$

بالنسبة للتحويلات السابقة، نضيف بعد إضافي مع الإبقاء على المصفوفة كما هي كي نتمكن من ضربها لاحقاً بمصفوفة التحريك، مثلاً تحويل التكبير الثلاثي الأبعاد سنستخدم مصفوفة رباعية $\mathbb{R}^4$:

$$s(\mathbf{v}, \mathbf{s}) = \begin{bmatrix} s_0 & 0 & 0 & 0\\ 0 & s_1 & 0 & 0\\ 0 & 0 & s_2 & 0\\ 0 & 0 & 0 & 1\\ \end{bmatrix}\begin{bmatrix} v_0\\ v_1\\ v_2\\ 1 \end{bmatrix} \in \mathbb{R}^4$$

وكذلك لباقي التحويلات، الآن يمكننا دمج تلك المصفوفات ببعض بحيث لم نعد بحاجة لعمل استثناء للتحريك.

الإحداثي المتجانس يسمى أيضاً إحداثي الإسقاط projective coordinate، حيث أن له أهمية أخرى غير التحريك قد نتحدث عنها مستقبلاً وهي الإسقاط خصوصاً الإسقاط المنظوري، فلو كانت $(v_0, v_1, v_2, w)$ وكانت قيمة $w \ne 1$، فإن النقطة هنا غير متجانسه، لذا لجعلها متجانسه أي $w = 1$، يقوم المعالج الرسومي بعد تمرير النقاط له بقسمة جميع النقاط على $w$ لجعلها متجانسه $(v_0/w, v_1/w, v_2/w, w/w=1)$ في عملية تسمى القسمة المنظورية، فلو كانت قيمة $w = 2$، ستجد أن الجسم صغر للنصف بعد القسمة المنظورية، ولو كانت $w = 0.5$ ستجد أن الجسم تضاعف حجمه، هذه الخاصية هي التي يعتمد عليها الإسقاط المنظوري وهي التي تجعل الأجسام الأبعد تبدو أصغر، قد نتحدث عن الإسقاط في المستقبل، لكن كل التحويلات التي قمنا بها تضمن لك أن قيمة $w=1$ دوماً.

جبر المصفوفات

قبل أن نتحدث عن دمج التحويلات، نحتاج لمعرفة كيفية ضرب المصفوفات ومعنى ضربها، وكذلك معرفة بسيطة بخصائصها المصفوفات الجبرية التي ستساعدنا في إيجاد المعكوس للتحويلات بعد دمجها.

ضرب المصفوفات

يمكننا ضرب المصفوفات ببعض عن طريق ضرب صفوف المصفوفة في اليسار ضرب قياسي بأعمدة المصفوفة في اليمين كالتالي:

$$\begin{bmatrix} a_1 & b_1\\ c_1 & d_1 \end{bmatrix} \begin{bmatrix} a_0 & b_0\\ c_0 & d_0 \end{bmatrix} = \begin{bmatrix} a_1a_0 + b_1c_0 & a_1b_0 + b_1d_0\\ c_1a_0 + d_1c_0 & c_1b_0 + d_1d_0 \end{bmatrix}$$

والمبدأ نفسه في $\mathbb{R}^2$ و $\mathbb{R}^3$، ضرب المصفوفات ليس سوى التركيب الدالي $(f \circ g)(x) = f(g(x))$، حيث نعوض التحويل التآلفي الذي تمثله المصفوفة في اليمين بالمصفوفة في اليسار لتنتج مصفوفة جديدة مكافئة تمثل التحويل التآلفي المكافئ لكلا المصفوفتين، فمثلاً: $$\begin{bmatrix} 2 & 0\\ 0 & 2 \end{bmatrix} \begin{bmatrix} 1 & 3\\ 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y \end{bmatrix}$$

يكافئ:

$$\begin{align*} \begin{bmatrix} 2 & 0\\ 0 & 2 \end{bmatrix} \begin{bmatrix} 1 & 3\\ 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y \end{bmatrix} &\equiv \bigl(\begin{smallmatrix} \begin{bmatrix} 2x + 0y \\ 0x + 2y \end{bmatrix} & \circ & \begin{bmatrix} x + 3y \\ 0x + y \end{bmatrix} \end{smallmatrix}\bigr) \\ &= \begin{bmatrix} 2(x + 3y) + 0(0x + y) &=& 2x + 6y\\ 0(x + 3y) + 2(0x + y) &=& 2y \end{bmatrix} \\ &= \begin{bmatrix} 2 & 6\\ 0 & 2 \end{bmatrix} \begin{bmatrix} x\\ y \end{bmatrix} \end{align*}$$

المصفوفة الأخيرة هي ناتج ضرب المصفوفتين، هنا ترى ميزة صيغة المصفوفات التي تجعلها الصيغة المفضلة في الرسوميات وجميع التطبيقات العلمية، فبدلاً من التعامل مع المعادلات كرموز نتعامل معها كأرقام وهذا شيء يجيده الكمبيوتر.

خصائص الضرب الجبري

خلافاً لضرب الأعداد الحقيقية، فضرب المصفوفات غير إبدالي، $\mathbf{M}\mathbf{N}$ غالباً لن يساوي $\mathbf{N}\mathbf{M}$، يمكن تفسير افتقار المصفوفات لخاصية الإبدال بالرجوع لفكرة أن ضرب المصفوفات ليس سوى تركيب دالي، أو تفسيرها هندسياً بأن موقع الكائن النهائي لو أدرته أولاً ثم حركته سيختلف عن موقعه لو حركته أولاً ثم أدرته:

Image

ضرب المصفوفات قابل للتجميع، أي $(\mathbf{O}\mathbf{N})\mathbf{M} = \mathbf{O}(\mathbf{N}\mathbf{M})$، فلا يهم إن ضربت $\mathbf{M}$ في $\mathbf{N}$ أولاً ثم ضربت المصفوفة الناتجة مع $\mathbf{O}$، أو ضربت $\mathbf{N}$ مع $\mathbf{O}$ ثم ضربت المصفوفة $\mathbf{M}$ مع المصفوفة الناتجة من العملية السابقة، لكن انتبه أن لاتعكس الترتيب، فكما قلنا أن ضرب المصفوفات غير إبدالي.

ضرب المصفوفة $\mathbf{M}$ بمعكوسها $\mathbf{M}^{-1}$ سيعطي المحايد الضربي للمصفوفات وهو مصفوفة الوحدة $\mathbf{I} = \mathbf{M}^{-1}\mathbf{M}$، معكوس المصفوفة يشبه المعكوس الضربي $a^{-1} = 1/a$ للعدد $a \ne 0 \in \mathbb{R}$ فلو ضربنا العدد بمعكوسه سنحصل على المحايد الضربي $a^{-1}a = 1$.

يمكن توزيع المنقول على المصفوفات $(\mathbf{N}\mathbf{M})^T = \mathbf{M}^T\mathbf{N}^T$ وذلك بتوزيع المنقول مع عكس ترتيب المصفوفات، ونفس الشيء مع معكوس المصفوفة $(\mathbf{N}\mathbf{M})^{-1} = \mathbf{M}^{-1}\mathbf{N}^{-1}$، الخاصية الأخيرة مهمة.

نضرب المتجه العمودي بمصفوفة $\mathbf{N}\mathbf{M}\mathbf{v}$ من اليمين لليسار أي $\mathbf{N}(\mathbf{M}\mathbf{v}) = (\mathbf{N}\mathbf{M})\mathbf{v}$، بينما في حالة المتجه الصفي نضرب من اليسار لليمين $(\mathbf{N}\mathbf{M}\mathbf{v})^T = \mathbf{v}^T\mathbf{M}^T\mathbf{N}^T = (\mathbf{v}^T\mathbf{M}^T)\mathbf{N}^T = \mathbf{v}^T(\mathbf{M}^T\mathbf{N}^T)$، ذلك لأن ناتج ضرب المتجه بمصفوفة عبارة عن متجه.

تركيب التحريك، والتدوير والتكبير

واحدة من أهم المصفوفات المستخدمة خصوصاً في الألعاب هي مصفوفة المسماة TRS اختصاراً لجملة تحريك-تدوير-تكبير، حيث أنها ناتج ضرب مصفوفات التحويلات التآلفية، مثال في البعد الثاني:

$$\begin{align*} trs(\mathbf{v}, \mathbf{t}, \theta, \mathbf{s}) &= t(\mathbf{v}, \mathbf{t})\cdot r(\mathbf{v}, \theta)\cdot s(\mathbf{v}, \mathbf{s}) \\ &= \begin{bmatrix} s_0\cos{\theta} & -s_0\sin{\theta} & t_0 \\ s_1 \sin{\theta} & s_1\cos{\theta} & t_1\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} v_0\\ v_1\\ 1 \end{bmatrix} \end{align*}$$

حيث تقوم أولاً بالتكبير كي لانقع في مشكلة في حال كان التكبير غير متجانس، ثم التدوير ثم التحريك، هكذا يمكننا إنشاء محرر رسومي لتحديد قيم المتغيرات:

Image

أو جعلها في ملف XML:

<Transform2D>
    <Rotation angle="45">
    <Scale x="1" y="2">
    <Position x="-5" y="2">
</Transform2D>

يمكن أيضاً حساب معكوس تلك المصفوفة باستخدام الخصائص الجبرية للمصفوفات:

$$\begin{align*} trs^{-1}(\mathbf{v}, \mathbf{t}, \theta, \mathbf{s}) &= (t(\mathbf{v}, \mathbf{t})\cdot r(\mathbf{v}, \theta)\cdot s(\mathbf{v}, \mathbf{s}))^{-1} \\ &= s^{-1}(\mathbf{v}, \mathbf{s}) \cdot r^{-1}(\mathbf{v}, \theta) \cdot t^{-1}(\mathbf{v}, \mathbf{t}) \\ &= \begin{bmatrix} \frac{\cos{\theta}}{s_0} & \frac{\sin{\theta}}{s_1} & \frac{-t_0\cos{\theta}}{s_0} - \frac{t_1\sin{\theta}}{s_1}\\ \frac{-\sin{\theta}}{s_0} & \frac{\cos{\theta}}{s_1} & \frac{t_0\sin{\theta}}{s_0} - \frac{t_1\cos{\theta}}{s_1}\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} v_0\\ v_1\\ 1 \end{bmatrix} \end{align*}$$

لاحظ أن هناك حدود مكررة مثل $\cos{\theta}$ و $\sin{\theta}$ و $\cos{\theta}/s_0$ و $\sin{\theta}/s_1$ وغيرها، تلك الحدود يمكن حسابها مرة واحدة فقط وتخزين النتيجة في متغيرات لإعادة استخدامها.

زوايا أويلر

زوايا أويلر Euler angles تستخدم للتدوير في الإحداثيات الثلاثية الأبعاد، وهي ليست سوى مصفوفات التدوير الثلاثة التي سبق أن أشرنا لها مضروبات ببعض:

$$\begin{align*} \underset{zxy}{r}(\mathbf{v}, \phi, \psi, \theta) &= r_z(\theta) \cdot r_x(\phi) \cdot r_y(\psi)\cdot\mathbf{v} \\ &= \cdots \end{align*}$$

هذا الترتيب قد يكون الأكثر شيوع، إلا أن هناك خمسة توافيق أخرى للتدوير مثل $xzy$ و $xyz$ وغيرها، طبعاً الحدود المكررة يمكن حسابها مرة واحدة، ويمكن استخدام زوايا أويلر في تحويل $trs$.

معكوس زوايا أويلر هو منقول تلك المصفوفات:

$$\begin{align*} \underset{zxy}{r}^{-1}(\mathbf{v}, \phi, \psi, \theta) &= (r_z(\theta) \cdot r_x(\phi) \cdot r_y(\psi))^{-1}\cdot\mathbf{v}\\ &= r_y^T(\psi) \cdot r_x^T(\phi) \cdot r_z^T(\theta)\mathbf{v} \\ &= \cdots \end{align*}$$

زوايا أويلر سهلة الفهم، لكنها تعاني من مشاكل مثل كثرة التوافيق، ومشكلة الغموض أحياناً حينما يكون هناك أكثر من تدوير على محاور مختلفة يؤدي بالكائن لنفس الموقع النهائي، وهناك مشاكل في التحريك animation عندما نريد الإنتقال بين دوارنين وذلك عندما يتطابق محوري دوران على بعض بحيث نفقد أحد محاور الدوران، لذا عادةً تستخدم أعداد الكواتيرنيون quaternions التي يرمز لها $\mathbb{H}$ والتي تمثل امتداد لمجموعة الأعداد المركبة $\mathbb{C}$، فكما أن الأعداد المركبة يمكن استخدامها للتدوير في الإحداثي الثنائي الأبعاد، تستخدم الكواتيرنيون للتدوير في الإحداثي الثلاثي الأبعاد، ميزتها أنها لاتعاني من الغموض، فلا يوجد هناك إلا طريقة وحيدة للتدوير، وسهل أن نتنقل بين تدويرين في التحريك دون الوقوع في مشكلة تطابق محاور الدوران، إلا أن عيب الكواتيرنيون أنها قد تكون صعبة الفهم، لذا عادةً مايحول الكواتيرنيون إلى زوايا أويلر عند العرض أو الإدخال ويتعامل البرنامج داخلياً مع الكواتيرنيون للتدوير، قد أكتب عنها في مقال لاحق.