android.graphics.Matrix詳解

Matrix類包含了一個3x3的矩陣用來改變座標,它沒有一個構造器來初始化它裏邊的內容,所以創建實例後需要調用reset()方法生成一個標準matrix,或者調用set..一類的函數,比如setTranslate, setRotate,,該函數將會決定matrix如何來改變座標。SDK裏邊沒有講述Matrix的3x3矩陣是如何改變點的座標值的,但是我在代碼裏邊通過打印那9個點的值時,大致可以得到如下結論,9個值[a,b,c,d,e,f,g,h,i],座標[x,y],當g=0,h=0,i=1,的時候,座標是這樣變換的,x'=a*x+b*y+c;y'=d*x+e*y+f;當調用setTranslate(10,20)之後,matrix的值就變成[1,0,10,0,1,20,0,0,1];這其實還是沒有脫離矩陣乘法,只是不知道後三位是如何應用的。瞭解這個對後邊的連接矩陣的理解有好處,連接矩陣其實就是兩個矩陣相乘後得到的新矩陣。

public Matrix()

創建一個標準矩陣,應用後點的座標不會有任何改變

public Matrix(Matrix src)

創建一個src的深度複製,改變規則與src一致

 

public boolean equals(Object obj)

如果obj爲Matrix並且它的值與當前Matrix對象相等的會將會返回true

public void getValues(float[] values)

獲取matrix的那9個值

public boolean invert(Matrix inverse)

將當前矩陣反轉,並且反轉後的值存入inverse中,如果當前矩陣不能反轉,那麼inverse不變,返回false,反轉規則應該是滿足 當前矩陣*inverse=標準矩陣,標準矩陣爲[1,0,0,0,1,0,0,0,1];不過其實也不用想得那麼複雜,比如當前matrix是setTranslate(10,20),那麼反轉後的matrix就是setTranslate(-10,-20);

public boolean isIdentity()

判斷當前矩陣是否爲標準矩陣,這個函數比if (getType() == 0)運行的可能更快一些

public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, int pointCount)

用當前矩陣改變src中的點的座標,然後將改變後的值對應的存入dst數組中,其中pointCount表示點的數目,(x,y)=(src[2*k],src[2*k+1])表示一個點的座標,k取整數值,安卓中用數組存儲點的座標值的時候都是按如此法則存儲的。

public void mapPoints(float[] pts)

用當前矩陣改變pts中的值,然後存儲在pts中,同上,pts也是存儲點的座標的數組

public void mapPoints(float[] dst, float[] src)

用當前矩陣改變src的值,並且存儲到數組dst中

public float mapRadius(float radius)

將一個半徑爲radius的圓的所有點座標用matrix進行變換後,計算出該圓的半徑並且返回該值。注意:要得到正確的值該圓默認是有中心的,個人注:說實話不明白這個函數有什麼用

public boolean mapRect(RectF dst,RectF src)

用matrix改變src的4個頂點的座標,並將改變後的座標調整後存儲到dst中,(RectF只能存儲改變後的左上角和右下角座標,所以需要調整),返回的值跟rectStaysRect()一樣,從字面意思可以認爲src改變後仍然是RectF,那麼就返回true

public boolean mapRect(RectF rect)

用matrix改變rect的4個頂點的座標,並將改變後的座標調整後存儲到rect當中

public void mapVectors(float[] dst, float[] src)

用matrix改變dst中的向量值並且存儲到src當中,注意:setTranslate(x,y)這樣的matrix調用了這個函數後不會有任何反應,這樣的matrix應該調用mapPoints

public void mapVectors(float[] vecs)

用matrix改變vecs中的值並且存儲到vecs當中,同上,注意:setTranslate(x,y)這樣的matrix調用了這個函數後不會有任何反應,這樣的matrix應該調用mapPoints

public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int vectorCount)

同上,只不過vectorCount表示向量的數目,dstIndex,srcIndex分別表示各自的起始位置

 

public boolean postConcat(Matrix other)

將當前的matrix連接到other之後,並且將連接後的值寫入當前matrix。 M‘=other*M,連接後變換的效果,相當於先變換M,然後在other變換

public boolean postRotate(float degrees)

相當於這樣:Matrix other=newMatrix();other.setRotate(degrees);postConcat(other);

先創建設置一個以0,0爲原點旋轉degrees度的矩陣other,然後將當前的matrix連接到other之後,並且將連接後的值寫入當前matrix。

public boolean postRotate(float degrees, float px, float py)

同上,不過改成這樣Matrix other=newMatrix();other.setRotate(degrees,px,py);postConcat(other);

public boolean postScale(float sx, float sy)

同上,無非是改成other.setScale(sx,sy);

public boolean postScale(float sx, float sy, float px, float py)

同上

public boolean postSkew(float kx, float ky)

public boolean postSkew(float kx, float ky, float px, float py)

public boolean postTranslate(float dx, float dy)

都是一樣的,不過是創建的other有所不一樣而已

public boolean preConcat(Matrix other)

public boolean preRotate(float degrees)

public boolean preRotate(float degrees, float px, float py)

public boolean preScale(float sx, float sy)

public boolean preScale(float sx, float sy, float px, float py)

public boolean preSkew(float kx, float ky)

public boolean preSkew(float kx, float ky, float px, float py)

public boolean preTranslate(float dx, float dy)

同上邊對應的函數功能類似,無非是other被連接在當前matrix之後,然後將連接後的值寫入當前matrix當中

public boolean rectStaysRect()

如果該matrix可以將rectF變換成rectF,那麼該函數返回true,在標準變換,伸縮變換,平移變換,和多個90度的旋轉變換時,該函數是返回true的

