Matrix矩阵

什么是矩阵? 矩阵的乘法代表什么?

由于大学时 <<线性代数>> 没怎么学好导致对于 android 中矩阵这块知识点一直非常的恐惧不敢去触碰。其实对矩阵感到恐惧根本原因还是因为不知道矩阵到底代表着什么意思,只记得以前学到的矩阵晦涩难懂的算术运算,但是完全不懂为什么要这么算。本着长痛不如短痛的想法,就来好好的研究一番,解惑。

要了解矩阵在 android 的应用首先要掌握什么是矩阵?矩阵的乘法运算代表什么意思?读了

Linear Algebra: What matrices actually are

仿射变换与齐次坐标

[Why, historically, do we multiply matrices as we do?

这两篇文章让我对矩阵有了基本的理解,矩阵其实代表了线性方程式,每一个线性方程式都有一个对应的矩阵,矩阵的乘法是一种直观的形式来替换向量空间中的线性变换过程

如果有方程式组 x’ = ax + by 和 y’ = cx + dy ,x″ = a′x′ + b′y′ 和 y″ = c′x′ + d′y′ 然后我们可以把第一对公式插入第二对公式,把 x″ 和 y″ 表示成 x 和 y 的形式:

写这些变量会比较得啰嗦,所以我们用一个阵列来表示,第一行是 x′ 和 x″ ,第二行是 y′ 和 y″ 上面两个线性变变换就可以用下面的矩阵乘法表示:

所以矩阵乘法是一种线性替换的记录器,那在计算机图形学里面点 (x,y) 做线性变换到点 (x”,y”) 的变换过程也就可以用矩阵来表示了。

假设P = (x,y) 是二维空间中的点,T 是一线性变换,那么存在一个矩阵A,使得P’ = (x’ , y’) = T(p) 下面的旋转变换R,以及缩放S变换都有相应的变换矩阵:

根据矩阵的乘法可以换算出方程式组正好可以解除变换后的点的坐标 (x’,y’)。

关于齐次坐标系以及为什么二维的矩阵是 3x3 上面几篇文章已经讲得很清楚了,就不再多说了。那在齐次坐标系中表示旋转,缩放和平移线性变换的矩阵如下:

Android中的矩阵

由齐次坐标系中各种线性变换的矩阵可分析出MSCALE_XMSCALE_Y 对缩放起作用,MSKEW_XMSKEW_Y 对错切起作用,MTRANS_XMTRANS_Y 对平移起作用,剩下的三个官方文档也没详细解释就忽略。MSCALE_XMSCALE_YMSKEW_XMSKEW_Y 这四个对旋转起作用。

在 Android 中初始矩阵为:

矩阵API各方法执行顺序

android 中对矩阵的相关数学操作都被系统封装的很好,然后暴露出 postRotate),postScale),preRotate) 等方法。post 开头的方法表示在矩阵乘法队列末尾添加一个矩阵,pre 开头的方法表示是在矩阵乘法队列的开头添加一个矩阵,set 开头的方法表示清空矩阵队列并设置新的矩阵。然后从头开始执行矩阵乘法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MatrixAnimation extends Animation {
private int mWidth, mHeight;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
this.mWidth = width;
this.mHeight = height;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
Matrix matrix = t.getMatrix();
matrix.preRotate(interpolatedTime * 360);//旋转
matrix.preTranslate(-mWidth / 2, -mHeight / 2);
matrix.postTranslate(mWidth / 2, mHeight / 2);
}
}

其实补间动画的原理就是 Matrix 变换,自定义个补间动画让 Button 围绕着中心选择这要这么实现呢?

首先选择要用到 Rotate() 方法,那么选择的中心点在哪呢?其实除了 translate() 变换,其余的变换如果不指定中心点的话就以 View 的 (0,0) 点作为中心点,所以要先 preTranslate(-mWidth / 2, -mHeight / 2) 做平移变换让绘制中心在(0,0)点然后再旋转,再 postTranslate(mWidth / 2, mHeight / 2) 平移回来。所以上面的执行顺序为 matrix.preTranslate(-mWidth / 2, -mHeight / 2)->preRotate(interpolatedTime * 360)->matrix.postTranslate(mWidth / 2, mHeight / 2)