目录
本质上说,QTransform是一个3×3的矩阵。在Qt官方文档里对bool QTransform::isAffine() const有这么一段解释:
Returns true if the matrix represent an affine transformation, otherwise returns false.
假如QTransform是仿射变换矩阵,此函数返回真,否则假。
那么什么是仿射变换?
仿射变换
根据Qt官方文档>>QTransform>>Basic Matrix Operations的解释:
The various matrix elements can be set when constructing the matrix, or by using the setMatrix() function later on. They can also be manipulated using the translate(), rotate(), scale() and shear() convenience functions
矩阵的元素...可以通过setMatrix()操作,也可以用translate(平移)、rotate(旋转)、scale(缩放)、shear(剪切)来操作。
平移、旋转、缩放、剪切都可以用矩阵表示,它们都是仿射变换,而且它们的乘积也都是仿射变换。
反过来说,任何仿射变换都可以分解为平移、旋转、缩放或者它们的乘积。这就是奇异值分解(SVD)。
平移、旋转、缩放三个操作不难理解。这里介绍一下剪切变换。
剪切变换
剪切变换严格意义上不属于基本变换,因为它可以分解为平移、旋转、缩放三个操作的乘积。
剪切变换可以理解为本来相互垂直的X轴和Y轴不再垂直。那么显然,本来在垂直坐标系下的矩形就不再是矩形,而是平行四边形。这样的变换就是剪切变换。
下面是两种最简单的剪切变换:沿X方向剪切、沿Y方向剪切:


当然,也存在以上两者的组合。但是XY方向均存在剪切的变换矩阵总是可以分解为一个单方向剪切矩阵乘以一个旋转矩阵。这就是著名的++QR分解++。
显然,仿射变换矩阵的逆矩阵也是仿射矩阵,因为正向平移的逆变换是负向平移变换,缩小变换的逆变换是放大变换,顺时针旋转的逆变换是逆时针旋转变换。
根据Qt官方文档解释:

m31和m32代表水平方向平移量和垂直方向平移量。m11和m22代表水平缩放因子和垂直缩放因子。m21和m12代表水平剪切和垂直剪切。
对于m13 m23 m33,这三个元素在仿射矩阵里都是定值,分别为0,0,1.只有在透视变换(一种非仿射变换)矩阵里才有可能为其他值。
非仿射变换
想象你有一个块橡皮,你在上面画一个正方形。你可以移动它(平移变换),也可以转动它(但是要保证正方形所在的平面一直面向你,旋转变换),还能拉伸它(缩放变换)。这些都是仿射变换。变换后你看到的正方形总可以通过一系列仿射变换矩阵乘法回到变换以前。而且还有一点,变换前的图案和变换后的图案都在同一个平面内。这其实是仿射变换一个非常重要的前提。
那么什么是透视变换,为什么它非仿射变换?
透视变换
想象你还有一块一模一样的橡皮,上面画了一模一样的图案。但是你把另一块橡皮图案朝上平放在桌子上,距离你眼睛比较远的地方。而原来的橡皮就放在你眼前,并且图案正对你。那么,因为近大远小,你看到远处的橡皮更像一个梯形;而近处的橡皮因为图案正对你,看上去还是正方形。

无论你使用何种仿射变换,都没有办法从近处的图案变换到远处的图案,反之亦然。这是因为,两者的变换是透视变换,而透视变换不是仿射变换。透视变换的本质,是两个图案不在同一个平面内。
透视变换矩阵的m13 m23 m33不再是定值0 0 1。这也是仿射矩阵和透视矩阵的区别。
显然,透视矩阵也是可逆矩阵。
其他非仿射变换
但是并不是所有非仿射变换都是透视变换。还是拿橡皮做例子。你还可以掰弯橡皮,这样你在橡皮上画的图案就不再平面上,而是在曲面上了。这种变换不仅不是仿射变换,而且也找不到一个3×3矩阵来描述这种操作。这里就不展开描述了。