1 矩阵基础
用 A(3行3列) 的行去乘以 B(3行2列) 的所有列,得出一个3行2列的矩阵。 1、当矩阵A的列数(column)等于矩阵B的行数(row)时,A与B可以相乘。 2、矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。 3、乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。 1、2点可总结为:A(m×p)×B(p×n)=C(m×n)
1.1 左乘和右乘
以下解释是为了方便记忆,不保证科学性。
左乘以:C = AB 称为A左乘以B,“以” 表示用,A左乘以B表示用B去乘A,A在左边,跟普通乘法顺序一致,从左到右。
左乘:与左乘以相反,C = AB 称为B左乘A(B左边乘A)
右乘以:C = BA 称为A右乘以B,用B去乘A,A在右边
右乘:与右乘以相反,C = BA 称为B右乘A(B右边乘A)
所以,C = AB可以称为:A左乘以B,B左乘A,B右乘以A,A右乘B。得出结论:左乘以 == 右乘,右乘以 == 左乘。
2 Matrix基础
Matrix 是 Android 图形库里的一个坐标转换类,它里面保存了一个 3 × 3 的矩阵,矩阵里各元素的对应关系如下所示:
具体为何这样对应请参考安卓自定义View进阶-Matrix原理。这里引用几个重要的变换。
2.1 平移
用矩阵表示:
2.2 缩放
用矩阵表示:
2.3 旋转
用矩阵表示:
旋转是一个矩阵元素组合实现。
Matrix 里有很多 pre 、 post 方法。pre 表示前乘(原始Matrix放前面),A pre B 输出 AB,按照我们刚才对矩阵左乘右乘的解释,前乘相当于矩阵的A左乘以B、A右乘B。post 表示后乘(原始Matrix放后面),A post B 输出 BA,后乘相当于矩阵的A右乘以B、A左乘B。
Matrix 里常用的变换有 平移(Translate)、旋转(Rotate)、缩放(Scale)。
2.4 Matrix常用方法
| 方法类别 | 相关API | 摘要 |
|---|---|---|
| 基本方法 | equals hashCode toString toShortString | 比较、 获取哈希值、 转换为字符串 |
| 数值操作 | set reset setValues getValues | 设置、 重置、 设置数值、 获取数值 |
| 数值计算 | mapPoints mapRadius mapRect mapVectors | 计算变换后的数值 |
| 设置(set) | setConcat setRotate setScale setSkew setTranslate | 设置变换 |
| 前乘(pre) | preConcat preRotate preScale preSkew preTranslate | 前乘变换 |
| 后乘(post) | postConcat postRotate postScale postSkew postTranslate | 后乘变换 |
| 特殊方法 | setPolyToPoly setRectToRect rectStaysRect setSinCos | 一些特殊操作 |
| 矩阵相关 | invert isAffine isIdentity | 求逆矩阵、 是否为仿射矩阵、 是否为单位矩阵 … |
具体各个方法使用参考:安卓自定义View进阶-Matrix详解,各方法在 Matrix 类里的注解都非常详细, 很多方法基本一看注解就能懂。
这里放几个典型的。
2.4.1 setRectToRect
public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {}
这个方法是 src 到 dst 的变换,可以理解为把 src 放进 dst 里去的的变换,第三个参数 stf 的缩放填充模式(充满FILL、保持比例左上START、居中CENTER、右下END)。
RectF src= new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight() );
RectF dst = new RectF(0, 0, mViewWidth, mViewHeight );
mRectMatrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
canvas.drawBitmap(mBitmap, mRectMatrix, new Paint());
代码很容易理解,把 bitmap 通过 matrix 变换绘制到 view 上。
2.4.2 mapRect
mapRect有两个方法,具体含义写在注释中。
/**
* 对 rect 进行 matrix 变换,并将结果存在 rect 中
*/
public boolean mapRect(RectF rect) {}
/**
* 对 src 进行 matrix 变换,并将结果存在 dst中
*/
public boolean mapRect(RectF dst, RectF src) {}
2.4.3 setPolyToPoly
这个比较复杂,建议详细看下安卓自定义View进阶-Matrix详解里的 setPolyToPoly 详细讲解。这里摘录下重点:
先看代码和效果:
float[] src = {0, 0, // 左上
mBitmap.getWidth(), 0, // 右上
mBitmap.getWidth(), mBitmap.getHeight(), // 右下
0, mBitmap.getHeight()}; // 左下
float[] dst = {0, 0, // 左上
mBitmap.getWidth(), 400, // 右上
mBitmap.getWidth(), mBitmap.getHeight() - 200, // 右下
0, mBitmap.getHeight()}; // 左下
// 核心要点
mPolyMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); // src.length >> 1 为位移运算 相当于处以2
效果图里我们看到了图片右边产生了上下都往里缩的形变,再看代码,src 数组存放了原图的四个边界点,在 dst 数组里存放了变换后的四个边界点,src.length >> 1 即为边界点个数,很容易看出 setPolyToPoly 是能精确到数组里各个点的变换。再看方法定义就好理解很多了:
boolean setPolyToPoly (
float[] src, // 原始数组 src [x,y],存储内容为一组点
int srcIndex, // 原始数组开始位置
float[] dst, // 目标数组 dst [x,y],存储内容为一组点
int dstIndex, // 目标数组开始位置
int pointCount) // 测控点的数量 取值范围是: 0到4
测控点数量对功能的影响:
| pointCount | 摘要 |
|---|---|
| 0 | 相当于reset |
| 1 | 相当于translate |
| 2 | 可以进行 缩放、旋转、平移 变换 |
| 3 | 可以进行 缩放、旋转、平移、错切 变换 |
| 4 | 可以进行 缩放、旋转、平移、错切以及任何形变 |