這裏咱們會詳細講解matrix的各個方法,以及它的用法。matrix叫作矩陣,在前面講解 ColorFilter 的文章中,咱們講解了ColorMatrix,他是一個4*5的矩陣。而這裏,咱們講解的Matrix不是用於處理顏色的,而是處理圖形的。他是一個3*3的矩陣。html
先看看matrix的矩陣是什麼樣子的:canvas
這裏能夠查看Matrix的代碼獲得。那麼這個矩陣分別表明了什麼呢,這裏經過他們的名字能夠看出,scale是縮放,skew是錯切(canvas變換中有講過),trans是平移,persp表明透視(官方文檔中,也沒有詳細講解,透視在這裏只作簡單介紹)。這裏須要把矩陣根據他們的做用劃分爲4塊:api
如上圖所示,這四塊區域各有做用。後面會詳細講解各個做用,先來看看這個矩陣是如何影響圖像的。先看看屏幕的座標系:數組
看上圖,這裏表示了屏幕的座標系,其中的x,y軸是你們所熟知的,可是其實,一個物體他是存在於一個三維空間的,因此必然會有z軸。咱們的屏幕,就像是一個窗口,透過它,咱們看到了屏幕後面的世界,那裏面有各類物體,咱們看到的是映射在x,y平面上的一個投射圖像。屏幕就像是一個鏡頭同樣,將裏面的物體映射到x,y平面上,成爲一個二維的圖像。那麼若是,咱們把屏幕這個鏡頭沿着z軸,拉遠或者拉進,那麼圖像會有什麼變化呢,確定會變小或者變大。就比如坐在飛機上透過窗口看地面的汽車,和在地面上看到的大小是不一樣的。app
結論就是,在屏幕上顯示的像素,不只僅有x,y座標,其實還有z軸的影響。因此這裏對應的像素描述由一個3行一列的矩陣來表示:ide
x,y分別表明x,y軸上的座標,而1表明屏幕在z軸上的座標爲默認的。若是將1變大,那麼屏幕會拉遠, 圖形會變小。函數
如今咱們來看看matrix怎麼做用於每一個像素的值。這裏須要用到矩陣的乘法,首先須要明確的是,矩陣的前乘和後乘是不相同的,也就是說不知足乘法交換律。post
這裏咱們經過一個旋轉變換來看看原理,其實一張圖片圍繞一個點旋轉,也就是全部的點都圍繞一個點旋轉,因此只須要關注一個點的狀況便可:spa
假定有一個點 ,相對座標原點順時針旋轉後的情形,同時假定P點離座標原點的距離爲r,以下圖:.net
那麼就有:
換作矩陣運算就以下圖:
從這裏就能夠看出,矩陣中的值,是如何做用於像素點的x,y座標以及z軸遠近。
同時,能夠看到,上面的矩陣四塊區域的切分也是由於矩陣乘法的操做決定的,因爲這裏的乘法運算中,左上角的四個值,能夠和x,y值作乘法運算,因此能夠影響到旋轉等操做,而右上角的模塊,只能作加法,因此只能影響到平移。右下角的模塊主要管z軸,天然就能夠進行等比的縮放了,左下角的模塊通常不去動他,不然會把x,y值加入到z軸中來,會不可控。
講解完了matrix做用於像素點的原理以後,咱們逐個講解它的方法。
public Matrix() public Matrix(Matrix src)
構造函數有兩個,第一個是直接建立一個單位矩陣,第二個是根據提供的矩陣建立一個新的矩陣(採用deep copy)
單位矩陣以下:
public boolean isIdentity()//判斷是不是單位矩陣 public boolean isAffine()//判斷是不是仿射矩陣
是不是單位矩陣很簡單,就不作講解了,這裏是不是仿射矩陣可能你們很差理解。
首先來看看什麼是仿射變換。仿射變換其實就是二維座標到二維座標的線性變換,保持二維圖形的「平直性」(即變換後直線仍是直線不會打彎,圓弧仍是圓弧)和「平行性」(指保持二維圖形間的相對位置關係不變,平行線仍是平行線,而直線上點的位置順序不變),能夠經過一系列的原子變換的複合來實現,原子變換就包括:平移、縮放、翻轉、旋轉和錯切。這裏除了透視能夠改變z軸之外,其餘的變換基本都是上述的原子變換,因此,只要最後一行是0,0,1則是仿射矩陣。
public boolean rectStaysRect()
判斷該矩陣是否能夠將一個矩形依然變換爲一個矩形。當矩陣是單位矩陣,或者只進行平移,縮放,以及旋轉90度的倍數的時候,返回true。
public void reset()
重置矩陣爲單位矩陣。
public void setTranslate(float dx, float dy)
設置平移效果,參數分別是x,y上的平移量。
效果圖以下:
代碼以下:
Matrix matrix = new Matrix(); canvas.drawBitmap(bitmap, matrix, paint); matrix.setTranslate(100, 1000); canvas.drawBitmap(bitmap, matrix, paint);
public void setScale(float sx, float sy, float px, float py) public void setScale(float sx, float sy)
兩個方法都是設置縮放到matrix中,sx,sy表明了縮放的倍數,px,py表明縮放的中心。這裏跟上面比較相似不作講解了。
public void setRotate(float degrees, float px, float py) public void setRotate(float degrees)
和上面相似,再也不講解。
public void setSinCos(float sinValue, float cosValue, float px, float py) public void setSinCos(float sinValue, float cosValue)
這個方法乍一看可能有點蒙,其實在前面的原理中,咱們講解了一個旋轉的例子,他最終的矩陣效果是這樣的:
其實旋轉,就是使用了這樣的matrix,顯而易見,這裏的參數就清晰了。
sinValue:對應圖中的sin值
cosValue:對應cos值
px:中心的x座標
py:中心的y座標
看一個示例,咱們把圖像旋轉90度,那麼90度對應的sin和cos分別是1和0。
看代碼以下:
Matrixmatrix = new Matrix(); matrix.setSinCos(1, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2); canvas.drawBitmap(bitmap, matrix, paint);
public void setSkew(float kx, float ky, float px, float py) public void setSkew(float kx, float ky)
錯切,這裏kx,ky分別表明了x,y上的錯切因子,px,py表明了錯切的中心。不瞭解錯切了在前面canvas變換中去查看,這裏再也不講解。
public boolean setConcat(Matrix a,Matrix b)
將當前matrix的值變爲a和b的乘積,它的意義在下面的 進階方法中來探討。
上面的基本方法中,有關於變換的set方法均可以帶來不一樣的效果,可是每一個set都會把上個效果清除掉,例如依次調用了setSkew,setTranslate,那麼最終只有setTranslate會起做用,那麼如何才和將兩種效果複合呢。Matrix給咱們提供了不少方法。可是主要都是2類:
preXXXX:以pre開頭,例如preTranslate
postXXXX:以post開頭,例如postScale
他們分別表明了前乘,和後乘。看一段代碼:
Matrix matrix = new Matrix(); matrix.setTranslate(100, 1000); matrix.preScale(0.5f, 0.5f);
這裏matrix前乘了一個scale矩陣,換算成數學式以下:
從上面能夠看出,最終得出的matrix既包含了縮放信息也有平移信息。
後乘天然就是matrix在後面,而縮放矩陣在前面,因爲矩陣先後乘並不等價,也就致使了他們的效果不一樣。咱們來看看後乘的結果:
能夠看到,結果跟上面不一樣,而且這也不是咱們想要的結果,這裏縮放沒有更改,可是平移被減半了,換句話說,平移的距離也被縮放了。因此須要注意先後乘法的關係。
來看看他們對應的效果圖:
前乘:
後乘:
能夠明顯看到,後乘的平移距離受了影響。
瞭解清除了先後乘的意義,在使用的過程當中,多個效果的疊加時,同樣要注意,不然效果達不到預期。
matrix除了上面的方法外,還有一些其餘的方法,這裏依次解析
public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf)
將rect變換成rect,上面的rectStaysRect已經說過,要保持rect只能作縮放平移和選擇90度的倍數,那麼這裏其實也是同樣,只是這幾種變化,這裏經過stf參數來控制。
ScaleToFit 有以下四個值:
FILL: 可能會變換矩形的長寬比,保證變換和目標矩陣長寬一致。
START:保持座標變換前矩形的長寬比,並最大限度的填充變換後的矩形。至少有一邊和目標矩形重疊。左上對齊。
CENTER: 保持座標變換前矩形的長寬比,並最大限度的填充變換後的矩形。至少有一邊和目標矩形重疊。
END:保持座標變換前矩形的長寬比,並最大限度的填充變換後的矩形。至少有一邊和目標矩形重疊。右下對齊。
這裏使用谷歌的api demo的圖片做爲例子:
public boolean setPolyToPoly(float[] src, int srcIndex,float[] dst, int dstIndex,int pointCount)
經過指定的0-4個點,原始座標以及變化後的座標,來獲得一個變換矩陣。若是指定0個點則沒有效果。
下面經過例子分別說明1到4個點的能夠達到的效果:
這裏寫代碼片
##### 1個點,平移
只指定一個點,能夠達到平移效果:
代碼以下:
float[] src = {0, 0}; int DX = 300; float[] dst = {0 + DX, 0 + DX}; matrix.setPolyToPoly(src, 0, dst, 0, 1); canvas.drawBitmap(bitmap, matrix, paint);
兩個點,能夠達到旋轉效果或者縮放效果,縮放比較簡單,這裏咱們來看旋轉效果,一個點指定中心,一點指出旋轉的效果
代碼以下
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);
圖片的中心點做爲旋轉的中心,先後不變,右上角變化到了下方,因此致使圖片旋轉了90度。
使用3個點,能夠產生錯切效果,指定3個頂點,一個固定,另外兩個移動。
看圖:
代碼以下:
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);
透視就是觀察的角度變化了。致使投射到平面上的二維圖像變化了。
咱們看下面的例子,更容易理解:
圖片看起來好像傾斜了,實現特別簡單:
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);
能夠看到,只是把左右兩個頂點往裏面收攏了,這樣就得出了一個有3d效果的透視圖。
public boolean invert(Matrix inverse)
反轉當前矩陣,若是能反轉就返回true並將反轉後的值寫入inverse,不然返回false。當前矩陣*inverse=單位矩陣。
反轉先後有什麼效果,咱們來看看示例:
能夠看到,反轉以後,實際上是對效果的一種反轉。
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)
映射點的值到指定的數組中,這個方法能夠在矩陣變換之後,給出指定點的值。
dst:指定寫入的數組
dstIndex:寫入的起始索引,x,y兩個座標算做一對,索引的單位是對,也就是通過兩個值才加1
src:指定要計算的點
srcIndex:要計算的點的索引
pointCount:須要計算的點的個數,每一個點有兩個值,x和y。
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基本相似,這裏是將一個矩陣做用於一個向量,因爲向量的平移先後是相等的,因此這個方法不會對translate相關的方法產生反應,若是隻是調用了translate相關的方法,那麼獲得的值和本來的一致。
public boolean mapRect(RectF dst, RectF src) public boolean mapRect(RectF rect)
返回值便是調用的rectStaysRect(),這個方法前面有講過,這裏把src中指定的矩形的左上角和右下角的兩個點的座標,寫入dst中。
public float mapRadius(float radius)
返回一個圓圈半徑的平均值,將matrix做用於一個指定radius半徑的圓,隨後返回的平均半徑。
以上基本解析完畢了全部matrix的方法,以及一些高階用法,本篇文章就到這裏