矩阵表示和齐次坐标
本节矩阵变换公式较多,为方便,设置为图片格式,但实例代码可复制,这样不影响学习,如果需要word版,请私聊。为方便阅读,图片水印加到了最右下角,但是个人劳动成果,未经过同意,请勿转载
【实例】
对象为三角形,平移量(tx,ty)=(0,100);缩放量(sx,xy)=(0.5,0.5);旋转角theta=pi/2;缩放固定点fixedPt、旋转基点pivPt为三角形中心点。
#include<GL/glut.h> #include<math.h> #include<Windows.h> #include<iostream> #include<stdlib.h> using namespace std; GLsizei winWidth = 600, winHeight = 600; GLuint regHex;//显示表标识 /*设置世界坐标范围*/ GLfloat xwcMin = 0.0, xwcMax = 225.0; GLfloat ywcMin = 0.0, ywcMax = 225.0; class wcPt2D { public: GLfloat x, y; }; typedef GLfloat Matrix3x3[3][3]; Matrix3x3 matComposite;//2D变换复合矩阵 const GLdouble pi = 3.14159; static void init(void) { //初始化函数,并加入表 glClearColor(1.0, 1.0, 1.0, 0.0);//设置为白色背景 } void Matrix3x3SetIdentity(Matrix3x3 matIdent3x3) { //生成一个单位矩阵 GLint row, col; for (row = 0; row < 3;++row) for (col = 0; col < 3;++col) { matIdent3x3[row][col] = (row==col); } } void matrix3x3Premultiply(Matrix3x3 m1, Matrix3x3 m2) { //矩阵的乘法,结果储存在M2中 GLint row, col; Matrix3x3 matTemp; for (row = 0; row < 3; ++row) for (col = 0; col < 3; col++) { matTemp[row][col] = m1[row][0] * m2[0][col] + m1[row][1] * m2[1][col] + m1[row][2] * m2[2][col]; } for (row = 0; row < 3; ++row) for (col = 0; col < 3; col++) { m2[row][col] = matTemp[row][col]; } } void translate2D(GLfloat tx, GLfloat ty) { /*通过偏移量tx,ty产生平移矩阵matTransl之后,再通过矩阵的乘法,实现对象的平移*/ Matrix3x3 matTransl;//平移矩阵 Matrix3x3SetIdentity(matTransl); matTransl[0][2] = tx; matTransl[1][2] = ty; /*矩阵乘法,平移*/ matrix3x3Premultiply(matTransl,matComposite); } void rotate2d(wcPt2D pivotPt, GLfloat theta) { //基准点pivotPt,旋转角度theta,产生旋转矩阵后相乘 Matrix3x3 matRot;//旋转矩阵 Matrix3x3SetIdentity(matRot); matRot[0][0] = cos(theta); matRot[0][1] = -sin(theta); matRot[0][2] = pivotPt.x*(1 - cos(theta)) + pivotPt.y*sin(theta); matRot[1][0] = sin(theta); matRot[1][1] = cos(theta); matRot[1][2] = pivotPt.y*(1 - cos(theta)) - pivotPt.x*sin(theta); /*矩阵乘法,旋转*/ matrix3x3Premultiply(matRot, matComposite); } void scale2D(GLfloat sx, GLfloat sy, wcPt2D fixedPt) { //固定点fixedPt,缩放系数sx,sy,产生缩放矩阵 Matrix3x3 matScale; Matrix3x3SetIdentity(matScale); matScale[0][0] = sx; matScale[0][2] = (1 - sx)*fixedPt.x; matScale[1][1] = sy; matScale[1][2] = (1 - sy)*fixedPt.y; matrix3x3Premultiply(matScale, matComposite); } void translate2D(GLint nverts, wcPt2D *verts) { //对象顶点与复合变换矩阵的乘法,得到坐标变换后的点 GLint k; GLfloat temp; for (k = 0; k < nverts; ++k) { temp = verts[k].x*matComposite[0][0] + verts[k].y*matComposite[0][1] + matComposite[0][2]; verts[k].y = verts[k].x*matComposite[1][0] + verts[k].y*matComposite[1][1] + matComposite[1][2]; verts[k].x = temp; } } void triangle(wcPt2D *verts) { //输出一个三角形 GLint k; glBegin(GL_TRIANGLES); cout << "当前顶点坐标为:"; for (k = 0; k < 3; ++k) { glVertex2f(verts[k].x,verts[k].y); cout << verts[k].x << ","<< verts[k].y << endl; } glEnd(); } void displayFcn() { GLint nverts = 3; wcPt2D verts[3] = { { 50.0, 25.0 }, { 150.0, 25.0 }, {100.0,100.0} };//定义一个三角形 wcPt2D centroidPt;//中点坐标顶点对象 GLint k, xSum = 0, ySum = 0;//xSum,ySum用于计算中点坐标,作为基点 for (k = 0; k < nverts; ++k) { xSum += verts[k].x; ySum += verts[k].y; } centroidPt.x = GLfloat(xSum )/ GLfloat(nverts); centroidPt.y = GLfloat(ySum) / GLfloat(nverts); wcPt2D pivPt, fixedPt;//旋转基点,缩放固定点 pivPt = centroidPt; fixedPt =centroidPt; GLfloat tx = 0.0, ty = 100.0; GLfloat sx = 0.5, sy = 0.5; GLdouble theta = pi / 2.0; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 1.0); triangle(verts);//蓝色三角形为原始三角形 Matrix3x3SetIdentity(matComposite); scale2D(sx, sy, fixedPt);//缩放 rotate2d(pivPt, theta);//旋转 translate2D(tx, ty);//移动 translate2D(nverts, verts); glColor3f(1.0, 0.0, 0.0);//红色为移动后的三角形 triangle(verts); glFlush(); } void winReshapeFcn(int newWidth, int newHeight) { //窗口重定形函数 glMatrixMode(GL_PROJECTION); glLoadIdentity();//将当前的用户坐标系的原点移到了屏幕中心:类似于一个复位操作 gluOrtho2D(xwcMin,xwcMax, ywcMin, ywcMax); glClear(GL_COLOR_BUFFER_BIT); } int main(int argc, char**argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(50, 50); glutInitWindowSize(winWidth, winHeight); glutCreateWindow("Example"); init(); glutDisplayFunc(displayFcn); glutReshapeFunc(winReshapeFcn); glutMainLoop(); return 0; }结果: