图形学实验:简单几何体的平移,缩放,旋转等几何变换,进行图形化交互

该博客介绍了使用OpenGL进行2D图形的几何变换,包括平移、旋转和缩放操作。通过设置变换矩阵并应用到顶点坐标上,实现了图形的动态变换。用户可以通过鼠标交互选择不同的变换模式,如平移、旋转和缩放,并实时观察图形的变化效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图形的几何变换也就是将图形的顶点的坐标进行变换后,根据新的顶点进行绘制的几何图形。

几何变换操作的过程是将变换矩阵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();//循环调用与事件相关的函数
}

测试:

运行出来的图形窗口点击右键,出来菜单,如下点击选择画图并在窗口点击绘制的图形的顶点的位置:

 继续右键选择平移:

继续点击右键选择 旋转:

继续点击右键选择缩放:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值