Matrix是一个矩阵,主要功能是坐标映射数值转换
Matrix特点
- 作用广泛: Matrix在View,图片,动画,效果等各个方面均有运用.
- 更加灵活: Matrix作为更接近底层的东西,必然要比画布操作更灵活.
Matrix基本原理
Matrix是一个矩阵,最根本的作用就是坐标转换.
基本变换有4种: 平移(translate)、缩放(scale)、旋转(rotate) 和 错切(skew).
Matrix复合原理
其实Matrix的多种复合操作都是使用矩阵乘法实现的,从原理上理解很简单,但是,使用矩阵乘法也有其弱点,后面的操作可能会影响到前面到操作,所以在构造Matrix时顺序很重要。
我们常用的四大变换操作,每一种操作在Matrix均有三类,前乘(pre),后乘(post)和设置(set),可以参见文末对Matrix方法表,由于矩阵乘法不满足交换律,所以前乘(pre),后乘(post)和设置(set)的区别还是很大的。
那么如何使用?
正确使用方式就是先构造正常的 Matrix 乘法顺序,之后根据情况使用 pre 和 post 来把这个顺序实现。
还是用一个最简单的例子理解,假设需要围绕某一点旋转。
可以用这个方法 xxxRotate(angle, pivotX, pivotY)
,由于我们这里需要组合构造一个 Matrix,所以不直接使用这个方法。
首先,有两条基本定理:
- 所有的操作(旋转、平移、缩放、错切)默认都是以坐标原点为基准点的。
- 之前操作的坐标系状态会保留,并且影响到后续状态。
基于这两条基本定理,我们可以推算出要基于某一个点进行旋转需要如下步骤:
1.先将坐标系原点移动到指定位置,使用平移 T
2.对坐标系进行旋转,使用旋转 S (围绕原点旋转)
3.再将坐标系平移回原来位置,使用平移 -T
按此写出来的伪代码如下:
Matrix matrix = new Matrix();
matrix.preTranslate(pivotX,pivotY);
matrix.preRotate(angle);
matrix.preTranslate(-pivotX, -pivotY);
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(API21) isIdentity | 求逆矩阵、 是否为仿射矩阵、 是否为单位矩阵 … |
构造方法:
1.无参构造
Matrix matrix = new Matrix();
通过这种方式创建出来的并不是一个数值全部为空的矩阵,而是一个单位矩阵,如下:
2.有参构造
Matrix (Matrix src)
这种方法则需要一个已经存在的矩阵作为参数,创建一个Matrix,并对src深拷贝(理解为新的matrix和src是两个对象,但内部数值相同即可)。
基本方法;
1.equals -> 比较两个Matrix的数值是否相同。
### 数值操作:
1.reset
void reset () //重置当前Matrix(为单位矩阵)
2.set
void set (Matrix src) //没有返回值,有一个参数,作用是将参数Matrix的数值复制到当前Matrix中。如果参数为空,则重置当前Matrix,相当于reset()。
3.setValues
void setValues (float[] values) //setValues的参数是浮点型的一维数组,长度需要大于9,拷贝数组中的前9位数值赋值给当前Matrix。
4.getValues
void getValues (float[] values) //很显然,getValues和setValues是一对方法,参数也是浮点型的一维数组,长度需要大于9,将Matrix中的数值拷贝进参数的前9位中。
数值计算
1.mapPoints
void mapPoints (float[] pts)
void mapPoints (float[] dst, float[] src)
void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount)
(1) void mapPoints (float[] pts)
方法仅有一个参数,pts数组作为参数传递原始数值,计算结果仍存放在pts中。
val pts = floatArrayOf(0f,0f,80f,100f,400f,300f)//初始数据为三个点 (0, 0) (80, 100) (400, 300)
val matrix = Matrix()
matrix.setScale(0.5f,1f)//x坐标缩放0.5
log(src.contentToString())
matrix.mapPoints(pts)
log(src.contentToString())
>>>
//变换前:[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
//变换后:[0.0, 0.0, 40.0, 100.0, 200.0, 300.0]
(2) void mapPoints (float[] dst, float[] src)
,src作为参数传递原始数值,计算结果存放在dst中,src不变。
val src = floatArrayOf(0f,0f,80f,100f,400f,300f)
val dst = FloatArray(6)
val matrix = Matrix()
matrix.setScale(0.5f,1f)
log(src.contentToString())
log(dst.contentToString())
matrix.mapPoints(dst,src)
log(src.contentToString())
log(dst.contentToString())
>>>
//src:[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
//dst:[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
//src:[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
//dst:[0.0, 0.0, 40.0, 100.0, 200.0, 300.0]
(3) void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount)
可以指定只计算一部分数值。
参数 | 摘要 |
---|---|
dst | 目标数据 |
dstIndex | 目标数据存储位置起始下标 |
src | 源数据 |
srcIndex | 源数据存储位置起始下标 |
pointCount | 计算的点个数 |
val src = floatArrayOf(0f,0f,80f,100f,400f,300f)
val dst = FloatArray(6)
val matrix = Matrix()
matrix.setScale(0.5f,1f)
log(src.contentToString())
log(dst.contentToString())
matrix.mapPoints(dst,0,src,2,2)//注意是从2开始后的,两个点,有四个值,并非两个数值
log(src.contentToString())
log(dst.contentToString())
>>>
//src:[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
//dst:[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
//src:[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
//dst:[40.0, 100.0, 200.0, 300.0, 0.0, 0.0]
2.mapRect
boolean mapRect (RectF rect)//测量rect并将测量结果放入rect中,返回值是判断矩形经过变换后是否仍为矩形。
boolean mapRect (RectF dst, RectF src)//测量src并将测量结果放入dst中,返回值是判断矩形经过变换后是否仍为矩形
3.mapVectors
void mapVectors (float[] vecs)
void mapVectors (float[] dst, float[] src)
void mapVectors (float[] dst, int dstIndex, float[] src, int srcIndex, int vectorCount)
mapVectors
与 mapPoints
基本上是相同的,可以直接参照上面的mapPoints
使用方法。
而两者唯一的区别就是mapVectors
不会受到位移的影响,这符合向量的定律
set、pre 与 post
方法 | 简介 |
---|---|
set | 设置,会覆盖掉之前的数值,导致之前的操作失效。 |
pre | 前乘,相当于矩阵的右乘, M' = M * S (S指为特殊矩阵) |
post | 后乘,相当于矩阵的左乘,M' = S * M (S指为特殊矩阵) |
特殊方法
1.setPolyToPoly
boolean setPolyToPoly (
float[] src, // 原始数组 src [x,y],存储内容为一组点
int srcIndex, // 原始数组开始位置
float[] dst, // 目标数组 dst [x,y],存储内容为一组点
int dstIndex, // 目标数组开始位置
int pointCount) // 测控点的数量 取值范围是: 0到4
有关于pointCount:
pointCount | 摘要 |
---|---|
0 | 相当于reset |
1 | 相当于translate |
2 | 可以进行 缩放、旋转、平移 变换 |
3 | 可以进行 缩放、旋转、平移、错切 变换 |
4 | 可以进行 缩放、旋转、平移、错切以及任何形变 |
1个点:
2个点:
3个点:
4个点:
由此可以直观的感受点数多带来的不同.