原文连接:http://geek.csdn.net/news/detail/89873git
做者:D_clockgithub
在 Android 开发中,矩阵是一个功能强大而且应用普遍的神器,例如:用它来制做动画效果、改变图片大小、给图片加各种滤镜等。对于矩阵,Android 官方 SDK 为咱们提供了一个强大的类 Matrix (还有 ColorMatrix )是一直困扰着个人问题,虽然大体可以调用相应的 API ,但却一直 get 不到其内在的梗。可是出来混老是别想着蒙混过关的,因此最近从新操起一年毕业的线性代数,再本着小事问老婆,大事问Google的心态,终于把多年不解的问题给破了。出于好记性不如烂笔头的缘由,便有了本文。在此先感谢下面两篇令我茅舍顿开的文章:数组
读完本文,相信你可以搞明白如下三个问题:网络
Matrix 是 Android SDK 提供的一个矩阵类,它表明一个 3 X 3 的矩阵(不懂矩阵为什么物的童鞋就要自行 Google 了)。 Matrix 提供了让咱们得到 Matrix 值的 API —— getValuesapp
利用此 API 传入一个长度为 9 的 float 数组,便可得到矩阵中每一个元素的值。那么这 9 个浮点数的做用和意义是什么呢,从 Android 官方文档上看,它为这个数组中的每个元素都定义了一个下标常量ide
这个 9 个常量取值分别是 0 - 8wordpress
若是咱们将这个 float 排成直观的矩阵格式,那它将是下面这样子的函数
实际上咱们日常利用 Matrix 来进行 Translate(平移)、Scale(缩放)、Rotate(旋转)的操做,就是在操做着这个矩阵中元素的数值来达到咱们想要的效果。可是如今问题来了,上面提到的平移、缩放、旋转操做中,旋转和缩放能够用乘法表示,而平移就只能用加法表示,并且 Matrix 是一个 3 X 3 的矩阵,实际上表示这些操做 2 X 2 的矩阵足矣!post
如上,能够依次看到平移、缩放、旋转的矩阵,其中动画
至于上面矩阵的推导过程,网络上不少,这里就不去赘述了。之前到了这里,我就会很纳闷,为何 2 X 2 矩阵能干的事情,恰恰要用 3 X 3 矩阵去作,直到遇到前面提到的两篇文章才有所领悟。
其实在计算机图形应用涉及到几何变换,主要包括平移、旋转、缩放。以矩阵表达式来计算这些变换时,平移是矩阵相加,旋转和缩放则是矩阵相乘。那些数学大神们为了方便计算,因此引入了同样神器叫作齐次坐标(不懂的童鞋,老规矩自行搜索),将平移的加法合并用乘法表示。因此,2 X 2 的矩阵通过一番变换后,成了下面这样的。
至此,咱们能够得知为何 Matrix 是一个 3 X 3 的矩阵,其实 2 X 2 的矩阵是足以表示的,不过是为了方便计算而合并写成了 3 X 3 的格式。
一个 Matrix 共有 9 个元素,那么它每一个元素的值发生改变会起到什么做用呢?按照前面所示的齐次坐标转换获得 3 X 3 的矩阵和 Android 文档提供的官方结构相对应,咱们不难看出下面的对应关系(其实从 Matrix 中每一个位置的常量命名也能够看出来):
从这咱们能够看出这个 Matrix 结构中的每一个参数发挥着以下做用:
若是要进行代码验证的话,也很是简单,例如直接只对 Matrix 作 Translate 的 API 调用操做,再将 Matrix 的信息打印到控制台,你会发现整个 Matrix 确实只有 MTRANS_X、MTRANS_Y 两个位置的数字在发生变化。其余 Scale、Rotate、Skew 操做也是同样,感兴趣的童鞋能够自行代码验证一番。
至此,咱们能够大体弄清矩阵每一个元素的做用。至于 MPERSP_0、MPERSP_一、MPERSP_2 这三个参数,目前暂时不得而知,网上有文章说这三个参数控制着透视变换,可是文档和 API 上都没怎么说起,因此仍是有待验证研究的,有明白的童鞋不妨留言赐教一下,不胜感激。
按照第一小节里面经过齐次坐标转换而来的矩阵方程能够知道,假设一根线执行了平移操做,至关于线上每一个点的坐标被下方的矩阵左乘。(缩放和旋转操做也是同理)
若是要进行同时缩放、平移之类的符合变化操做,也无非就是选取相应的矩阵作左乘操做。为了加深矩阵变换对应 Matrix API 调用的理解,直接经过下面的一个自定义的动画效果和代码来说解好了。
public class SimpleCustomAnimation 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.preScale(interpolatedTime, interpolatedTime);//缩放 matrix.preRotate(interpolatedTime * 360);//旋转 //下面的Translate组合是为了将缩放和旋转的基点移动到整个View的中心,否则系统默认是以View的左上角做为基点 matrix.preTranslate(-mWidth / 2, -mHeight / 2); matrix.postTranslate(mWidth / 2, mHeight / 2); } }
熟悉动画这块的童鞋确定知道,Animation 就是经过不断改变 applyTransformation 函数传入的 Matrix 来实现各类各样的动画效果的,经过上面 applyTransformation 寥寥的几行 Matrix 的复合变换操做能够获得以下效果
实际上这几行代码用矩阵来表示就至关于以下所示:
关于代码的做用上边已经给出了注释,这里就很少写了。主要仍是要弄明白 Matrix 复合变换中 pre 、 post 等操做与其对应的矩阵发生的左乘、右乘变化。
到此,整篇文章已经完结,相信已经可以让你明白开头提到的三个问题。其实咱们也能够发现,Google 封装了 Matrix 已是很完美了,几乎屏蔽了全部的数学细节,使得我这种数学水平通常的开发者也可以去调用相应的 API 实现一些简单的效果。虽然被封装得很完美,但掌握相应的一些原理,依旧能够帮你更好的理解一些技术实现,这次加深了对 Matrix 一些操做的理解,帮我本身解决了之前很多的困惑,不知道有没有帮你 get 到一些什么呢?
上面给的示例代码很简单,复制黏贴便可运行玩耍,实在须要直接运行源码的童鞋就到 https://github.com/D-clock/AndroidStudyCode 找吧!