圖形矩陣-----Matrix

一、矩陣的定義

二焊切、矩陣與矩陣的乘法

矩陣的乘法滿足以下運(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í)例的所有原圖):

    實(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);
圖片為原點(diǎn)中心

圖片為旋轉(zhuǎn)中心
  • 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)


setSinCos

如果我們把圖像旋轉(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的前乘留储,后乘是不一樣的翼抠,如下圖可以看到


a * b
b * a

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β)

旋轉(zhuǎn)

選擇需要用到如下的三角函數(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í)例1 效果

實(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);
公式

實(shí)例 2 效果

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半徑的圓,隨后返回的平均半徑狈醉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末廉油,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子苗傅,更是在濱河造成了極大的恐慌抒线,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渣慕,死亡現(xiàn)場(chǎng)離奇詭異嘶炭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)逊桦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)眨猎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人强经,你說(shuō)我怎么就攤上這事睡陪。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵兰迫,是天一觀的道長(zhǎng)信殊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)汁果,這世上最難降的妖魔是什么涡拘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮据德,結(jié)果婚禮上鳄乏,老公的妹妹穿的比我還像新娘。我一直安慰自己棘利,他們只是感情好橱野,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著善玫,像睡著了一般仲吏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝌焚,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天裹唆,我揣著相機(jī)與錄音,去河邊找鬼只洒。 笑死许帐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毕谴。 我是一名探鬼主播成畦,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涝开!你這毒婦竟也來(lái)了循帐?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤舀武,失蹤者是張志新(化名)和其女友劉穎拄养,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體银舱,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘪匿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寻馏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棋弥。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖诚欠,靈堂內(nèi)的尸體忽然破棺而出顽染,到底是詐尸還是另有隱情漾岳,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布粉寞,位于F島的核電站蝗羊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏仁锯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一翔悠、第九天 我趴在偏房一處隱蔽的房頂上張望业崖。 院中可真熱鬧,春花似錦蓄愁、人聲如沸双炕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妇斤。三九已至,卻和暖如春丹拯,著一層夾襖步出監(jiān)牢的瞬間站超,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工乖酬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留死相,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓咬像,卻偏偏與公主長(zhǎng)得像算撮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子县昂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容