Matrix 常用来实现图片平移,图片旋转,图片错切,图片缩放。在查看MPAndroidChart源码时,发现其中的图表平移等功能用到了Metrix。刷新我的认知,原来还可以这样来写自定义View。果然还是一直活在梦里。。。
下图是一张Matrix内容图
1890917-4168fa9b2791e659.png0.getValues(float[] values)/setValues(float[] values)
public static final int MSCALE_X = 0; //!< use with getValues/setValues
public static final int MSKEW_X = 1; //!< use with getValues/setValues
public static final int MTRANS_X = 2; //!< use with getValues/setValues
public static final int MSKEW_Y = 3; //!< use with getValues/setValues
public static final int MSCALE_Y = 4; //!< use with getValues/setValues
public static final int MTRANS_Y = 5; //!< use with getValues/setValues
public static final int MPERSP_0 = 6; //!< use with getValues/setValues
public static final int MPERSP_1 = 7; //!< use with getValues/setValues
public static final int MPERSP_2 = 8; //!< use with getValues/setValues
可以获取相对应的坐标点信息。
1. public boolean isIdentity()
判断是否为单位矩阵
Matrix matrix = new Matrix();
System.out.println("matrix = "+matrix.toShortString() + "\n" + "matrix is isIdentity " + matrix.isIdentity());
matrix.postTranslate(20, 20);
System.out.println("matrix = "+matrix.toShortString() + "\n" + "matrix is isIdentity " + matrix.isIdentity());
output
System.out:matrix = [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
System.out:matrix is isIdentity true
System.out:matrix = [1.0, 0.0, 20.0][0.0, 1.0, 20.0][0.0, 0.0, 1.0]
System.out:matrix is isIdentity false
2.public boolean isAffine()
判断是否为仿射矩阵(https://www.zhihu.com/question/20666664)一般来说我们变换过的基本上是仿射矩阵。感觉这里比较深奥,不继续探讨。
3. public boolean rectStaysRect()
Returns true if will map a rectangle to another rectangle. This can be true if the matrix is identity, scale-only, or rotates a multiple of 90 degrees.
长方形 变换之后 任然为长方形的返回 true,也就是说一般的平移,缩放都会返回 true(旋转需要90 的整数倍)。这些操作不会改变物体的形状。错切会改变形状。
Matrix matrix = new Matrix();
matrix.postTranslate(20, 20);
System.out.println("rectStaysRect " + matrix.rectStaysRect());//true
matrix.postRotate(90);
System.out.println("rectStaysRect " + matrix.rectStaysRect());//true
matrix.postRotate(18);
System.out.println("rectStaysRect " + matrix.rectStaysRect());//false
matrix.postSkew(4, 4);
System.out.println("rectStaysRect " + matrix.rectStaysRect());//false
4.public void set(Matrix src)
重新设置矩阵中的数值
5.public boolean equals(Object obj)
判断两个矩阵是否相等
6.public void reset()
将矩阵重新设置为单位矩阵
下面是一些重要的 API
7.setXXX/preXXX/postXXX
方法名 | 用途 |
---|---|
setScale/Rotate/SinCos/Skew/Concat/Translate | 重新设置 |
preScale/Rotate/SinCos/Skew/Concat/Translate | 前乘,相当于矩阵右乘 |
postScale/Rotate/SinCos/Skew/Concat/Translate | 后乘,相当于矩阵左乘 |
这里需要注意 pre与post 的使用。举个例子:
private void toTest() {
int width = mImageView.getMeasuredWidth();
int height = mImageView.getMeasuredHeight();
Bitmap bitmap = Bitmap.createBitmap(width + 300, height + 300, baseBitmap.getConfig());
Canvas canvas = new Canvas(bitmap);
Matrix matrix = new Matrix();
matrix.postTranslate(300, 300);
//matrix = [1.0, 0.0, 300.0][0.0, 1.0, 300.0][0.0, 0.0, 1.0]
matrix.preScale(0.5f ,0.5f);
//matrix =[0.5, 0.0, 300.0][0.0, 0.5, 300.0][0.0, 0.0, 1.0]
canvas.drawBitmap(baseBitmap, matrix, mPaint);
mImageViewAfter.setImageBitmap(bitmap);
}
private void toTest() {
....
matrix.postTranslate(300, 300);
//matrix = [1.0, 0.0, 300.0][0.0, 1.0, 300.0][0.0, 0.0, 1.0]
matrix.postScale(0.5f ,0.5f);
//matrix = [0.5, 0.0, 150.0][0.0, 0.5, 150.0][0.0, 0.0, 1.0]
....
}
上面两段代码执行之后的效果是不一样的
WechatIMG15.jpeg WechatIMG16.jpeg
上面两个矩阵的计算过程如下:
WechatIMG18.jpeg
所以执行之后的效果是不一样的。有的地方讲的是 pre是先执行,post是后执行。这种说法是完全错的。看上面代码的日志打印。我们需要用矩阵乘法来理解。
8.public boolean postConcat(Matrix other)
Postconcats the matrix with the specified matrix. M' = other * M
Matrix matrix = new Matrix();
matrix.postTranslate(20, 20);
System.out.println("matrix = " + matrix.toShortString());
//matrix = [1.0, 0.0, 20.0][0.0, 1.0, 20.0][0.0, 0.0, 1.0]
Matrix matrix2 = new Matrix();
matrix2.postConcat(matrix);
System.out.println("matrix2 = " + matrix2.toShortString());
//matrix2 = [1.0, 0.0, 20.0][0.0, 1.0, 20.0][0.0, 0.0, 1.0]
原始矩阵 与 目标矩阵相乘
9.public boolean setConcat(Matrix a, Matrix b)
将原始矩阵设为 a * b
Matrix matrix = new Matrix();
matrix.postTranslate(20, 20);
System.out.println("matrix = " + matrix.toShortString());
//matrix = [1.0, 0.0, 20.0][0.0, 1.0, 20.0][0.0, 0.0, 1.0]
Matrix matrix2 = new Matrix();
Matrix matrix3 = new Matrix();
matrix3.setConcat(matrix, matrix2);
System.out.println("matrix3 = " + matrix3.toShortString());
//matrix3 = [1.0, 0.0, 20.0][0.0, 1.0, 20.0][0.0, 0.0, 1.0]
10.public boolean invert(Matrix inverse)
矩阵反转,可以把转换后的数据还原成初始数据(前提是目标矩阵没有变)
Matrix matrix = new Matrix();
matrix.postTranslate(20, 0);
float[] pts = {0, 20, 20, 30};
matrix.mapPoints(pts);
System.out.println(Arrays.toString(pts));
//System.out: [20.0, 20.0, 40.0, 30.0]
Matrix temp = new Matrix();
matrix.invert(temp);
temp.mapPoints(pts);
System.out.println(Arrays.toString(pts));
//System.out: [0.0, 20.0, 20.0, 30.0]
可以看到矩阵反转把初始数据还原了
11.public void mapPoints
这个个方法是可以把对应的点坐标集,进行矩阵转换。例如点平移,“缩放”等。这个方法有几个重载方法,下面来看一个例子。
Matrix matrix = new Matrix();
Matrix tmp = new Matrix();
matrix.postTranslate(20.f, 0f);
float[] points = {0, 0, 10, 10, 20, 20, 30, 30};
matrix.mapPoints(points);
System.out.println(Arrays.toString(points));
//System.out: [20.0, 0.0, 30.0, 10.0, 40.0, 20.0, 50.0, 30.0]
tmp.reset();
matrix.invert(tmp);
tmp.mapPoints(points);//利用反转恢复初始数据
float[] dest = new float[points.length];
matrix.mapPoints(dest, points);
System.out.println(Arrays.toString(points));
//System.out: [0.0, 0.0, 10.0, 10.0, 20.0, 20.0, 30.0, 30.0]
System.out.println(Arrays.toString(dest));
//System.out: [20.0, 0.0, 30.0, 10.0, 40.0, 20.0, 50.0, 30.0]
Arrays.fill(dest, 0f);//重新填充数组
matrix.mapPoints(dest, 2, points, 2, 2);
System.out.println(Arrays.toString(points));
//System.out: [0.0, 0.0, 10.0, 10.0, 20.0, 20.0, 30.0, 30.0]
System.out.println(Arrays.toString(dest));
//System.out: [0.0, 0.0, 30.0, 10.0, 40.0, 20.0, 0.0, 0.0]
需要注意的是 dest 数组长度要等于 src 数组长度。
public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,int pointCount)
//destIndex 是 dest 数组中开始转变的数组元素下标。可以是奇数,可以是偶数!
//这里需要注意的是 pointCount 这里是指点的个数。两两一对。pointCount=2,则是四个数组元素
12.public void mapVectors
这个方法可以过滤掉 “位移”的影响。
Matrix matrix = new Matrix();
matrix.postTranslate(20.f, 0f);
float[] points = {0, 0, 10, 10, 20, 20, 30, 30};
matrix.mapVectors(points);
System.out.println(Arrays.toString(points));
//System.out: [0.0, 0.0, 10.0, 10.0, 20.0, 20.0, 30.0, 30.0]
matrix.postScale(1, 2);
matrix.mapVectors(points);
System.out.println(Arrays.toString(points));
//System.out: [0.0, 0.0, 10.0, 20.0, 20.0, 40.0, 30.0, 60.0]
13.public boolean mapRect
Matrix matrix = new Matrix();
matrix.postTranslate(20f, 0f);
RectF rect = new RectF(0,0,10,10);
matrix.mapRect(rect);//mapRect(RectF dst, RectF src)即不改变原有数据源,用新数据源存储数据
System.out.println(rect);
//System.out: RectF(20.0, 0.0, 30.0, 10.0)
14.public float mapRadius(float radius)
Matrix matrix = new Matrix();
matrix.postScale(0.5f,1f);
int radius = 10;
float result = matrix.mapRadius(radius);
System.out.println(result);
//System.out: 7.071068
这里圆变成了椭圆,这里得到的是平均半径。
15.public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)
/**
* Set the matrix such that the specified src points would map to the specified dst points. The
* "points" are represented as an array of floats, order [x0, y0, x1, y1, ...], where each
* "point" is 2 float values.
*
* @param src The array of src [x,y] pairs (points)
* @param srcIndex Index of the first pair of src values
* @param dst The array of dst [x,y] pairs (points)
* @param dstIndex Index of the first pair of dst values
* @param pointCount The number of pairs/points to be used. Must be [0..4]
* @return true if the matrix was set to the specified transformation
*/
贴一下官方解释文档。设置矩阵以便于源坐标集合 映射成 目标集合。即把指定的点移到指定的位置。
int width = mImageView.getMeasuredWidth();
int height = mImageView.getMeasuredHeight();
float[] src = {0 ,0 , width, 0, width, height, 0, height };
float[] dest = {0, 0, width, height / 5, width/2, height, 0, height};
Bitmap bitmap = Bitmap.createBitmap(width + 300, height + 300, baseBitmap.getConfig());
Canvas canvas = new Canvas(bitmap);
Matrix matrix = new Matrix();
matrix.setPolyToPoly(src, 0, dest, 0, 4);
canvas.drawBitmap(baseBitmap, matrix, mPaint);
mImageViewAfter.setImageBitmap(bitmap);
WechatIMG19.jpeg
上面这个示例把 右上角 和 右下角的点分别移动,所以出现上图所示的变换。自己可以在纸上画一下。
pointCount | 功能 |
---|---|
0 | 什么事也做不了 |
1 | 平移 |
2 | 平移,旋转 |
3 | 平移,旋转,错切 |
4 | 任意形状的变换 |
16.public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf)
把原矩阵内容填充到目标矩阵中。如何填充看第三个参数。
ScaleToFit | 结果 |
---|---|
FILL | 填充满目标矩阵 |
START | 填充在目标矩阵开始位置 |
CENTER | 填充在目标矩阵中心位置 |
END | 填充在目标矩阵结束位置 |
网友评论