矩阵表示和齐次坐标
本节矩阵变换公式较多,为方便,设置为图片格式,但实例代码可复制,这样不影响学习,如果需要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;
}
结果: