2D平面中關於矩陣(Matrix)跟圖形變換的講解


在二維平面上,常用的有以下三種基本的圖形變化:

1)Translation

2)Scale

3)Rotation

在canvas的開發中,我們也經常會用到這樣的一些圖形變換,尤其是我們在寫自定義View時,更是會經常利用到Matrix來實現一些效果,比如平移,旋轉,縮放及切變等,相信很多朋友應該很想知道,矩陣實現這種變換的原理是什么,什么是矩陣的左乘右乘,它們在實現效果上有什么差別嗎?今天就讓我們一起來看一下吧。

都是由點組成的

平面上的元素,就是點,線,面,而線就是由一個個點組成的,而是由一條條線組成的,所以歸根結底,平面上所有的圖形都是由點組成的。而在我們坐標系中,一個點就是由一對x,y值組成的,p = {x, y}。而在平面上,過兩點間的,我們可以畫一條直線,所以我們一般通過 p1, p2可定義一條直線,e = {p1, p2},而圖形呢,則是由眾多的點和點之間的的線段組成的。所以,其實平面上的圖形變換,就是點坐標位置的變換。
在平面上,一個點,可以通過一個向量或者矩陣來表示:
而下面這條紅色的直線則是由一組組的點組成的,起始點是(120,0),終點是(240,120)。

Translation(平移)

如果我們現在要平移這條直線,向右120(tx),向下120(ty),那么新的點會是怎么樣呢?很顯然,起始點就會是(240,120),而終點就會是(360,240),效果如下:
綠色的線就是平移后的線了,可以看出每一個新的點的值是
這樣的一個變換translation也可以用一對值來表示,t = {tx, ty},其中tx是在x坐標上的偏移量,而ty是在y坐標上的偏移量。移動點 p 到 p',我們只要加上這個偏移就行,如果用矩陣或者向量來表示就是:
(可能會有朋友覺得奇怪,怎么是加呢,canvas里面矩陣不都是乘嗎?這是什么原因呢?)

Scale(縮放)

那如果我們對這條直線進行放大呢,比如放大2倍呢,一般來講,我們縮放,是指所有維度的縮放,當然在這里就只有x坐標跟y坐標,當然也可以只針對一個維度,但是就會變形了哦。我們先看一下放大到2倍的效果和只放大列的效果吧。
          
很顯然,兩邊都放大的話,起始點由(120,0)變成(240,0),終點由(240,120)變成(480,240)。而如果只放大列的話,起始點的坐標是不變的。而且我們可以看到,放大的時候,線也跟着向右平移了一個單位,為什么會這樣呢?這是因為縮放是基於原點(0,0)的,在canvas中,也就是屏幕的左上角,但縮放的位數大於1的時候,就會遠離原點,而相反,當縮放的位數小於1時,則會趨近原點。
縮放的變換是由下面的矩陣來表示的:
那么縮放后的直線的點就是:
各位朋友,可以想一下,這樣直接Scale的話,這個圖形可是會平移的哦,如果不想要平移,應該怎么辦?

Rotation(旋轉)

我們再看一下下圖,這條直線順時針旋轉了45度,也就是往逆時針方向旋轉了 - 45 度,這里的α 代表的是順時針旋轉角度
那么新的點是怎么算出來的呢?
逆時針(注意這里)旋轉的矩陣表示是:
同樣的,旋轉后的點就是根據下面的矩陣相乘而得出來的結果:
我們可以將我們的點代進去求解,可得新的起始點P0'為(84.85,84.85),而新的結束點為:(84.85,254.56),可看出,剛好是上面綠色線所在的地方。
 

Combine Transformation (組合變換)

對於Scale 和 Rotation 來說,它們都是基於原點(0,0)的變換,那如果我們要讓它基於某個點縮放或者旋轉,就比如繞着起始點轉呢,而這也經常是我們想要的一種效果。這個點就是所謂的旋轉,而解決辦法其實就是將圖形先平移到原點,再進行縮放或者旋轉的變化,然后再移回來,就可以了。
假設這三種變換的矩陣表示如下:
那么它應該實施的變換就如下:先平移 T 到原點,再基於原點進行縮放(或者旋轉),然后再平移回去,
其實這一步,我們可以在Canvas的代碼中看到的,如下:
 1     /**
 2      * Preconcat the current matrix with the specified scale.
 3      *
 4      * @param sx The amount to scale in X
 5      * @param sy The amount to scale in Y
 6      * @param px The x-coord for the pivot point (unchanged by the scale)
 7      * @param py The y-coord for the pivot point (unchanged by the scale)
 8      */
 9     public final void scale(float sx, float sy, float px, float py) {
10         translate(px, py);
11         scale(sx, sy);
12         translate(-px, -py);
13     }
上面代碼中的軸點的實現,其實就是對於平移的來回操作,至於為什么是translate(px,py)在前,而translate(-px,py)在后呢,這涉及到矩陣左乘和右乘的計算,后面我們會談到的。
 

Homogeneous Coordinates(齊次坐標)

在上面的矩陣中,我們可以看到平移的矩陣是相加的,而旋轉跟縮放的矩陣都是相乘的,這樣計算起來多麻煩呀!於是為了方便計算,大家都統一用一種方式來進行計算,聰明的計算機圖形科學家,它們就設計出這樣一種坐標系,叫homogeneous coordinates,而它的目的只是為了更加方便地去用矩陣來計算圖形的變換,沒有其他。
那什么是齊次坐標呢?
其實就是在原來2D的維度,再加上一個新的維度,多出來的維度的值永遠是1,比如點的矩陣就變成:
而Translation(平移)的矩陣表示就變成:
這樣,平移變換的加法就可以變成乘法:
而Scale(縮放)跟Rotation(旋轉)相對應的矩陣也就變成:
看到這幾個,大家發現了沒有?沒錯,這幾個就是我們canvas中用到的矩陣了。
 
當我們在Canvas上用Scale的時候,其實就是乘上S矩陣,當我們用Rotate的時候,其實就是乘上R矩陣,大家明白沒有?
轉載自:https://blog.csdn.net/linmiansheng/article/details/18801947
關於矩陣左乘右乘,前乘后乘的關系,如果有困惑的朋友,可以看一下下面這篇文章:
https://blog.csdn.net/linmiansheng/article/details/18820599
 
另外矩陣相關文章:
https://www.cnblogs.com/fangsmile/p/5651429.html
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM