android Matrix学习

1.matrix:译为 矩阵  
	在Android中Matrix是一个3×3的矩阵,是由长度为9的一维数组表示的,用来对view在屏幕上的空间位置进行设置 
  可以通过获取view 的Matrix:
            Matrix matrix=view.getMatrix();
			float[] list=new float[9];
			 String matrixString=Arrays.tostring(matrix.getValues(list));
	
	Matrix基本原理:

                                 

 Matrix 是一个矩阵,最根本的作用就是坐标转换,下面我们就看看几种常见变换的原理:

  我们所用到的变换均属于仿射变换,仿射变换是 线性变换(缩放,旋转,错切) 和 平移变换(平移) 的复合

   基本变换有4种: 平移(translate)、缩放(scale)、旋转(rotate) 和 错切(skew)。	

下面我们看一下四种变换都是由哪些参数控制的

最后三个参数是控制透视的

MSCALE:缩放Scale,也就是控件的放大和缩小。
MSKEW:Skew错切,是控件X(或Y)轴不变,Y(或X)轴根据比例平移形成的变化。
MTRANS:Translate平移,是控件平移指定距离后的图像
MPERSP:Perspective透视
 

1.缩放(Scale)

用矩阵表示:

你可能注意到了,我们坐标多了一个1,这是使用了齐次坐标系的缘故,在数学中我们的点和向量都是这样表示的(x, y),两者看起来一样,计算机无法区分,为此让计算机也可以区分它们,增加了一个标志位,增加之后看起来是这样: 

(x, y, 1) - 点
(x, y, 0) - 向量

另外,齐次坐标具有等比的性质,(2,3,1)、(4,6,2)…(2N,3N,N)表示的均是(2,3)这一个点。(将MPERSP_2解释为scale这一误解就源于此)。

2.错切(Skew)

错切存在两种特殊错切,水平错切(平行X轴)和垂直错切(平行Y轴)。

水平错切

用矩阵表示:

图例:

垂直错切

用矩阵表示:

图例:

复合错切

水平错切和垂直错切的复合。

用矩阵表示:

图例:

3.旋转(Rotate)

 

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

用矩阵表示:

图例:

4.平移(Translate)

此处也是使用齐次坐标的优点体现之一,实际上前面的三个操作使用 2x2 的矩阵也能满足需求,但是使用 2x2 的矩阵,无法将平移操作加入其中,而将坐标扩展为齐次坐标后,将矩阵扩展为 3x3 就可以将算法统一,四种算法均可以使用矩阵乘法完成。

用矩阵表示:

图例:

Matrix复合原理

其实Matrix的多种复合操作都是使用矩阵乘法实现的,从原理上理解很简单,但是,使用矩阵乘法也有其弱点,后面的操作可能会影响到前面到操作,所以在构造Matrix时顺序很重要。

我们常用的四大变换操作,每一种操作在Matrix均有三类,前乘(pre),后乘(post)和设置(set),由于矩阵乘法不满足交换律,所以前乘(pre),后乘(post)和设置(set)的区别还是很大的。

前乘(pre)

前乘相当于矩阵的右乘:

这表示一个矩阵与一个特殊矩阵前乘后构造出结果矩阵。

后乘(post)

后乘相当于矩阵的左乘:

这表示一个矩阵与一个特殊矩阵后乘后构造出结果矩阵。

设置(set)

设置使用的不是矩阵乘法,而是直接覆盖掉原来的数值,所以,使用设置可能会导致之前的操作失效

如何理解和使用 pre 和 post ?不要去管什么先后论,顺序论,就按照最基本的矩阵乘法理解。

 

pre  : 右乘, M‘ = M*A
post : 左乘, M’ = A*M

那么如何使用?

正确使用方式就是先构造正常的 Matrix 乘法顺序,之后根据情况使用 pre 和 post 来把这个顺序实现。

还是用一个最简单的例子理解,假设需要围绕某一点旋转。

可以用这个方法 xxxRotate(angle, pivotX, pivotY) ,由于我们这里需要组合构造一个 Matrix,所以不直接使用这个方法。

首先,有两条基本定理:

  • 所有的操作(旋转、平移、缩放、错切)默认都是以坐标原点为基准点的。

  • 之前操作的坐标系状态会保留,并且影响到后续状态。

基于这两条基本定理,我们可以推算出要基于某一个点进行旋转需要如下步骤:

1. 先将坐标系原点移动到指定位置,使用平移 T
2. 对坐标系进行旋转,使用旋转 S (围绕原点旋转)
3. 再将坐标系平移回原来位置,使用平移 -T

具体公式如下:

M 为原始矩阵,是一个单位矩阵, M‘ 为结果矩阵, T 为平移, R为旋转

M' = M*T*R*-T = T*R*-T

按照公式写出来的伪代码如下:

Matrix matrix = new Matrix();
matrix.preTranslate(pivotX,pivotY);
matrix.preRotate(angle);
matrix.preTranslate(-pivotX, -pivotY);

围绕某一点操作可以拓展为通用情况,即:

Matrix matrix = new Matrix();
matrix.preTranslate(pivotX,pivotY);
// 各种操作,旋转,缩放,错切等,可以执行多次。
matrix.preTranslate(-pivotX, -pivotY);

公式为:

M' = M*T* ... *-T = T* ... *-T

但是这种方式,两个调整中心的平移函数就拉的太开了,所以通常采用这种写法:

Matrix matrix = new Matrix();
// 各种操作,旋转,缩放,错切等,可以执行多次。
matrix.postTranslate(pivotX,pivotY);
matrix.preTranslate(-pivotX, -pivotY);

这样公式为:

M' = T*M* ... *-T = T* ... *-T

可以看到最终化简结果是相同的。

所以说,pre 和 post 就是用来调整乘法顺序的,正常情况下应当正向进行构建出乘法顺序公式,之后根据实际情况调整书写即可。

在构造 Matrix 时,个人建议尽量使用一种乘法,前乘或者后乘,这样操作顺序容易确定,出现问题也比较容易排查。当然,由于矩阵乘法不满足交换律,前乘和后乘的结果是不同的,使用时应结合具体情景分析使用。

下面我们用不同对方式来构造一个相同的矩阵:

注意:

  • 1.由于矩阵乘法不满足交换律,请保证使用初始矩阵(Initial Matrix),否则可能导致运算结果不同。
  • 2.注意构造顺序,顺序是会影响结果的。
  • 3.Initial Matrix是指new出来的新矩阵,或者reset后的矩阵,是一个单位矩阵。

1.仅用pre:

// 使用pre, M' = M*T*S = T*S
Matrix m = new Matrix();
m.reset();
m.preTranslate(tx, ty); 
m.preScale(sx, sy); //先执行后边

用矩阵表示:

2.仅用post:

// 使用post, M‘ = T*S*M = T*S
Matrix m = new Matrix();
m.reset();
m.postScale(sx, sy);  //,越靠前越先执行。
m.postTranslate(tx, ty);

用矩阵表示:

3.混合:

// 混合 M‘ = T*M*S = T*S
Matrix m = new Matrix();
m.reset();
m.preScale(sx, sy);  
m.postTranslate(tx, ty);

或:

// 混合 M‘ = T*M*S = T*S
Matrix m = new Matrix();
m.reset();
m.postTranslate(tx, ty);
m.preScale(sx, sy);  

由于此处只有两步操作,且指定了先后,所以代码上交换并不会影响结果。

用矩阵表示:

注意: 由于矩阵乘法不满足交换律,请保证初始矩阵为单位矩阵,如果初始矩阵不为单位矩阵,则导致运算结果不同。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值