Android Matrix矩阵

Matrix

Matrix是一个矩阵,主要功能是坐标映射,数值转换,在View,图片,动画效果等各个方面均有运用。
基本变换有4种:

  • 平移(Translate)
  • 缩放(Scale)
  • 旋转(Rotate)
  • 错切(Skew)

矩阵运算

矩阵加减法:

就是相同位置的数字相加


矩阵相加.png

矩阵减法也类似

矩阵乘以一个常数

就是所有位置都乘以这个数:

矩阵乘常数.png

矩阵乘以矩阵

矩阵乘以矩阵.png

计算规则是,第一个矩阵第一行的每个数字(2和1),各自乘以第二个矩阵第一列对应位置的数字(1和1),然后将乘积相加( 2 x 1 + 1 x 1),得到结果矩阵左上角的那个值3。也就是说,结果矩阵第m行与第n列交叉位置的那个值,等于第一个矩阵第m行与第二个矩阵第n列,对应位置的每个值的乘积之和

矩阵的本质就是线性方程式,两者是一一对应关系

线性方程式.png

矩阵的最初目的,只是为线性方程组提供一个简写形式。


矩阵.png

四种变换

1、缩放(Scale)

缩放.png

2.错切(Skew)

错切.png

3.旋转(Rotate)

假定一个点 A(x0, y0) ,距离原点距离为 r, 与水平轴夹角为 α 度, 绕原点旋转 θ 度, 旋转后为点 B(x, y) 如下:

旋转.png

4.平移(Translate)

平移.png

Matrix复合原理

常用的四大变换操作,每一种操作在Matrix均有三类,前乘(pre),后乘(post)和设置(set)
前乘(pre):前乘相当于矩阵的右乘
后乘(post):前乘相当于矩阵的左乘
设置(set):设置使用的不是矩阵乘法,而是直接覆盖掉原来的数值
例如:

Matrix m = new Matrix();
m.reset();
m.preTranslate(tx, ty);
m.preScale(sx, sy);
左乘.png
Matrix m = new Matrix();
m.reset();
m.postScale(sx, sy); 
m.postTranslate(tx, ty);
右乘.png

pre 和 post 就是右乘或者左乘的区别,pre 和 post 不能影响程序执行顺序,而程序每执行一条语句都会得出一个确定的结果,从实际上来说,由于矩阵乘法满足结合律,所以不论你说是靠右先执行还是靠左先执行,从结果上来说都没有错

Matrix方法

1.Matrix ()

2.Matrix (Matrix src)

3.void set (Matrix src)

4.void reset ()
重置当前Matrix(将当前Matrix重置为单位矩阵)。

5.void setValues (float[] values)
setValues的参数是浮点型的一维数组,长度需要大于9,拷贝数组中的前9位数值赋值给当前Matrix。

6.void getValues (float[] values)
getValues和setValues是一对方法,参数也是浮点型的一维数组,长度需要大于9,将Matrix中的数值拷贝进参数的前9位中。

7.boolean invert (Matrix inverse)
求矩阵的逆矩阵,简而言之就是计算与之前相反的矩阵,如果之前是平移200px,则求的矩阵为反向平移200px,如果之前是缩小到0.5f,则结果是放大到2倍

8.isAffine
判断矩阵是否是仿射矩阵, 基本上这个一直是true,因为我们所使用的变换基本上都是放射变换。

9.isIdentity
判断是否为单位矩阵,什么是单位矩阵呢,新创建的Matrix和重置后的Matrix都是单位矩阵,不过,只要随意操作一步,就不在是单位矩阵了。

10.setConcat
Matrix类还提供了直接矩阵计算方式。Matrix a=new Matrix()相当于创建一个单位矩阵。

  • a.set(b),就是赋值a = b;
  • a.preConCat(b),相当于前乘,即 a=a×b;
  • a.postConCat(b),相当于前乘,即 a=b×a;
  • c.setConcat(a,b),相当于c=a×b;

11.void setTranslate(float dx, float dy)
设置平移效果,参数分别是x,y上的平移量。

12.void setScale(float sx, float sy, float px, float py)
void setScale(float sx, float sy)

两个方法都是设置缩放到matrix中,sx,sy代表了缩放的倍数,px,py代表缩放的中心。

13.void setRotate(float degrees, float px, float py)
void setRotate(float degrees)
和上面类似

14.void setSkew(float kx, float ky, float px, float py)
void setSkew(float kx, float ky)
错切,这里kx,ky分别代表了x,y上的错切因子,px,py代表了错切的中心

15.mapPoints
计算一组点基于当前Matrix变换后的位置,(由于是计算点,所以参数中的float数组长度一般都是偶数的,若为奇数,则最后一个数值不参与计算)

