自定義View(十)Matrix 基礎(chǔ)理論與使用

Matrix就是矩陣的意思,所有的控件中都有Matrix的身影。

Matrix是一個(gè)三階矩陣,主要功能是坐標(biāo)映射,數(shù)值變換,見(jiàn)下圖

Matrix

再講下邊的內(nèi)容之間,先提前介紹一下下邊用到的名詞:

名詞 解釋
單位矩陣
單位矩陣
M 原始矩陣,沒(méi)有變換之前的矩陣
A 變換
M` 結(jié)果矩陣
T 平移變換
-T 反向平移變換
R 旋轉(zhuǎn)變換

Matrix基本原理

Matrix的根本作用就是坐標(biāo)的變化;基本變換有平移(translate),縮放(scale),旋轉(zhuǎn)(skew),錯(cuò)切四種。


矩陣中各數(shù)據(jù)組合所指

矩陣中各數(shù)據(jù)組合所指

最后一行的數(shù)據(jù)透視使用在3D變換中

縮放(scale)

在進(jìn)行縮放的時(shí)候需要變換(MSCALE_X,MSCALE_Y)這兩個(gè)值,分別作用于x和y。


縮放
X=K1*X0
Y=K2*Y0

錯(cuò)切(skew)

錯(cuò)切需要變換(MSKEW_X,MSKEW_Y),分別作用于水平錯(cuò)切和垂直錯(cuò)切;


錯(cuò)切
X=X0+K1*Y0
Y=K2*X0+Y0

旋轉(zhuǎn)(rotate)

當(dāng)要旋轉(zhuǎn) θ角度的時(shí)候,博客中計(jì)算了一遍,講了下邊矩陣變換數(shù)據(jù)的來(lái)歷,我看了一遍也記不住,還是及這個(gè)圖來(lái)的快。。。。


旋轉(zhuǎn)

平移(translate)

平移需要修改的是最后一列的前兩個(gè)數(shù)據(jù)(MTRANS_X,MTRANS_Y),分別作用在x和y 上。


平移

總結(jié)

看了上邊的幾種變換,其實(shí)就是對(duì)應(yīng)修改單位矩陣中的特定數(shù)值。比如說(shuō),要旋轉(zhuǎn),就要修改左上角四個(gè)數(shù)值,得到變換矩陣,拿變換矩陣跟原始矩陣相乘。平移,就是修改單位矩陣中最后一列的上邊兩個(gè)數(shù)值,如果你只想在x軸平移,那么只需要修改最后一列的第一個(gè)數(shù)據(jù)??戳松线叺臇|西,大概知道矩陣作用了,可是矩陣該怎么在實(shí)際代碼中使用呢?一步一步來(lái)

Matrix 矩陣復(fù)合原理

矩陣復(fù)合有三種,前乘(pre),后乘(post),設(shè)置(set)
為什么會(huì)有前乘和后乘的區(qū)別呢?
因?yàn)?/p>

矩陣乘法不滿足交換律,即 AB ≠ BA
矩陣乘法滿足結(jié)合律,即 (AB)C = A(BC)
矩陣與單位矩陣相乘結(jié)果不變,即 A * I = A

前乘(pre)

前乘就是原始矩陣在前邊,變換矩陣在后邊

M`=M*A

后乘(post)

后乘就是原始矩陣在后邊,變換矩陣在前邊

M`=S*A

設(shè)置(set)

設(shè)置不是矩陣的乘法,而是覆蓋原來(lái)的矩陣,使用設(shè)置之后會(huì)對(duì)之前的操作有影響。

幾個(gè)常見(jiàn)的錯(cuò)誤結(jié)論:

1.pre 是順序執(zhí)行,post 是逆序執(zhí)行
2.pre 是先執(zhí)行,而 post 是后執(zhí)行

其實(shí)前乘后乘執(zhí)行的順序,跟這句代碼所在的位置沒(méi)有關(guān)系。

下邊將一個(gè)遠(yuǎn)博客中的例子。
我們想講一個(gè)控件先平移到屏幕的中間,然后對(duì)控件做一系列縮放,錯(cuò)切,平移等等操作,最后我們?cè)賹⒖丶揭苹剡h(yuǎn)位置。
上面的操作我們可以使用三種方法實(shí)現(xiàn):

第一種前后兩個(gè)平移全部使用前乘(pre)

Matrix matrix=new Matrix();
matrix.preTranslate(200,200);
matrix.preRotate(angle);
matrix.preTranslate(-200,-200);

M`=M*T*R-T
新實(shí)例化的矩陣就是單位矩陣,所以這里M為原始矩陣,所以上邊的式子可以簡(jiǎn)化為
M`=*T*R
-T

第二種前后兩個(gè)平移全部使用后乘

Matrix matrix=new Matrix();
matrix.postTranslate(-200,-200);
matrix.postRotate(angle);
matrix.postTranslate(-200,-200);

化簡(jiǎn)公式為M`=T*R*-T*

混合使用前乘和后乘

Matrix matrix = new Matrix();
// 各種操作,旋轉(zhuǎn),縮放,錯(cuò)切等,可以執(zhí)行多次。
matrix.postTranslate(pivotX,pivotY);
matrix.preTranslate(-pivotX, -pivotY);

M' = TM ... -T = T ... *-T
這種方法是為了避免兩次平移被拉得太開(kāi),代碼量多的話,會(huì)容易漏寫(xiě)。

pre 和 post 就是用來(lái)調(diào)整乘法順序的,由于矩陣乘法不滿足交換律,所以前乘后乘的結(jié)果是不一樣的。

上面都是矩陣的基礎(chǔ)知識(shí)的理解,到底該怎么用。下邊開(kāi)始總結(jié):

Matrix的基本使用

先看一下Matrix的基礎(chǔ)方法

方法 解釋
Matrix (); 構(gòu)造方法,創(chuàng)建一個(gè)新的矩陣,為單位矩陣
Matrix (Matrix src); 構(gòu)造方法,對(duì)src矩陣進(jìn)行深拷貝,也就是創(chuàng)建一個(gè)跟src矩陣一毛一樣的矩陣。
equals 比較兩個(gè)Matrix的數(shù)值是否相同。
hashCode 獲取Matrix的哈希值。
toString 將Matrix轉(zhuǎn)換為字符串: Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
toShortString 將Matrix轉(zhuǎn)換為短字符串: [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
void set (Matrix src) 沒(méi)有返回值,有一個(gè)參數(shù),作用是將參數(shù)Matrix的數(shù)值復(fù)制到當(dāng)前Matrix中。如果參數(shù)為空,則重置當(dāng)前Matrix,相當(dāng)于reset()。
void reset () 重置當(dāng)前Matrix(將當(dāng)前Matrix重置為單位矩陣)。
void setValues (float[] values) setValues的參數(shù)是浮點(diǎn)型的一維數(shù)組,長(zhǎng)度需要大于9,拷貝數(shù)組中的前9位數(shù)值賦值給當(dāng)前Matrix。
void getValues (float[] values) 很顯然,getValues和setValues是一對(duì)方法,參數(shù)也是浮點(diǎn)型的一維數(shù)組,長(zhǎng)度需要大于9,將Matrix中的數(shù)值拷貝進(jìn)參數(shù)的前9位中。

數(shù)值計(jì)算方法

方法 解釋
void mapPoints (float[] pts) 計(jì)算一組點(diǎn)基于當(dāng)前Matrix變換后的位置,講計(jì)算后的矩陣數(shù)值存放到pts數(shù)組中
void mapPoints (float[] dst, float[] src) 與上個(gè)方法作用一樣,只不過(guò)是講計(jì)算后的結(jié)果存放到dst數(shù)組中,src不變
void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount) 作用和上邊兩個(gè)方法一致,只不過(guò)可以指定存儲(chǔ)的數(shù)組長(zhǎng)度。dstIndex表示目標(biāo)數(shù)據(jù)存儲(chǔ)位置起始下標(biāo),srcIndex表示原數(shù)據(jù)存儲(chǔ)起始下標(biāo),pointCount表示計(jì)算的點(diǎn)個(gè)數(shù)
float mapRadius (float radius) 測(cè)量半徑,由于圓可能會(huì)因?yàn)楫?huà)布變換變成橢圓,所以此處測(cè)量的是平均半徑。radius表示原半徑,返回的是經(jīng)過(guò)變換之后的半徑。
boolean mapRect (RectF rect) 測(cè)量rect并將測(cè)量結(jié)果放入rect中,返回值是判斷矩形經(jīng)過(guò)變換后是否仍為矩形
boolean mapRect (RectF dst, RectF src) 測(cè)量src并將測(cè)量結(jié)果放入dst中,返回值是判斷矩形經(jīng)過(guò)變換后是否仍為矩形
mapVectors 和上邊mapPoints方法類似,不過(guò)這里測(cè)量的是向量,也就是說(shuō)平移操作不會(huì)影響結(jié)果

