Android 图形库中的 android.graphics.Matrix 是一个 3×3 的 float 矩阵,其主要作用是坐标变换
它的结构大概是这样的
其中每个位置的数值作用和其名称所代表的的含义是一一对应的
在 Android 中,我们直接实例化一个 Matrix
,内部的矩阵长这样:
是一个左上到右下为 1,其余为 0 的矩阵,也叫单位矩阵,一般数学上表示为 I
前面说到 Matirx 主要的作用就是处理坐标的变换,而坐标的基本变换有:平移、缩放、旋转和错切
这里所说的基本变换,也称仿射变换 ,透视不属于仿射变化,关于透视相关的内容不在本文的范围内
当矩阵的最后一行是 0,0,1 代表该矩阵是仿射矩阵,下文中所有的矩阵默认都是仿射矩阵
在正式介绍 Matrix 是如何控制坐标变换的原理之前,我们先简单复习一下线性代数中的矩阵乘法,详细的讲解可参见维基百科或者翻翻大学的《线性代数》,这里只做最简单的介绍
了解矩阵乘法的基本方法之后,我们还需要记住几个性质,对后续的分析有用
A(BC)=(AB)C
A(B + C) = AB + AC
(A + B)C = AC + BC
AB != BA
I
与任意矩阵相乘,等于矩阵本身,即 IA = A
,BI = B
我们先想想,让我们实现把一个点 (x0, y0) 的 x 轴和 y 轴分别缩放 k1 和 k2 倍,我们会怎么做,很简单
val x = k1 * x0
val y = k2 * y0
复制代码
那如果用矩阵怎么实现呢,前面我们讲到 Matrix 中 MSCALE_X
、MSCALE_Y
是用来控制缩放的,我们在这里填分别设置为 k1 和 k2,看起来是这样的
而点 (x0, y0) 用矩阵表示是这样的
有些人会疑问,最后一行这里不是还有一个 1 吗,这是使用了齐次坐标系的缘故,在数学中我们的点和向量都是这样表示的 (x, y),两者看起来一样,计算机无法区分,为了让计算机也可以区分它们,增加了一个标志位,即
(x, y, 1) -> 点
(x, y, 0) -> 向量
复制代码
现在 Matrix 和点都可以用矩阵表示了,接下来我们看看怎么通过这两个矩阵得到一个缩放之后的点 (x, y). 前面我们已经介绍过矩阵的乘法,让我们看看把上面两个矩阵相乘会得到什么结果
可以看到,矩阵相乘得到了一个(k1x0, k2y0,1)的矩阵,上面说过,计算机中,这个矩阵就代表点 (k1x0, k2y0), 而这个点刚好就是我们要的缩放之后的点
以上所有过程用代码来实现,看起来就是像下面这样
val xy = FloatArray(x0, y0)
Matrix().apply {
setScale(k1, k2)
mapPoints(xy)
}
复制代码
平移和缩放也是类似的,实现平移,我们一般可写为
val x = x0 + deltaX
val y = y0 + deltaY
复制代码
而用矩阵来实现则是
val xy = FloatArray(x0, y0)
Matrix().apply {
setTranslate(k1, k2)
mapPoints(xy)
}
复制代码
换成数学表示
根据矩阵乘法
x = 1 × x0 + 0 × y0 + deltaX × 1 = x0 + deltaX
y = 0 × x0 + 1 × y0 + deltaY × 1 = y0 + deltaY
复制代码
可得和一开始的实现也是效果一致的
错切相对于平移和缩放,可能大部分人对这个名词比较陌生,直接看三张图大家可能会比较直观
水平错切
x = x0 + ky0
y = y0
复制代码
矩阵表示
垂直错切
x = x0
y = kx0 + y0
复制代码
矩阵表示
复合错切
x = x0 + k1y0
y = k2x0 + y0
复制代码
矩阵表示
旋转相对以上三种变化又有一点复杂,这里涉及一些三角函数的计算,忘记的可以去维基百科 先复习下
同样我们先自己实现一下旋转,假设一个点 A(x0, y0)
, 距离原点的距离为 r,与水平夹角为 α,现绕原点顺时针旋转 θ 度,旋转之后的点为 B(x, y)
用矩阵表示
前面介绍了四种基本变换,如果我们需要同时应用上多种变化,比如先绕原点顺时针旋转 90° 再 x 轴平移 100,y 轴平移 100, 最后 x、y 轴缩放0.5 倍,那么就需要用到复合操作
还是先用自己的实现来实现一下
x = ((x0 · cosθ - y0 · sinθ) + 100) · 0.5
y = ((y0 · cosθ + x0 · sinθ) + 100) · 0.5
复制代码
矩阵表示
按照前面的方式逐个推导,最终也能得到和上述一样的结果
到此,我们可以对 Matrix 做出一个基本的认识:Matrix 基于矩阵计算的原理,解决了计算机中坐标映射和变化的问题
下一篇文章《Matirx 方法详解及应用场景》将介绍 Matrix 中常用的 api 以及实际开发中的应用场景
相关链接