欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt5.12+OpenGL 计算机图形学(第四版)第4章 例子1

程序员文章站 2024-03-17 17:32:34
...

因为使用的是Qt框架,没有使用GLUT,所以改写了书中部分代码:

1. 文本用QString数组保存。

2. 绘制字符没有使用GLUT函数,直接使用QPainter进行绘制,Qt绘图坐标是以左上角为原点(0,0),因此,坐标也需要进行变换。

关键部分源代码,其它可以参照前面章节的例子。

a. 绘制折线图

QString label[12] = {
    "Jan", "Feb", "Mar", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

GLint dataValue[12] = {
    420, 342, 324, 310, 262, 185, 190, 196, 217, 240, 312, 438
};

void OpenGLWidget::lineGraph()
{
    GLint month, k;
    GLint xRaster = 20;
    GLint yRaster = 150;
    GLint x = 30;

    int h = this->height();

    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0, 0.0, 1.0);

    glBegin(GL_LINE_STRIP);
        for(k=0; k< 12; k++)
            glVertex2i(x+k*50, dataValue[k]);
    glEnd();

    QPainter painter(this);
    painter.setPen(Qt::red);
    painter.setFont(QFont("Arial", 10));
    for(k=0; k<12; k++) {
        painter.drawText(x+k*50-5, h-dataValue[k]+10, "*");
    }

    painter.setPen(Qt::black);
    painter.setFont(QFont("Helvecica", 12));
    for(month=0; month<12; month++) {
        for(k=3*month; k<3*month+3; k++)
            painter.drawText(xRaster, h - yRaster, label[month]);
        xRaster += 50;
    }

    glFlush();
}

效果图:

Qt5.12+OpenGL 计算机图形学(第四版)第4章 例子1

b. 绘制直方图

void OpenGLWidget::barChart()
{
    GLint month, k;
    GLint xRaster = 20;
    GLint yRaster = 150;
    int h = this->height();

    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0, 0.0, 0.0);
    for(k=0; k<12; k++)
        glRecti(20+k*50, 165, 40+k*50, dataValue[k]);

    QPainter painter(this);
    painter.setPen(Qt::black);
    painter.setFont(QFont("Helvecica", 12));
    for(month=0; month<12; month++) {
        for(k=3*month; k<3*month+3; k++)
            painter.drawText(xRaster, h - yRaster, label[month]);
        xRaster += 50;
    }
}

效果图:

Qt5.12+OpenGL 计算机图形学(第四版)第4章 例子1

c. 绘制饼图

关于中点画圆的算法可以参考https://www.cnblogs.com/clairvoyant/p/5528067.html这篇文章,讲得还是比较清楚的。


GLsizei winWidth = 400, winHeight = 300;

const GLdouble twoPi = 6.283185;

void OpenGLWidget::pieChart()
{
    QPoint circCtr, piePt;
    GLint radius = winWidth / 4;

    GLdouble sliceAngle, previousSliceAngle = 0.0;

    GLint k, nSlices = 12;

    GLfloat dataValues[12] = {
        10.0, 7.0, 13.0, 5.0, 13.0, 14.0, 3.0, 16.0, 5.0, 3.0, 17.0, 8.0
    };
    GLfloat dataSum = 0.0;

    circCtr.setX(winWidth / 2);
    circCtr.setY(winHeight / 2);
    circleMidpoint(circCtr, radius);

    for(k=0; k<nSlices; k++) {
        dataSum += dataValues[k];
    }

    for(k=0; k<nSlices; k++) {
        sliceAngle = twoPi * dataValues[k] / dataSum + previousSliceAngle;
        piePt.setX(circCtr.x() + radius * cos(sliceAngle));
        piePt.setY(circCtr.y() + radius * sin(sliceAngle));

        glBegin(GL_LINES);
            glVertex2i(circCtr.x(), circCtr.y());
            glVertex2i(piePt.x(), piePt.y());
        glEnd();
        previousSliceAngle = sliceAngle;
    }
}

void putpixel(int x0, int y0, int x, int y)
{
    glBegin(GL_POINTS);
        glVertex2f(x0 + x, y0 + y);
        glVertex2f(x0 + x, y0 - y);
        glVertex2f(x0 - x, y0 + y);
        glVertex2f(x0 - x, y0 - y);
        glVertex2f(x0 + y, y0 + x);
        glVertex2f(x0 + y, y0 - x);
        glVertex2f(x0 - y, y0 + x);
        glVertex2f(x0 - y, y0 - x);
    glEnd();
}

/*
 * 通过中点和半径画圆
 */
void OpenGLWidget::circleMidpoint(QPoint c, int r)
{
    int x, y, p;
    x = 0; y = r; p = 1 - r;
    while(x <= y) {
        putpixel(c.x(), c.y(), x, y);
        if ( p < 0 ) {
            p += 2 * x + 1;
        } else {
            p += 2 * (x - y) + 1;
            y--;
        }
        x++;
    }
}

效果图:

Qt5.12+OpenGL 计算机图形学(第四版)第4章 例子1