public void reset()

將當前matrix設置爲標準矩陣

public void set(Matrix src)

將src的內容深度複製給當前矩陣,如果src爲null,那麼當前矩陣變爲標準矩陣

public boolean setConcat(Matrix a,Matrix b)

將當前matrix的值變爲a和b的乘積

public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)

將當前matrix的值設置爲這樣的值,對src變換後可以得到dst的數據,pointCount表示點的數目,只能是0-4。設置成功返回true

public boolean setRectToRect(RectF src,RectF dst, Matrix.ScaleToFit stf)

將當前matrix的值設置爲這樣的值,對src進行變換後可以得到dst,因兩者都是RectF,所以該matrix的值只能是伸縮和平移的組合,設置成功了返回true,stf爲伸縮參數,這個Matrix.ScaleToFit伸縮參數有什麼名堂呢,它有四個常量,每個常量應用後會導致matrix有什麼結果呢,根據那4個常量的文字說明可知,CENTER,END,START表示得到的伸縮矩陣m,m對src進行變換後得到dst1,dst1跟src有同樣的寬高比例,dst1在dst的內部,不同的地方是CENTER的狀態是這樣的:dst1.left-dst.left=dst.right-dst1.right,dst1.top-dst.top=dst.bottom-dst1.bottom;END的狀態是這樣的:dst1.right=dst.right,dst1.bottom=dst.bottom.START的狀態是這樣的:dst1.left=dst.left,dst1.top=dst.top;至於FILL表示得到的伸縮矩陣m,通過它對src變換後得到的Rect就是dst,完全重合。結論通過RectF(0,0,10,10),  RectF(0,0,20,30)這兩個矩陣得到了驗證。

public void setRotate(float degrees)

設置當前matrix,使作用於點座標時使點座標以點(0,0)爲原點旋轉degrees度。

public void setRotate(float degrees, float px, float py)

設置當前matrix,使作用於點座標時使點座標以點(px,py)爲原點旋轉degrees度。在轉換過程中,該原點不可改變

public void setScale(float sx, float sy, float px, float py)

設置當前matrix,使作用於點座標時使點座標以(px,py)爲支點伸縮sx,sy倍。(px,py)在轉換過程中不能改變。這個解釋有點蒙,驗證了下發現其實就是x'=(x+px)*sx,y'=(y+py)*sy

public void setScale(float sx, float sy)

這其實就是setScale(sx,sy,0,0);

public void setSinCos(float sinValue, float cosValue)

這其實就是setSinCos(sinValue,cosValue,0,0);

public void setSinCos(float sinValue, float cosValue, float px, float py)

設置當前matrix,以px,py爲支點進行旋轉變換,變換方式與sinValue,cosValue的值有關,經過驗證,可以得到近似換算公式爲:x'=cosValue*x-sinValue*y+(1-cosValue)*px+sinValue*py;y'=sinValue*x+cosValue*y-sinValue*px+(1-cosValue)*py;

public void setSkew(float kx, float ky, float px, float py)

設置當前matrix,以px,py爲支點進行傾斜kx,ky.公式變換應該爲x'=x+kx*(y-py),y'=ky*(x-px)+y;

public void setSkew(float kx, float ky)

相當於setSkew(kx,ky,0,0);

public void setTranslate(float dx, float dy)

設置matrix,應用時使點座標(x,y)各自平移爲(x+dx,y+dy);

 

public void setValues(float[] values)

複製9個數據給matrix,由於matrix的變形,或許這些數據會變成16位的數據,所以用getValues()可能不能得到與初始化相同的數據。不出意外的話,values的後三位要是0,0,1,否則可能該matrix變化後得不到你想要的點座標

public String toShortString ()

public String toString ()

返回一個字符串用來描述該目標和數據,該類的子類是鼓勵重寫該函數的,詳細描述該對象的類型和數據。默認的描述方式如下

getClass().getName() + '@' + Integer.toHexString(hashCode())

 補充源碼如下

 

package com.hahajlu;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.View;

public class MatrixActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SampleView(this));
    }
}
class SampleView extends View
{
  Matrix mt1=new Matrix(); 
  Matrix mt2=new Matrix();
  public SampleView(Context context)
  {
   super(context);
  
  }

@Override
protected void onDraw(Canvas canvas) {
 // TODO Auto-generated method stub
 float p[]=new float[]{100.f,100.f};
// mt1.setRotate(90);
    mt1.setValues(new float[]{1,0,1,0,1,3,1,2,1});
//    mt1.mapPoints(p);
// mt1.setScale(0.5f, 0.5f);
// mt1.mapPoints(p); 
// mt1.setTranslate(10.f, 10.f);
 //mt1.invert(mt2);
// mt1.setRectToRect(new RectF(0,0,10,10), new RectF(0,0,20,30), Matrix.ScaleToFit.FILL);
// mt1.setScale(0.5f, 0.5f, 20f, 30f);
// mt1.setSinCos(0.5f, 0.6f,30.f,20.f);
// mt1.setSkew(10f, 15f, 20f, 32f);
 float values[]=new float[9];
 mt1.getValues(values);
 mt1.mapPoints(p);
 Paint paint=new Paint();
 paint.setColor(Color.BLACK);
 canvas.drawColor(Color.WHITE);
 canvas.drawText("爲了", p[0], p[1], paint);
 System.out.println("x="+p[0]+"y="+p[1]);
 for(int i=0;i<9;i++)
   System.out.println("values="+values[i]);
// float radiu=mt1.mapRadius(10.f);
// System.out.println("radiu="+radiu); 
 super.onDraw(canvas);
}
 
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章