转载请注明出处:http://blog.csdn.net/ljmingcom304/article/details/49302395
本文出自:【梁敬明的博客】
1.矩阵表示二维图形
在二维空间中,可以通过
2.矩阵的几何变换
矩阵的基本几何变换都是相对于原点或座标轴进行平移、旋转、缩放、错切等。
在操作矩阵的几何变换前首先需要科普下齐次座标法,所谓的齐次座标法就是将n维的向量用n+1维来表示,主要用计算矩阵的几何变换,例如平移、旋转、缩放等。例如:将点A(1,1)用矩阵的二维行向量表示为[1,1],采用齐次座标法用矩阵的三维行向量表示为[1,1,1]。所以三角形ABC用矩阵也可以表示为
矩阵的几何变换的计算方式为:变换前图形矩阵×变换矩阵1×变换矩阵2…=变换后图形矩阵(当一个矩阵进行多次几何变换时,只需要连乘即可)。假设一个三角形三个顶点座标分别为
public class MatrixUtils {
/**
* 多矩阵相乘
* @param arrays 变换前图形矩阵
* @param arg 变换矩阵
* @return 变换后图形矩阵
*/
public static float[][] matrixsMcl(float[][] arrays, float[][]... args) {
float[][] results = arrays;
for (float[][] arg : args) {
results = matrixMcl(results, arg);
}
return results;
}
/**
* 两矩阵相乘
* @param arrays 变换前图形矩阵
* @param arg 变换矩阵
* @return 变换后图形矩阵
*/
private static float[][] matrixMcl(float[][] arrays, float[][] arg) {
int i, j, k;
float[][] results = new float[arrays.length][];
for (i = 0; i < arrays.length; i++) {
float[] array = arrays[i];
results[i] = new float[array.length];
float[][] newArg = transposeF(arg);
for (j = 0; j < newArg.length; j++) {
float[] newArgJ = newArg[j];
int count = 0;
for (k = 0; k < newArgJ.length; k++) {
count += array[k] * newArgJ[k];
}
results[i][j] = count;
}
}
return results;
}
/**
* 矩阵转置:所有元素绕着一条从第1行第1列元素出发的右下方45度的射线作镜面反转
* @param arrays 转置前矩阵
* @return 转置后矩阵
*/
private static float[][] transposeF(float[][] arrays) {
int i, j;
float[][] newArrays = new float[arrays[0].length][arrays.length];
for (i = 0; i < arrays.length; i++) {
for (j = 0; j < arrays[i].length; j++) {
newArrays[j][i] = arrays[i][j]; // 转置核心
}
}
return newArrays;
}
......
}
##2.1.平移变换
平移变换:图形中的每一个点在给定方向上移动相同距离所进行的变换。
二维图形的平移变换矩阵为T=![平移](https://img-blog.csdn.net/20151021160844879)
public class MatrixUtils { ...... /** 平移 */ public static Point[] translate(float x, float y, Point... ps) { for (Point point : ps) { float[][] points = { { point.x, point.y, 1f } }; float[][] translate = { { 1, 0, 0 }, { 0, 1, 1 }, { x, y, 1 } }; //矩阵相乘 float[][] results = matrixMcl(points, translate); point.x = (int) results[0][0]; point.y = (int) results[0][1]; } return ps; } }##2.2.缩放变换 缩放变换:图形以固定点为中心,按相同比例进行放大或缩小所进行的变换。 二维图形的以原点为中心缩放变换矩阵为T=
![缩放](https://img-blog.csdn.net/20151021160912756)
public class MatrixUtils { ...... /** 缩放 */ public static Point[] scale(float x, float y, Point... ps) { for (Point point : ps) { float[][] points = { { point.x, point.y, 1 } }; float[][] scale = { { x, 0, 0 }, { 0, y, 1 }, { 0, 0, 1 } }; //矩阵相乘 float[][] results = matrixMcl(points, scale); point.x = (int) results[0][0]; point.y = (int) results[0][1]; } return ps; } }##2.3.对称变换 缩放变换:图形中的每一个点关于某个点或某条线进行对称后所得的变换。 二维图形的关于原点或直线对称变换矩阵为T=
![对称](https://img-blog.csdn.net/20151021160934656)
public class MatrixUtils { ...... /** X轴对称 */ public static Point[] projectX(Point... ps) { for (Point point : ps) { float[][] points = { { point.x, point.y, 1 } }; float[][] project = { { 1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } }; //矩阵相乘 float[][] results = matrixMcl(points, project); point.x = (int) results[0][0]; point.y = (int) results[0][1]; } return ps; } /** Y轴对称 */ public static Point[] projectY(Point... ps) { for (Point point : ps) { float[][] points = { { point.x, point.y, 1 } }; float[][] project = { { -1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; //矩阵相乘 float[][] results = matrixMcl(points, project); point.x = (int) results[0][0]; point.y = (int) results[0][1]; } return ps; } /** 原点对称 */ public static Point[] projectP(Point... ps) { for (Point point : ps) { float[][] points = { { point.x, point.y, 1 } }; float[][] scale = { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } }; //矩阵相乘 float[][] results = matrixMcl(points, scale); point.x = (int) results[0][0]; point.y = (int) results[0][1]; } return ps; } }##2.4.旋转变换 旋转变换:图形中的中的每一个点按相同的方向、相同的旋转角度旋转所进行的变换。 二维图形的关于原点的旋转变换矩阵为T=
![旋转](https://img-blog.csdn.net/20151021160955944)
public class MatrixUtils { ...... /** 旋转 */ public static Point[] rotate(float angle, Point... ps) { for (Point point : ps) { float cos = (float) Math.cos(angle); float sin = (float) Math.sin(angle); float[][] points = { { point.x, point.y, 1 } }; float[][] rotate = { { cos, -sin, 0 }, { sin, cos, 1 }, { 0, 0, 1 } }; //矩阵相乘 float[][] results = matrixMcl(points, rotate); point.x = (int) results[0][0]; point.y = (int) results[0][1]; } return ps; } }##2.5.错切变换 错切变换:图形中的各点在某一方向上的座标保持不变,在另一方向上的座标进行线性变换,或在两座标方向的座标都进行的线性变换。 二维图形的错切变换矩阵为T=
![错切](https://img-blog.csdn.net/20151021161021735)
public class MatrixUtils { ...... /** 错切 */ public static Point[] skew(float x, float y, Point... ps) { for (Point point : ps) { float[][] points = { { point.x, point.y, 1 } }; float[][] skew = { { 1, y, 0 }, { x, 1, 0 }, { 0, 0, 1 } }; float[][] results = matrixMcl(points, skew); point.x = (int) results[0][0]; point.y = (int) results[0][1]; } return ps; } }#3.通过自定义控件实现矩阵几何变换 首先在自定义控件中基于控制点绘制一个初始的矩形方框:
public class MatrixView extends View {
private Paint paint;
private Path path;
private Point[] ps;
private int w;
private int h;
private Point p1;
private Point p2;
private Point p3;
private Point p4;
public MatrixView(Context context) {
this(context, null);
}
public MatrixView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MatrixView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
paint.setAntiAlias(true);//抗锯齿使边缘更加平滑
paint.setStrokeWidth(3);//边框宽度
paint.setStyle(Style.STROKE);
paint.setColor(Color.RED);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
this.w = w;//控件的宽度
this.h = h;//控件的高度
p1 = new Point(-w / 2, -h / 4);
p2 = new Point(0, -h / 4);
p3 = new Point(0, 0);
p4 = new Point(-w / 2, 0);
ps = new Point[] { p1, p2, p3, p4 };
path = new Path();
}
/**通过Path路径绘制一个矩形*/
private void toShape(boolean isClose, Path path, Point... ps) {
for (int i = 0; i < ps.length; i++) {
if (i == 0) {
path.moveTo(ps[0].x, ps[0].y);
} else {
path.lineTo(ps[i].x, ps[i].y);
}
}
if (isClose)
path.close();
}
@Override
protected void onDraw(Canvas canvas) {
// 绘制初始图形
toShape(true, path, ps);
//将画布的原点移动到屏幕的中央
canvas.translate(w / 2, h / 2);
canvas.drawPath(path, paint);
path.reset();
}
......
}
然后基于控制点对当前View进行几何变换:public class MatrixView extends View { ...... /**还原*/ public void clear() { ps = new Point[] { new Point(-w / 2, -h / 4), new Point(0, -h / 4), new Point(0, 0), new Point(-w / 2, 0) }; invalidate(); } /** 平移 */ public void translate() { ps = MatrixUtils.translate(200, 200, ps); invalidate(); } /** 错切 */ public void skew() { ps = MatrixUtils.skew(-0.5f, 0, ps); invalidate(); } /** 缩放 */ public void scale() { ps = MatrixUtils.scale(0.5f, 0.5f, ps); invalidate(); } /** 旋转 */ public void rotate() { ps = MatrixUtils.rotate(-(float) Math.PI / 4, ps); invalidate(); } /** X轴对称 */ public void projectX() { ps = MatrixUtils.projectX(ps); invalidate(); } /** Y轴对称 */ public void projectY() { ps = MatrixUtils.projectY(ps); invalidate(); } /** 原点对称 */ public void projectP() { ps = MatrixUtils.projectP(ps); invalidate(); } }
最后显示效果图: