一、矩陣的定義
二焊切、矩陣與矩陣的乘法
矩陣的乘法滿足以下運(yùn)算律:
結(jié)合律,分配律,
但是矩陣乘法不滿足交換律祸轮。
更詳細(xì)的矩陣知識(shí):
矩陣的運(yùn)算及其運(yùn)算規(guī)則
三、Matrix---------圖形矩陣
1.Matrix 的結(jié)構(gòu)
Matrix 是 Android SDK 提供的一個(gè)矩陣類(lèi)哀峻,它代表一個(gè) 3 X 3 的矩陣涡相。 Matrix 提供了讓我們獲得 Matrix 值的 API —— getValues。如果我們將這個(gè) float 排成直觀的矩陣格式剩蟀,那它將是下面這樣子的
- 構(gòu)造函數(shù)
public Matrix()
public Matrix(Matrix src)
構(gòu)造函數(shù)有兩個(gè)催蝗,第一個(gè)是直接創(chuàng)建一個(gè)單位矩陣,第二個(gè)是根據(jù)提供的矩陣創(chuàng)建一個(gè)新的矩陣(采用深copy)育特。
- isIdentity與isAffine
public boolean isIdentity()//判斷是否是單位矩陣
public boolean isAffine()//判斷是否是仿射矩陣
仿射變換其實(shí)就是二維坐標(biāo)到二維坐標(biāo)的線性變換丙号,保持二維圖形的“平直性”(即變換后直線還是直線不會(huì)打彎,圓弧還是圓荤衷)和“平行性”(指保持二維圖形間的相對(duì)位置關(guān)系不變犬缨,平行線還是平行線,而直線上點(diǎn)的位置順序不變)棉浸,可以通過(guò)一系列的原子變換的復(fù)合來(lái)實(shí)現(xiàn)怀薛,原子變換就包括:平移、縮放迷郑、翻轉(zhuǎn)乾戏、旋轉(zhuǎn)和錯(cuò)切迂苛。這里除了透視可以改變z軸以外,其他的變換基本都是上述的原子變換鼓择,所以三幻,只要最后一行是0,0,1則是仿射矩陣。
- rectStaysRect
public boolean rectStaysRect()
判斷該矩陣是否可以將一個(gè)矩形依然變換為一個(gè)矩形呐能。當(dāng)矩陣是單位矩陣念搬,或者只進(jìn)行平移,縮放摆出,以及旋轉(zhuǎn)90度的倍數(shù)的時(shí)候朗徊,返回true。
reset
public void reset()
重置矩陣為單位矩陣偎漫。setTranslate
public void setTranslate(float dx, float dy)
設(shè)置平移效果爷恳,參數(shù)分別是x,y上的平移量象踊。setScale
public void setScale(float sx, float sy, float px, float py)
public void setScale(float sx, float sy)
兩個(gè)方法都是設(shè)置縮放到matrix中温亲,sx,sy代表了縮放的倍數(shù)杯矩,px,py代表縮放的中心栈虚。這里跟上面比較類(lèi)似不做講解了。-
setRotate
public void setRotate(float degrees, float px, float py)
public void setRotate(float degrees)
例如:
原圖(以下實(shí)例的所有原圖):
//以圖片為原點(diǎn)中心史隆,
Matrix matrix = new Matrix();
matrix.setRotate(1, 0, 0, 0);
canvas.drawBitmap(bitmap, matrix, paint);
//以圖片為旋轉(zhuǎn)中心魂务,
Matrix matrix = new Matrix();
matrix.setRotate(1, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
canvas.drawBitmap(bitmap, matrix, paint);
- setSinCos
public void setSinCos(float sinValue, float cosValue, float px, float py)
public void setSinCos(float sinValue, float cosValue)
sinValue:對(duì)應(yīng)圖中的sin值
cosValue:對(duì)應(yīng)cos值
px:中心的x坐標(biāo)
py:中心的y坐標(biāo)
如果我們把圖像旋轉(zhuǎn)90度,那么90度對(duì)應(yīng)的sin和cos分別是1和0泌射。
看代碼如下:
Matrixmatrix = new Matrix();
matrix.setSinCos(1, 0, 0, 0);
canvas.drawBitmap(bitmap, matrix, paint);
-setSkew
public void setSkew(float kx, float ky, float px, float py)
public void setSkew(float kx, float ky)
錯(cuò)切粘姜,這里kx,ky分別代表了x熔酷,y上的錯(cuò)切因子孤紧,px,py代表了錯(cuò)切的中心纯陨。
-
setConcat
public boolean setConcat(Matrix a,Matrix b)
將當(dāng)前matrix的值變?yōu)閍和b的乘積
Matrix matrix_a = new Matrix();
matrix1.setValues(new float[]{0.5f, 0, 0, 0, 0.5f, 0, 0, 0, 1.0f});//縮小0.5
Matrix matrix_b = new Matrix();
matrix2.setValues(new float[]{1, 0, 100, 0, 1, 100, 0, 0, 1.0f});//平移100
matrix.setConcat(matrix_a,matrix_b);
canvas.drawBitmap(bitmap, matrix, paint);
注意哦!矩陣a和矩陣b的前乘留储,后乘是不一樣的翼抠,如下圖可以看到
2. 進(jìn)階方法解析
Matrix主要用于對(duì)平面進(jìn)行平移(Translate),縮放(Scale)获讳,旋轉(zhuǎn)(Rotate)以及斜切(Skew)操作阴颖。
為簡(jiǎn)化矩陣變換,Android封裝了一系列方法來(lái)進(jìn)行矩陣變換丐膝;其中包括:
set系列方法:setTranslate量愧,setScale钾菊,setRotate,setSkew偎肃;設(shè)置煞烫,會(huì)覆蓋之前的參數(shù)。
pre系列方法:preTranslate累颂,preScale滞详,preRotate,preSkew紊馏;矩陣先乘料饥,如M' = M * T(dx, dy)。
post系列方法:postTranslate朱监,postScale岸啡,postRotate,postSkew赫编;矩陣后乘巡蘸,如M' = T(dx, dy) * M。
通過(guò)將變換矩陣與原始矩陣相乘來(lái)達(dá)到變換的目的沛慢,例如:
平移(x'=x+tx赡若;y'=y+ty)
縮放(x'=sx * x;y'=sy * y)
旋轉(zhuǎn)(x'=cosβ * x-sinβ * y团甲;y'=sinβ * x+cosβ)
選擇需要用到如下的三角函數(shù)的公式:
①sin(α+β)=sinαcosβ+cosαsinβ
②cos(α+β)=cosαcosβ-sinαsinβ
公式①可以由單位圓方法或托勒密定理推導(dǎo)出來(lái)逾冬。
斜切(x'=x+k1 * y;y'=k2 * x+y)
如下代碼:
Matrix matrix = new Matrix();
matrix.setTranslate(100, 1000);
matrix.preScale(0.5f, 0.5f);
這里matrix前乘了一個(gè)scale矩陣躺苦,換算成數(shù)學(xué)式如下:
反之身腻,
Matrix matrix = new Matrix();
matrix.setTranslate(100, 1000);
matrix.postScale(0.5f, 0.5f);
這里matrix后乘了一個(gè)scale矩陣,換算成數(shù)學(xué)式如下:
實(shí)例 1
Matrix matrix = new Matrix();
matrix.preScale(0.5f, 0.5f);//縮放
matrix.preRotate(180);//旋轉(zhuǎn)
//下面的Translate組合是為了將縮放和旋轉(zhuǎn)的基點(diǎn)移動(dòng)到整個(gè)圖像的中心匹厘,不然系統(tǒng)默認(rèn)是以圖像的左上角作為基點(diǎn)
matrix.preTranslate(-mBitmapWidth()/2, -mBitmapHeight()/2);
matrix.postTranslate(mBitmapWidth()/2, mBitmapHeight()/2);
實(shí)例 2
matrix.reset();
//這段代碼的執(zhí)行順序:translate(50f, 50f) -> scale(1.5f, 1.5f) -> scale(0.5f, 0.5f) -> translate(50f, 50f)
matrix.preScale(1.5f, 1.5f);
matrix.preTranslate(50f, 50f);
matrix.postScale(0.5f, 0.5f);
matrix.postTranslate(50f, 50f);
3.其他方法解析
matrix除了上面的方法外嘀趟,還有一些其他的方法,
(1) setRectToRect
public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf)
將rect變換成rect愈诚,上面的rectStaysRect已經(jīng)說(shuō)過(guò)她按,要保持rect只能做縮放平移和選擇90度的倍數(shù),那么這里其實(shí)也是一樣炕柔,只是這幾種變化酌泰,這里通過(guò)stf參數(shù)來(lái)控制。
ScaleToFit 有如下四個(gè)值:
FILL: 可能會(huì)變換矩形的長(zhǎng)寬比匕累,保證變換和目標(biāo)矩陣長(zhǎng)寬一致陵刹。
START:保持坐標(biāo)變換前矩形的長(zhǎng)寬比,并最大限度的填充變換后的矩形欢嘿。至少有一邊和目標(biāo)矩形重疊衰琐。左上對(duì)齊也糊。
CENTER: 保持坐標(biāo)變換前矩形的長(zhǎng)寬比,并最大限度的填充變換后的矩形羡宙。至少有一邊和目標(biāo)矩形重疊狸剃。
END:保持坐標(biāo)變換前矩形的長(zhǎng)寬比,并最大限度的填充變換后的矩形辛辨。至少有一邊和目標(biāo)矩形重疊捕捂。右下對(duì)齊。
這里使用谷歌的api demo的圖片作為例子:
(2) setPolyToPoly
public boolean setPolyToPoly(float[] src, int srcIndex,float[] dst, int dstIndex,int pointCount)
通過(guò)指定的0-4個(gè)點(diǎn)斗搞,原始坐標(biāo)以及變化后的坐標(biāo)指攒,來(lái)得到一個(gè)變換矩陣。如果指定0個(gè)點(diǎn)則沒(méi)有效果僻焚。
下面通過(guò)例子分別說(shuō)明1到4個(gè)點(diǎn)的可以達(dá)到的效果:
1個(gè)點(diǎn)-----平移
只指定一個(gè)點(diǎn)允悦,可以達(dá)到平移效果:
float[] src = {0, 0};
int DX = 100;
float[] dst = {0 + DX, 0 + DX};
matrix.setPolyToPoly(src, 0, dst, 0, 1);
canvas.drawBitmap(bitmap, matrix, paint);
2個(gè)點(diǎn)-----旋轉(zhuǎn)或者縮放
兩個(gè)點(diǎn),可以達(dá)到旋轉(zhuǎn)效果或者縮放效果虑啤,縮放比較簡(jiǎn)單隙弛,這里我們來(lái)看旋轉(zhuǎn)效果,一個(gè)點(diǎn)指定中心狞山,一點(diǎn)指出旋轉(zhuǎn)的效果,代碼如下:
int bw = bitmap.getWidth();
int bh = bitmap.getHeight();
float[] src = {bw / 2, bh / 2, bw, 0};
float[] dst = {bw / 2, bh / 2, bw / 2 + bh / 2, bh / 2 + bw / 2};
matrix.setPolyToPoly(src, 0, dst, 0, 2);
canvas.drawBitmap(bitmap, matrix, paint);
圖片的中心點(diǎn)作為旋轉(zhuǎn)的中心全闷,前后不變,右上角變化到了下方萍启,所以導(dǎo)致圖片旋轉(zhuǎn)了90度总珠。
3個(gè)點(diǎn)------錯(cuò)切
使用3個(gè)點(diǎn),可以產(chǎn)生錯(cuò)切效果勘纯,指定3個(gè)頂點(diǎn)局服,一個(gè)固定,另外兩個(gè)移動(dòng)驳遵。 代碼如下:
Matrix matrix = new Matrix();
int bw = bitmap.getWidth();
int bh = bitmap.getHeight();
float[] src = {0,0, 0, bh,bw,bh};
float[] dst = {0, 0, 200, bh, bw + 200, bh};
matrix.setPolyToPoly(src, 0, dst, 0, 3);
canvas.drawBitmap(bitmap, matrix, paint);
4個(gè)點(diǎn)------透視
透視就是觀察的角度變化了淫奔。導(dǎo)致投射到平面上的二維圖像變化了。
Matrix matrix = new Matrix();
int bw = bitmap.getWidth();
int bh = bitmap.getHeight();
float[] src = {0, 0, 0, bh, bw, bh, bw, 0};
int DX = 100;
float[] dst = {0 + DX, 0, 0, bh, bw, bh, bw - DX, 0};
matrix.setPolyToPoly(src, 0, dst, 0, 4);
canvas.drawBitmap(bitmap, matrix, paint);
可以看到堤结,只是把左右兩個(gè)頂點(diǎn)往里面收攏了唆迁,這樣就得出了一個(gè)有3d效果的透視圖。
(3) invert
public boolean invert(Matrix inverse)
反轉(zhuǎn)當(dāng)前矩陣竞穷,如果能反轉(zhuǎn)就返回true并將反轉(zhuǎn)后的值寫(xiě)入inverse唐责,否則返回false。當(dāng)前矩陣inverse=單位矩陣来庭。
反轉(zhuǎn)前后有什么效果妒蔚,我們來(lái)看看示例:
可以看到穿挨,反轉(zhuǎn)之后月弛,其實(shí)是對(duì)效果的一種反轉(zhuǎn)肴盏。
(4) mapPoints
public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,int pointCount)
public void mapPoints(float[] dst, float[] src)
public void mapPoints(float[] pts)
映射點(diǎn)的值到指定的數(shù)組中,這個(gè)方法可以在矩陣變換以后帽衙,給出指定點(diǎn)的值菜皂。
dst:指定寫(xiě)入的數(shù)組
dstIndex:寫(xiě)入的起始索引,x厉萝,y兩個(gè)坐標(biāo)算作一對(duì)恍飘,索引的單位是對(duì),也就是經(jīng)過(guò)兩個(gè)值才加1
src:指定要計(jì)算的點(diǎn)
srcIndex:要計(jì)算的點(diǎn)的索引
pointCount:需要計(jì)算的點(diǎn)的個(gè)數(shù)谴垫,每個(gè)點(diǎn)有兩個(gè)值章母,x和y。
(5) mapVectors
public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,int vectorCount)
public void mapVectors(float[] dst, float[] src)
public void mapVectors(float[] vecs)
與上面的mapPoionts基本類(lèi)似翩剪,這里是將一個(gè)矩陣作用于一個(gè)向量乳怎,由于向量的平移前后是相等的,所以這個(gè)方法不會(huì)對(duì)translate相關(guān)的方法產(chǎn)生反應(yīng)前弯,如果只是調(diào)用了translate相關(guān)的方法蚪缀,那么得到的值和原本的一致。
(6) mapRect
public boolean mapRect(RectF dst, RectF src)
public boolean mapRect(RectF rect)
返回值即是調(diào)用的rectStaysRect()恕出,這個(gè)方法前面有講過(guò)询枚,這里把src中指定的矩形的左上角和右下角的兩個(gè)點(diǎn)的坐標(biāo),寫(xiě)入dst中浙巫。
(7) mapRadius
public float mapRadius(float radius)
返回一個(gè)圓圈半徑的平均值金蜀,將matrix作用于一個(gè)指定radius半徑的圓,隨后返回的平均半徑狈醉。