图形的几何变换也就是将图形的顶点的坐标进行变换后,根据新的顶点进行绘制的几何图形。
几何变换操作的过程是将变换矩阵M作用于齐次坐标点P生成新的坐标点P´,即P´=M·P。
//缩放
void scale2D(GLfloat sx, GLfloat sy, int x, int y) {
Matrix matScale;
setMatrixIdentity(matScale);//得到一个单位矩阵
matScale[0][0] = sx;
matScale[0][2] = (1 - sx) * x;
matScale[1][1] = sy;
matScale[1][2] = (1 - sy) * y;
matrixpreMultiply(matScale, Composite);//两个矩阵相乘
}
//平移
void translate2D(GLfloat tx, GLfloat ty) {
Matrix matTransl;
setMatrixIdentity(matTransl);//设置为单位矩阵
matTransl[0][2] = tx;
matTransl[1][2] = ty;
matrixpreMultiply(matTransl, Composite);//矩阵相乘
}
//旋转
void rotate2D(int x, int y, float theta) {
theta = theta / 180 * PI;
Matrix matRot;
setMatrixIdentity(matRot);//得到单位矩阵
matRot[0][0] = cos(theta);
matRot[0][1] = -sin(theta);
matRot[0][2] = x * (1 - cos(theta)) + y * sin(theta);
matRot[1][0] = sin(theta);
matRot[1][1] = cos(theta);
matRot[1][2] = y * (1 - cos(theta)) - x * sin(theta);
matrixpreMultiply(matRot, Composite);矩阵相乘
}
上代码:
#include<gl/glut.h>
#include<iostream>
#include<cmath>
#include<vector>
#define PI 3.14159265358
using namespace std;
struct position {//存储所有点
double x;
double y;
};
typedef GLfloat Matrix[3][3];
Matrix Composite;//复合矩阵
vector<position> xy;//存储顶点
position tmp;
//r,d,v,g分别为平移,绘制多边形,旋转,缩放
#define TRANSLATE 0
#define DRAWPOLYGON 1
#define ROTATE 2
#define SCALE 3
int tran_x, tran_y;
int _xtmp, _ytmp;//作为缩放变量用
int mode = DRAWPOLYGON;//默认为绘制模式
//该方法将矩阵设为单位矩阵
void setMatrixIdentity(Matrix mat) {
GLint row, col;
for (row = 0;row < 3;row++) {
for (col = 0;col < 3;col++)
mat[row][col] = (row == col);
}
}
//进行全局的初始化
void init() {
glClearColor(1.0, 1.0, 1.0, 1.0);//设置绘制窗口颜色为白色
glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容
/*设置为投影类型模式和其他观察参数*/
glPointSize(3.0f);
glColor3f(1.0, 0.0, 0.0);//设置颜色为红
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 800, 650, 0);
setMatrixIdentity(Composite);
}
//矩阵相乘
void matrixpreMultiply(Matrix m1, Matrix m2) {
GLint row, col;
Matrix tmp;
for (row = 0;row < 3;row++) {
for (col = 0;col < 3;col++) {
tmp[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] = tmp[row][col];
}
}
}
//平移
void translate2D(GLfloat tx, GLfloat ty) {
Matrix matTransl;
setMatrixIdentity(matTransl);//设置为单位矩阵
matTransl[0][2] = tx;
matTransl[1][2] = ty;
matrixpreMultiply(matTransl, Composite);
}
//旋转
void rotate2D(int x, int y, float theta) {
theta = theta / 180 * PI;
Matrix matRot;
setMatrixIdentity(matRot);
matRot[0][0] = cos(theta);
matRot[0][1] = -sin(theta);
matRot[0][2] = x * (1 - cos(theta)) + y * sin(theta);
matRot[1][0] = sin(theta);
matRot[1][1] = cos(theta);
matRot[1][2] = y * (1 - cos(theta)) - x * sin(theta);
matrixpreMultiply(matRot, Composite);
}
//缩放
void scale2D(GLfloat sx, GLfloat sy, int x, int y) {
Matrix matScale;
setMatrixIdentity(matScale);
matScale[0][0] = sx;
matScale[0][2] = (1 - sx) * x;
matScale[1][1] = sy;
matScale[1][2] = (1 - sy) * y;
matrixpreMultiply(matScale, Composite);
}
//复合矩阵
void transformVerts2D() {
GLfloat tmp;
for (int i = 0;i < xy.size();i++) {
tmp = Composite[0][0] * xy[i].x + Composite[0][1] * xy[i].y + Composite[0][2];
xy[i].y = Composite[1][0] * xy[i].x + Composite[1][1] * xy[i].y + Composite[1][2];
xy[i].x = tmp;
}
DrawPicture();
setMatrixIdentity(Composite);
}
//绘制多边形
void DrawPicture() {
// glEnable(GL_POLYGON_STIPPLE);
glPolygonMode(GL_BACK, GL_LINE);//设置反面为线性模式
glPolygonMode(GL_FRONT, GL_LINE);//设置正面为线性模式
glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容
glBegin(GL_POLYGON);
for (unsigned int i = 0;i < xy.size();i++) {
glVertex2f(xy[i].x, xy[i].y);
}
glEnd();
glFlush();
}
//鼠标拖动后根据选择做相应的移动
void Drawmouse(int x, int y) {
float ssx = 1, ssy = 1;
switch (mode)
{
//q,w,e,r
case TRANSLATE:
translate2D(x - tran_x, y - tran_y);
transformVerts2D();
tran_x = x;
tran_y = y;
break;
case DRAWPOLYGON:
break;
case ROTATE:
if (x <= _xtmp && y >= _ytmp)
rotate2D(tran_x, tran_y, -8);
else
rotate2D(tran_x, tran_y, 8);
transformVerts2D();
_xtmp = x;
_ytmp = y;
break;
case SCALE:
/*不等比例缩放*/
if (x > _xtmp) {
ssx += 0.1f;
}
else if (x < _xtmp && ssx>0) {
ssx -= 0.1f;
}
if (y < _ytmp) {
ssy += 0.1f;
}
else if (y > _ytmp && ssy > 0) {
ssy -= 0.1f;
}
/*等比例缩放*/
if(x<=_xtmp&&y>=_ytmp){
ssx-=0.1f;
ssy-=0.1f;
}else{
ssx+=0.1f;
ssy+=0.1f;
}
scale2D(ssx, ssy, tran_x, tran_y);
transformVerts2D();
_xtmp = x;
_ytmp = y;
break;
default:
break;
}
}
//监听鼠标状态并回应相应的移动
void mymouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
switch (mode)
{
case TRANSLATE://平移
tran_x = x;
tran_y = y;
break;
case DRAWPOLYGON://画图
tmp.x = x;
tmp.y = y;
xy.push_back(tmp);//将一个新的点加到vector的最后面
DrawPicture();
break;
case ROTATE://旋转
tran_x = x;
tran_y = y;
_xtmp = x;
_ytmp = y;
break;
case SCALE://缩放
tran_x = x;
tran_y = y;
break;
default:
break;
}
}
}
//监听键盘输入选择不同的移动
void myKeyboardUp(unsigned char key, int x, int y) {
switch (key)
{
case 'r':mode = TRANSLATE;
break;
case 'd':mode = DRAWPOLYGON;
break;
case 'v':mode = ROTATE;
break;
case 'g':mode = SCALE;
break;
default:
break;
}
}
void myDisplay() {
glFlush();
}
void mymenu(int id) {
if (id == 0)
mode = 0;
else if (id == 1)
mode = 1;
else if (id == 2)
mode = 2;
else if (id == 3)
mode = 3;
}
//主函数
int main(int argc, char ** argv) {
glutInit(&argc, argv);//初始化
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置绘制模式
glutInitWindowPosition(500, 300);
glutInitWindowSize(800, 650);
glutCreateWindow("实验4.二维图形的变换");//创建窗口
int id = glutCreateMenu(mymenu);//添加菜单
//以下为菜单添加条目
glutAddMenuEntry("TRANSLATE", 0);
glutAddMenuEntry("DRAWPOLYGON", 1);
glutAddMenuEntry("ROTATE", 2);
glutAddMenuEntry("SCALE", 3);
glutAttachMenu(GLUT_RIGHT_BUTTON);//把菜单和鼠标右键关联起来:菜单的显示方式:鼠标右键
init();//进行初始化
glutDisplayFunc(myDisplay);
glutMouseFunc(mymouse);//鼠标监听回调函数
glutMotionFunc(Drawmouse);//鼠标拖动
glutKeyboardUpFunc(myKeyboardUp);//键盘弹起状态
glutMainLoop();//循环调用与事件相关的函数
}
测试:
运行出来的图形窗口点击右键,出来菜单,如下点击选择画图并在窗口点击绘制的图形的顶点的位置:
继续右键选择平移:
继续点击右键选择 旋转:
继续点击右键选择缩放: