0、前言
一开始接触Matrix是因为需要对图片做一些处理,然而笔者是一个刚毕业半年的小青年,最初连Matrix这个类都不知道,后来通过各种查找资料才知道Matrix是用来做一些平移、旋转、缩放操作的,而且不仅仅只能作用于图片上,同样也可以作用于Rect、Point等。然后网上的资料有对有错,也不是很详细,导致笔者在这过程中踩了不少坑。本文旨在帮助和笔者一样还不是很了解Matrix,甚至还没用过的读者,从原理上了解Matrix,也为自己做一个总结。
1、Matrix是什么?
Matrix翻译成中文叫做矩阵,样子就长成下面这样
矩阵在数学上代表的是一组线性方程,学过线性代数的同学肯定就很了解了。啥?没学过怎么办?别担心,本文只用到了矩阵的乘法,并不会涉及很深的线代知识。
2、矩阵的乘法
矩阵乘法公式:
单看乘法公式可能不是很直观,再来看一下两个2*2的矩阵相乘是怎么运算的
来个简单的例题练习一下
怎么样,是不是很简单呢。好了,准备工作就做到这里,接下来就进去正题了。
3、Android中的Matrix
首先来看一下Android Developer上对于Matrix类的介绍
The Matrix class holds a 3x3 matrix for transforming coordinates.
可以看出Matrix就是用于坐标变换的。而且是一个3x3的矩阵。就长酱紫
Matrix可以操作的基础变换可分为四种:
Scale:缩放
Skew:错切
Rotate:旋转
Translate:平移
顺带一提,最后一行的三个参数分别为0,0,1。是固定值,那为什么要这样做,明明六个参数的可以做的事情为什么要变成9个?其实这个在线代里面叫做齐次方程,简而言之就是为了方便计算。
4、Matrix中的setXXX、preXXX、postXXX
这三者有何区别?setXXX是最简单的,调用setXXX会直接将Matrix重置并赋值。而pre和post就没那么简单了,如果单纯只使用一种变换,那么pre和post是没有区别的(为什么没有区别呢?此处先留一个坑)。但是如果组合使用,那么区别就大了。笔者当时就是同时使用了scale和translate,踩坑之旅就此开始…
一开始笔者在网上查找资料,发现不少博文说pre是先执行,post是后执行。比如说:我先调用postTransla,然后再调用preScale,则系统会先执行scale再执行post。然而坑就是这么踩进去的,首先博文并没有说清楚,先执行和后执行有什么差异,再者,这里的逻辑存在问题,我们都知道代码都是一行一行去执行的,不可能先执行下一行再返回去执行上一行。
这里首先要说明的是,pre根本不是什么先执行,post也根本不是后执行,pre和post分别代表着左乘(前乘?)和右乘(后乘?),不过有点搞不懂谷歌这边为什么要用pre和post。本文为了方便理解,就直译为前乘和后乘,左为前,右为后。
以translate为例,谷歌对于postTranslate的说明是这样的
postTranslate
boolean postTranslate (float dx, float dy)
Postconcats the matrix with the specified translation.M’ = T(dx, dy) * M
后乘将自身置于后面,前面矩阵乘以自身
preTranslate同理
M’ = M * T(dx, dy)
前乘将自身置于前,再乘以后面矩阵
为什么会有前乘后乘,因为矩阵不符合乘法交换律(特殊情况除外,如:两个矩阵一模一样),矩阵交换相乘会得出不一样的结果,建议同学们自己验证一下。
这里再提一下,笔者原本以为前乘是前边乘以一个矩阵,然而这与实际完全相反,后来看了api才知道错了,所以提倡大家遇到问题一定要去官网找资料,那肯定是最权威的,况且谷歌中国不是已经回归了吗,不必再辛苦翻墙,此时不看更待何时。
5、组合使用变换时,preXXX和postXXX产生的不同结果
本文仅以Scale和Translate进行讲解,其他情况童鞋们可以自己证明
- preScale(ΔX , ΔY)
结论:preScale(float x, float y)并不会影响原先的偏移量。
- postScale(ΔX , ΔY)
结论:postScale(float x, float y)会将原先的偏移量一起缩放。
本文前面挖了一个坑,当只有一种类型变换时,pre和post的效果是一致的。当自由scale时,translate等于0,所以两者得出的结果一致。
- preTranslate(ΔX , ΔY)
结论:preTranslate(float x, float y)按照之前的缩放比例缩放偏移量。
- postTranslate(ΔX , ΔY)
结论:postTranslate(float x, float y)会偏移指定值,与缩放参数无关。
同理,当使用Translate变换时,scale等于1,preTranslate和postTranslate的结果是一致的。
关于其他的变换就不再证明了,既然知道了原理,同学们就自己动手试着做看看。
6、后话
这段话写给看到最后的童鞋,同时也是写给自己。虽然Google已经封装好了Api供开发者使用,但是必要时还是得去了解原理,否则模凌两可所走的弯路,可能会比你脚踏实地来得更加曲折。这不仅仅是作为开发者应该具备的素质,更是人生中的一笔巨大财富。