set/pre/post控制平移(translate)、縮放(scale)、旋轉(zhuǎn)(rotate)、 錯(cuò)切(skew) 的變換

上邊在講Matrix原理的時(shí)候就已經(jīng)對(duì)這些方法進(jìn)行過(guò)講解。

特殊方法

setPoluToPoly()

boolean setPolyToPoly (
        float[] src,    // 原始數(shù)組 src [x,y],存儲(chǔ)內(nèi)容為一組點(diǎn)
        int srcIndex,   // 原始數(shù)組開(kāi)始位置
        float[] dst,    // 目標(biāo)數(shù)組 dst [x,y],存儲(chǔ)內(nèi)容為一組點(diǎn)
        int dstIndex,   // 目標(biāo)數(shù)組開(kāi)始位置
        int pointCount) // 測(cè)控點(diǎn)的數(shù)量 取值范圍是: 0到4

這個(gè)方法是控制兩部分進(jìn)行變換的。一是進(jìn)行變換的點(diǎn)的數(shù)據(jù),而是變化的點(diǎn)數(shù)。
srcIndex定義要變換哪些點(diǎn),中心點(diǎn)可以,四邊形四邊中點(diǎn)可以,四邊形四個(gè)角可以,這里去的是容易獲取的點(diǎn);dstIndex表示根據(jù)srcIndex變換后的點(diǎn);pointCount是變換點(diǎn)的數(shù)量;比如說(shuō)你上邊定義了四個(gè)點(diǎn)的變化,但是pointCount是1,那么結(jié)果可能就不是你想要得到的。

pointCount 摘要
0 相當(dāng)于reset
1 相當(dāng)于translate
2 可以進(jìn)行 縮放、旋轉(zhuǎn)、平移 變換
3 可以進(jìn)行 縮放、旋轉(zhuǎn)、平移、錯(cuò)切 變換
4 可以進(jìn)行 縮放、旋轉(zhuǎn)、平移、錯(cuò)切以及任何形變

這個(gè)方法還是很有必要仔細(xì)研究的,具體代碼我就不貼了,原博客中有詳細(xì)講解

setRectToRect

這個(gè)方法的作用主要就是填充的模式,比如一張圖片要放到父空間中,圖片尺寸比較小,那這張圖片是要放在左上角,還是右下角,還是中間,還是鋪滿呢?setRectToRect方法就是控制這些操作的。

boolean setRectToRect (RectF src,           // 源區(qū)域
                RectF dst,                  // 目標(biāo)區(qū)域
                Matrix.ScaleToFit stf)      // 縮放適配模式
模式 摘要
CENTER 居中,對(duì)src等比例縮放,將其居中放置在dst中。
START 頂部,對(duì)src等比例縮放,將其放置在dst的左上角。
END 底部,對(duì)src等比例縮放,將其放置在dst的右下角。
FILL 充滿,拉伸src的寬和高,使其完全填充滿dst。

rectStaysRect

判斷舉行變換之后是否還是矩形。

invert

獲取矩陣的逆矩陣
boolean invert (Matrix inverse)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容