Matrix的中文是矩陣的意思,在Android中它起着座標映射、變換的功能。意思就是說我們在自定義view中,有時需要對圖表進行縮放、旋轉、轉移、錯切等操作,就需要對圖表的座標進行一定的轉換,此時就是Matrix在後臺起作用的。Matrix是一個3x3的矩陣,大概長成下面那樣子,如圖:
舉個例子,爲什麼要用Matrix進行座標轉換,比如我想對點A圍繞原點旋轉30°,此時通過Matrix就可以很容易的實現這一需求,操作如下
Matrix matrix=new Matrix();
matrix.postRotate(30);
其實這個旋轉操作本質上是點A在旋轉前後的座標值發生了改變而已,但是如果旋轉後的座標值要我們自己去計算的話就非常麻煩,而直接調用matrix的postRotate方法,matrix就已經幫我們算好了。至於它裏面是怎麼計算的,下面會講到,這裏只是想說明Matrix的作用,就是對座標通過映射轉換成我們需要的座標值
Matrix的基本變換有四種:translate(平移)、scale(縮放)、rotate(旋轉)、skew(錯切)。下面來看看這個幾種變換分別對應Matrix矩陣的哪些位置
由上面兩個圖表,可以清楚地看到Matrix是一個3×3矩陣,每個參數代表的一定的意義,我們着重關注旋轉、位移、縮放、錯切這幾個參數即可。下面就逐一分析一下這幾種矩陣變換內部是如何實現的
1.縮放(scale)
比如對一個圖表在x和y軸分別縮放k1和k2倍
用Matrix實現如下
//首先構建一個單位矩陣
Matrix matrix=new Matrix();
matrix.setScale(k1,k2);
但從Matrix的內部原理來分析,它的計算公式如下
x=x0 * k1、y=y0 * k2
其中(x0、y0)代表變換前的座標,(x、y)代表變換後的座標
等價於矩陣的如下表示:
可以看到縮放值k1和k2剛好在Matrix矩陣的對應位置,然後通過矩陣的乘法規則,就可以計算出縮放後坐標的x值和y值了,同時也驗證了上面Matrix矩陣中MSACLE_X和MSCALE_Y參數所表示的意義
可以看到Matrix在內部就是這樣通過矩陣算法去映射縮放前後的座標值的
2.旋轉(rotate)
假如有一個點A(x0, y0),原來它跟X軸的夾角是α度,現在需要繞原點旋轉θ度
用Matrix實現如下
Matrix matrix=new Matrix();
matrix.setRotate(θ);
當然不管是縮放還是旋轉,矩陣計算的最終目的都是座標值的變換,假如旋轉後點A變換爲點 B(x, y),那麼點B的座標值x、y的計算如下:
上面的純數學計算方法,那麼用Matrix如何表示呢,如下圖:
圖示如下:
3.平移(translate)
假如對點對座標點(x0, y0)在X軸和Y軸方向分別平移△x和△y的大小
用Matrix的實現如下
Matrix matrix=new Matrix();
matrix.setTranslate(△x,△y);
如果平移後的座標爲(x, y ),則計算座標的公式如下:
矩陣表示如下
4.錯切(skew)
錯切分水平錯切、垂直錯切、複合錯切三種情形
水平錯切表示如下:
矩陣表示:
圖示:
垂直錯切:
矩陣表示:
圖示:
複合錯切:是上面兩種錯切的複合形式
矩陣表示:
圖示:
上面分析Matrix的四種基本操作,瞭解它們的內部運作原理,本質上就是通過矩陣算法去映射得到座標值。下面我們來看看Matrix的複合原理
Matrix複合原理分析
在開發的過程中,往往對座標的變換都不是單一操作,而上面四種情況都是矩陣的單一操作,如果要進行矩陣的複合操作,那麼就要用到複合操作方法了,常見的有:pre(前乘)、post(後乘)、set(設置),由於矩陣相乘不遵循乘法交換規則,所以關於前乘和後乘還是有很大區別的,而set操作是直接覆蓋掉前面的操作,重新開始
下面通過例子來理解這幾種複合操作:
先解析一下字母的意義,S代表縮放,T代表移動,M代表單位矩陣,R代表旋轉,M'代表結果
pre(前乘):有如下僞代碼
//首先構建一個單位矩陣
Matrix matrix=new Matrix();
//前乘旋轉angle角度
matrix.preRotate(angle);
//前乘縮放scale
matrix.preScale(scale);
//前乘位移trans
matrix.preTranslate(trans);
就如上面的矩陣複合是怎麼計算的呢?代碼的執行順序我們很明瞭,但是當前乘的時候,我們的矩陣是不斷加在前面的,表示成這樣:M' = M * R * S * T
後乘(post),有如下僞代碼:
//首先構建一個單位矩陣
Matrix matrix=new Matrix();
//後乘旋轉angle角度
matrix.postRotate(angle);
//後乘縮放scale
matrix.postScale(scale);
//後乘位移trans
matrix.postTranslate(trans);
用矩陣乘法表示:M' = T*S*R*M,即我們首先是一個單位矩陣M,然後R加在M的前面,S又加在R的前面,如此類推。由於矩陣不符合乘法交換法則,所以前乘和後乘得到的結果是一般是不一樣的。所以在開發的過程中,我們應該儘量使用一個乘法,即要麼都使用前乘要麼都使用後乘,這樣不容易混亂出錯
下面我們通過一個例子來論證,前乘和後乘的區別,現有兩個矩陣變換,代碼如下:
//構建單位矩陣
Matrix matrix=new Matrix();
//前乘代碼
matrix.preScale(0.5f,0.6f);
matrix.preTranslate(100,100);
//後乘代碼
matrix.postScale(0.5f,0.6f);
matrix.postTranslate(100,100);
上面前乘用公式表示:M' = S * T ; 後乘公式表示:M' = T * S ;可以看到它們的相乘順序是相反的,下面我們通過矩陣運算看看它們的結果是怎麼樣的:
前乘(pre)的計算如下:
後乘(post)的計算如下:
如此我們可以看到,它們的結果完全不一樣,主要是因爲矩陣是不符合乘法交換法則的,所以我們在運用複合操作的時候要特別注意這一點
Matrix的方法表:
方法類別 | 相關API | 摘要 |
---|---|---|
基本方法 | equals hashCode toString toShortString | 比較、 獲取哈希值、 轉換爲字符串 |
數值操作 | set reset setValues getValues | 設置、 重置、 設置數值、 獲取數值 |
數值計算 | mapPoints mapRadius mapRect mapVectors | 計算變換後的數值 |
設置(set) | setConcat setRotate setScale setSkew setTranslate | 設置變換 |
前乘(pre) | preConcat preRotate preScale preSkew preTranslate | 前乘變換 |
後乘(post) | postConcat postRotate postScale postSkew postTranslate | 後乘變換 |
特殊方法 | setPolyToPoly setRectToRect rectStaysRect setSinCos | 一些特殊操作 |
矩陣相關 | invert isAffine isIdentity | 求逆矩陣、 是否爲仿射矩陣、 是否爲單位矩陣 ... |
關於矩陣的基本原理,就先講到這裏,有更多的內容,可能會後續加入
附:關於矩陣相乘的法則,比如C=AB,因爲AB需要矩陣A的行依次乘以矩陣B的列,對應的元素相乘然後將它們的乘積相加。所以說矩陣A的列數和矩陣B的行數一定要相等。並且兩個矩陣的乘積C的行數等於第一個矩陣A的行數,列數等於第二個矩陣B的列數