前言
最近在搞一个图形编辑类的前端项目,其中底层涉及到大量矩阵变换,于是总结心得遂成此文。
先引出矩阵
2D 变换矩阵主要形式如下:
⎣⎡ab0cd0ef1⎦⎤
下面我们来对此矩阵进行分解。
分解矩阵
变换基量
举个例子。
下图是两个用两维的笛卡尔坐标系表示的二维平面:黑色坐标系 x-y、蓝色坐标系 i-j。
已知点 p 处在 i-j 坐标系中,坐标为 (2, 1),又知 i-j 坐标系在 x-y 坐标系的基量为 i =(1, 1),j=(-1, 1)。那么点 p 在坐标系 x-y 的坐标是什么?
解:p = 2i+j = 2(x+y)+(-x+y) = x+3y,因此点 p 在 x-y 坐标系中的坐标为 (1, 3)。
所以一般地,假设点 p 在 i-j 坐标系下为 (k1, k2),在 x-y 坐标系下为 (q1, q2)。同样地有基向量 i 对应在 x-y 空间中为 (m1, m2);j 对应在 x-y 空间中为 (n1, n2),则有:
p=k1(m1x+m2y)+k2(n1x+n2y)
最后得到:
q1=k1m1+k2n1q2=k1m2+k2n2
即:
(q1 q2)=(k1 k2) [m1n1m2n2]
这里的矩阵对应文章一开头矩阵中的 a、b、c、d。
偏移
得到 x-y 坐标下的点 p 后,我们允许点 p 能在该坐标系下偏移,产生 x 方向与 y 方向对应的偏移量 e 与 f,则有:
q1′=q1+eq2′=q2+f
CSS3 中的常见矩阵
其实,transform: matrix(a,b,c,d,e,f)
,就是对应文章开头的矩阵,结合上面得到的分解,可以得到对应公式:
⎣⎡ab0cd0ef1⎦⎤⋅⎣⎡xy1⎦⎤=⎣⎡ax+cy+ebx+dy+f0+0+1⎦⎤
根据此公式,我们可以推导出 css 中内置 transform 函数中的变换矩阵。
translate
1
| transform: translate(tx, ty);
|
等同于:
1
| transform: matrix(1, 0, 0, 1, tx, ty);
|
scale
1
| transform: scale(sx, sy);
|
等同于:
1
| transform: matrix(sx, 0, 0, sy, 0, 0);
|
rotate
1
| transform: rotate(θx deg, θy deg);
|
等同于:
1
| transform: matrix(cosθ, sinθ, -sinθ, cosθ, 0, 0);
|
skew
1
| transform: skew(θx deg, θy deg);
|
等同于:
1
| transform: matrix(1, tan(θy), tan(θx), 1, 0, 0);
|
高级矩阵变换
变换叠加
见于 transform
有多个变换或者父子节点嵌套 transform
,其实就是将这些变换矩阵进行相乘运算:
⎣⎡ab0cd0ef1⎦⎤⋅⎣⎡a′b′0c′d′0e′f′1⎦⎤=⎣⎡aa′+cb′ba′+db′0ac′+cd′bc′+dd′0ae′+cf′+ebe′+df′+f1⎦⎤
反变换
这种变换并不常见,其实是逆矩阵运算:
⎣⎡ab0cd0ef1⎦⎤−1=⎣⎢⎢⎢⎡ad−bcdbc−adb0bc−adcad−bca0bc−adde−cfad−bcbe−af1⎦⎥⎥⎥⎤
总结
矩阵变换的见解(选自孟岩的 blog)
- 线性空间中的任何一个对象,通过选取基和坐标的办法,都可以表达为向量的形式。这里的基可以看成是坐标系。
- 只要我们选定一组基,那么对于任何一个线性变换,都能够用一个确定的矩阵来加以描述。
- 矩阵不仅可以作为线性变换的描述,而且可以作为一组基的描述。而作为变换的矩阵,不但可以把线性空间中的一个点给变换到另一个点去,而且也能够把线性空间中的一个坐标系(基)表换到另一个坐标系(基)去。
回到 css
- 任何内置变换函数都可以用一种变换矩阵来表示
- 须注意变换原点的位置:
transform-origin
Ref
- 从坐标系图中理解“空间变换”
- 理解CSS3 transform中的Matrix(矩阵)