(1) void mapPoints (float[] pts)
void mapPoints (float[] pts) 方法仅有一个参数,pts数组作为参数传递原始数值,计算结果仍存放在pts中

// 初始数据为三个点 (0, 0) (80, 100) (400, 300) 
float[] pts = new float[]{0, 0, 80, 100, 400, 300};

// 构造一个matrix,x坐标缩放0.5
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);

// 输出pts计算之前数据
Log.i(TAG, "before: "+ Arrays.toString(pts));

// 调用map方法计算
matrix.mapPoints(pts);

// 输出pts计算之后数据
Log.i(TAG, "after : "+ Arrays.toString(pts));
before: [0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
after : [0.0, 0.0, 40.0, 100.0, 200.0, 300.0]

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

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

16.float mapRadius (float radius)
测量半径,由于圆可能会因为画布变换变成椭圆,所以此处测量的是平均半径。

float radius = 100;
float result = 0;

// 构造一个matrix,x坐标缩放0.5
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);

Log.i(TAG, "mapRadius: "+radius);

result = matrix.mapRadius(radius);

Log.i(TAG, "mapRadius: "+result);

17.boolean mapRect (RectF rect)

boolean mapRect (RectF dst, RectF src)
测量矩形变换后位置。

RectF rect = new RectF(400, 400, 1000, 800);

// 构造一个matrix
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);
matrix.postSkew(1,0);

Log.i(TAG, "mapRadius: "+rect.toString());

boolean result = matrix.mapRect(rect);

Log.i(TAG, "mapRadius: "+rect.toString());
Log.e(TAG, "isRect: "+ result);

18.mapVectors
测量向量。
mapVectorsmapPoints基本上是相同的,可以直接参照上面的mapPoints使用方法。
而两者唯一的区别就是 mapVectors 不会受到位移的影响,由于向量的平移前后是相等的,这符合向量的定律

float[] src = new float[]{1000, 800};
float[] dst = new float[2];

// 构造一个matrix
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);
matrix.postTranslate(100,100);

// 计算向量, 不受位移影响
matrix.mapVectors(dst, src);
Log.i(TAG, "mapVectors: "+Arrays.toString(dst));

// 计算点
matrix.mapPoints(dst, src);
Log.i(TAG, "mapPoints: "+Arrays.toString(dst));

//打印:
mapVectors: [500.0, 800.0]
mapPoints: [600.0, 900.0]

19.setPolyToPoly

boolean setPolyToPoly (
        float[] src,    // 原始数组 src [x,y],存储内容为一组点
        int srcIndex,   // 原始数组开始位置
        float[] dst,    // 目标数组 dst [x,y],存储内容为一组点
        int dstIndex,   // 目标数组开始位置
        int pointCount) // 测控点的数量 取值范围是: 0到4

pointCount的意义
0 相当于reset
1 相当于translate
2 可以进行 缩放、旋转、平移 变换
3 可以进行 缩放、旋转、平移、错切 变换
4 可以进行 缩放、旋转、平移、错切以及任何形变

20.setRectToRect

boolean setRectToRect (RectF src,           // 源区域
                RectF dst,                  // 目标区域
                Matrix.ScaleToFit stf)      // 缩放适配模式

将源矩形的内容填充到目标矩形中,然而在大多数的情况下,源矩形和目标矩形的长宽比是不一致的,到底该如何填充呢,这个填充的模式就由第三个参数 stf 来确定
ScaleToFit 是一个枚举类型,共包含了四种模式

CENTER 居中,对src等比例缩放,并最大限度的填充变换后的矩形,将其居中放置在dst中。
START 顶部,对src等比例缩放,并最大限度的填充变换后的矩形,将其放置在dst的左上角。左上对齐
END 底部,对src等比例缩放,并最大限度的填充变换后的矩形,将其放置在dst的右下角。 右下对齐
FILL 充满,拉伸src的宽和高,使其完全填充满dst。

21.rectStaysRect
判断矩形经过变换后是否仍为矩形

Matrix实用技巧

1.获取View在屏幕上的绝对位置

@Override
protected void onDraw(Canvas canvas) {
    float[] values = new float[9];
    int[] location1 = new int[2];

    Matrix matrix = canvas.getMatrix();
    matrix.getValues(values);

    location1[0] = (int) values[2];
    location1[1] = (int) values[5];
    Log.i(TAG, "location1 = " + Arrays.toString(location1));

    int[] location2 = new int[2];
    this.getLocationOnScreen(location2);
    Log.i(TAG, "location2 = " + Arrays.toString(location2));
}

2.利用setPolyToPoly制造3D效果

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容