CSS3——CSS3矩陣matrix進行2D變換的數學原理
css3的2D轉換中matrix接受6個引數,卻可以實現平移、旋轉、放縮、斜切四種效果。它是如何做到的呢? 此處的你有兩個選擇 0 - 對自己有較高要求!老老實實靜下心來將本文看完, 1 - 直接看總結——點我直達,只學習如何使用matrix
預備知識
:矩陣相乘和三角函式,fighting!
此處附上矩陣相乘的百度百科
定義
我們先將matrix接受的六個引數記為a,b,c,d,e,f,則該變換矩陣記為
二維平面上一個點記為(x,y),為了與向量
區分開,我們使用數字1
代表點,0
代表向量,則二維平面上一個點應記為(x,y,1),為了使該點經過變換後依舊為(x,y,1)的形式,矩陣可以改為
進行相乘變換(自行百度矩陣相乘的公式)
平移
我們知道,對一個點(x,y,1)向x軸正向平移10,向y軸正向平移20,得到的點為(x+10,y+20,1),而經過矩陣變換的點為(ax+cy+e,bx+dy+f,1),對比得到a=1,c=0,e=10,b=0,d=1,f=20 所以變換矩陣為
transform: matrix(1,0,0,1,10,20); // a=1,c=0,e=10,b=0,d=1,f=20
顯然,與平移變換直接相關的引數為e、f
引數!!
當我們只進行平移變換時,只需要這樣
transform: matrix(1,0,0,1,e,f); // 相當於 transform: translate(e,f);
放縮
假設我們對一個邊長為10px的正方形放大2倍,如圖所示 對左上角的那個點來說,它由(0,10,1)變為(0,20,1) 對任意一個點(x,y,1)來說,放大後得到的點為(2x,2y,1),而經過矩陣變換的點為(ax+cy+e,bx+dy+f,1),對比得到a=2,c=0,e=0,b=0,d=2,f=0 所以變換矩陣為
transform: matrix(2,0,0,2,0,0); // a=2,c=0,e=0,b=0,d=2,f=0
顯然,與縮放變換直接相關的引數為a、d
引數!!
當我們只進行平移變換時,只需要這樣
transform: matrix(a,0,0,d,0,0); // 相當於 transform: scale(a,d)
聰明的你現在肯定猜到了,如果既進行平移,又進行縮放,則transform: matrix(a,0,0,d,e,f);
即可,a、d表示縮放,e、f表示平移
旋轉
剩下兩個引數b、c,可是還有旋轉和斜切沒有實現呢!(冒汗
旋轉的話,涉及到旋轉角度的問題啦。記為θ。
複習一波三角函式,以下使用極座標
表示
來一波推理
對任意一個點(x,y,1)來說,旋轉θ°後得到的點為(xcosθ-ysinθ,xsinθ+ycosθ,1),而經過矩陣變換的點為(ax+cy+e,bx+dy+f,1),對比得到a=cosθ,b=sinθ,c=-sinθ,d=cosθ,e=0,f=0
所以變換矩陣為
這裡用到了a、b、c、d四個引數,前面我們知道縮放用了a、d兩個引數,如果我們既要旋轉又要縮放怎麼辦呢??
已經證明:任何二維組合變換均可分解為多個基本變換的乘積
故我們只需要分別求出變換矩陣,再相乘
即可。
q=DCBAp => q=(DCBA)p=Mp
解釋:p表示當前的點,ABCD表示四種變換,上述式子的變換順序為A->B->C->D
斜切
先沿x軸扭曲
有以下式子
與(ax+cy+e,bx+dy+f,1)對比得出a=1,c=tanθ,e=0,b=0,d=1,f=0
所以變換矩陣為
再看沿y軸扭曲
變換矩陣為
當l種變換同時進行時,有
【思考】我們之前說過,任何二維組合變換均可分解為多個基本變換的乘積,為什麼這裡不是將兩個扭曲矩陣相乘呢?(先沿x軸扭曲,再沿y軸扭曲?
emmm,是這樣的,我們這裡的計算都是相對最初始
的圖形,如果用兩個矩陣相乘,則是使初始圖形沿x軸扭曲θx度後得到的新圖形
再對y軸扭曲θy度!!如果要達到我們想要的效果,就只能重新計算沿y軸的扭曲角度!!
【總結】 至此我們已經把2D變換的數學原理挖出來了,寫一個用法總結,便於自己查詢也便於大家檢視
- 平移,只需要控制最後兩個引數e、f,a、d引數為1
transform: matrix(1,0,0,1,e,f);
// 等同於
transform: translate(e,f);
- 放縮,只需要控制a、d引數,其它為0
transform: matrix(a,0,0,d,0,0);
// 等同於
transform: scale(a,d);
- 旋轉,只需要控制a、b、c、d引數
transform: matrix(cosθ, sinθ, -sinθ, cosθ);
// 等同於
rtransform: rotate(θdeg)
- 斜切
transform: matrix(1, tanθy, tanθx, 1, 0, 0);
// 等同於
transform: skew(θx, θy);
- 複合變換 如以下這種型別,先旋轉再縮放再扭曲,如何用矩陣得到呢?
transform: rotate(360deg) scale(2,2) skew(10deg,5deg);
已經證明:任何二維組合變換均可分解為多個基本變換的乘積 故我們先求出旋轉矩陣A,縮放矩陣B和斜切矩陣C 最後得到變換矩陣M = CBA = C(B(A))
【什麼時候我們用矩陣?】 思考下,既然已經有rotate、scale等函式,直接呼叫不就行了嗎??為什麼人類要跟自己過不去,手算矩陣??? 大部分情況下,當然是使用那些基本的rotate、scale函式就好了,下面這種型別的情況呢?
- 需求說:請把這些點沿著y軸取對稱。 你:簡單
x’ = ax+cy+e = -x,y’ = bx+dy+f = y嘛,一番心算後你得到
transform: matrix(-1,0,0,1,0,0);
- 需求說:算了,還是對y=x取對稱吧。你:簡單,先整體旋轉
逆時針
旋轉45°,再對y軸取對稱,再整體順時針
旋轉45°(45°)就好了嘛~ (上圖右側表示逆時針旋轉)
用我們的高中數學來驗證一波,點(a,b)關於y=x軸取對稱,得到的點應該為(b,a) 驗證正確!transform: matrix(0,1,1,0,0,0);
- 需求猶豫了0.5s,哎呀還是對y=kx取對稱吧…
- 需求搖搖頭說,對y=kx+b取對稱吧…
此處插播高中知識——如何關於一條直線取對稱點呢?
- 兩個點關於一條直線對稱,那麼這兩個點的連線的中點必在該直線上
- 兩個點的連線所在直線的斜率與該直線斜率的乘積為-1(因為垂直)
- 可以列出兩個方程,求出對稱點!
- 對稱點都求出來了,矩陣也就出來了~
- 現在請看官使用rotate、scale、skew、translate實現上述需求~