基於Qt的軌跡還原之三:代碼實現與測試

先上代碼,由於程序結構很清楚,上節也講到了Qt中實現OpenGL的框架,因此代碼讀起來沒有太大困難,如果有問題,歡迎私信~

MyGLWidget:

#ifndef MYGLWIDGET_H
#define MYGLWIDGET_H

#include <QGLWidget>

class MyGLWidget : public QGLWidget
{
    Q_OBJECT
public:
    MyGLWidget(QWidget *parent = 0);
    ~MyGLWidget();
    void setData(QVector<double> , QVector<double>, QVector<double>);

protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int width, int height);

    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void keyPressEvent(QKeyEvent *event);
    void wheelEvent(QWheelEvent *event);

public slots:
    void setXRotation(int angle);
    void setYRotation(int angle);
    void setZRotation(int angle);

    void setXtran(double x);
    void setYtran(double x);

    void setScale(double x);

signals:
    void xRotationChanged(int angle);
    void yRotationChanged(int angle);
    void zRotationChanged(int angle);

private:
    double xRot, yRot, zRot;
    double xtran, ytran;
    double scal;
    double dMax;
    QVector<double> dx, dy, dz, r, g, b;
    int dSize;
    QPoint lastPos;
};

#endif // MYGLWIDGET_H


#include <QtOpenGL>
#include "myglwidget.h"

MyGLWidget::MyGLWidget(QWidget *parent) : QGLWidget(parent)
{
    dMax=0;
    xRot =0; yRot =0; zRot =0;
    xtran=0; ytran=0;
    scal=1;

    QVector<double> rl(7), gl(7), bl(7);
    rl[0]=1.0; rl[1]=1.0; rl[2]=1.0; rl[3]=0.0; rl[4]=0.0; rl[5]=0.0; rl[6]=1.0;
    gl[0]=0.0; gl[1]=0.5; gl[2]=1.0; gl[3]=1.0; gl[4]=0.0; gl[5]=1.0; gl[6]=0.0;
    bl[0]=0.0; bl[1]=0.0; bl[2]=0.0; bl[3]=0.0; bl[4]=1.0; bl[5]=1.0; bl[6]=1.0;
    r=rl; g=gl; b=bl;
}

MyGLWidget::~MyGLWidget(){}

void MyGLWidget::setData(QVector<double> x, QVector<double> y, QVector<double> z)
{
    dSize=x.size(); dx=x; dy=y; dz=z;
    for (int i=0;i<dSize;i++)
    {
        dMax=qMax(dMax,dx.at(i));
        dMax=qMax(dMax,dy.at(i));
        dMax=qMax(dMax,dz.at(i));
    }
}

void MyGLWidget::initializeGL()
{
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);
}

void MyGLWidget::resizeGL(int width, int height)
{
    int border=qMax(width,height);
    glViewport((width-border)/2, (height-border)/2, border, border);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-dMax*1.5, +dMax*1.5, -dMax*1.5, +dMax*1.5, -dMax*10.0, dMax*10.0);
    glMatrixMode(GL_MODELVIEW);
}

void MyGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glScalef(scal,scal,scal);
    glTranslatef(xtran, ytran, 0);
    glRotatef(xRot / 16.0, 1.0, 0.0, 0.0);
    glRotatef(yRot / 16.0, 0.0, 1.0, 0.0);
    glRotatef(zRot / 16.0, 0.0, 0.0, 1.0);

    qglClearColor(Qt::gray);
    glBegin(GL_LINES);
      glColor3f(0.0f,0.0f,0.0f);
      glVertex3f(-dMax, 0.0f, 0.0f);
      glVertex3f(dMax,0.0f, 0.0f);

      glVertex3f(dMax,0.0f, 0.0f);
      glVertex3f(dMax-0.05*dMax,0.05*dMax, 0.0f);
      glVertex3f(dMax,0.0f, 0.0f);
      glVertex3f(dMax-0.05*dMax,-0.05*dMax, 0.0f);

      glColor3f(0.0f,0.0f,0.0f);
      glVertex3f(0, -dMax, 0.0f);
      glVertex3f(0,dMax, 0.0f);

      glVertex3f(0,dMax, 0.0f);
      glVertex3f(0.05*dMax,dMax-0.05*dMax, 0.0f);
      glVertex3f(0,dMax, 0.0f);
      glVertex3f(-0.05*dMax,dMax-0.05*dMax, 0.0f);

      glColor3f(0.0f,0.0f,0.0f);
      glVertex3f(0, 0, -dMax);
      glVertex3f(0, 0, dMax);

      glVertex3f(0,0, dMax);
      glVertex3f(0,0.05*dMax, dMax-0.05*dMax);
      glVertex3f(0,0, dMax);
      glVertex3f(0,-0.05*dMax, dMax-0.05*dMax);
    glEnd();

    glBegin(GL_LINES);
      glColor3f(1.0f,1.0f,1.0f);

      glVertex3f(-dMax*1.1, -dMax*1.1, -dMax*1.1);
      glVertex3f(-dMax*1.1, -dMax*1.1, dMax*1.1);
      glVertex3f(-dMax*1.1, +dMax*1.1, -dMax*1.1);
      glVertex3f(-dMax*1.1, -dMax*1.1, -dMax*1.1);
      glVertex3f(-dMax*1.1, -dMax*1.1, -dMax*1.1);
      glVertex3f(+dMax*1.1, -dMax*1.1, -dMax*1.1);

      glVertex3f(+dMax*1.1, +dMax*1.1, +dMax*1.1);
      glVertex3f(+dMax*1.1, +dMax*1.1, -dMax*1.1);
      glVertex3f(+dMax*1.1, +dMax*1.1, +dMax*1.1);
      glVertex3f(+dMax*1.1, -dMax*1.1, +dMax*1.1);
      glVertex3f(+dMax*1.1, +dMax*1.1, +dMax*1.1);
      glVertex3f(-dMax*1.1, +dMax*1.1, +dMax*1.1);

      glVertex3f(-dMax*1.1, +dMax*1.1, +dMax*1.1);
      glVertex3f(-dMax*1.1, +dMax*1.1, -dMax*1.1);
      glVertex3f(-dMax*1.1, +dMax*1.1, +dMax*1.1);
      glVertex3f(+dMax*1.1, +dMax*1.1, +dMax*1.1);
      glVertex3f(-dMax*1.1, +dMax*1.1, +dMax*1.1);
      glVertex3f(-dMax*1.1, -dMax*1.1, +dMax*1.1);

      glVertex3f(-dMax*1.1, -dMax*1.1, +dMax*1.1);
      glVertex3f(+dMax*1.1, -dMax*1.1, +dMax*1.1);
      glVertex3f(+dMax*1.1, -dMax*1.1, +dMax*1.1);
      glVertex3f(+dMax*1.1, -dMax*1.1, -dMax*1.1);
      glVertex3f(+dMax*1.1, -dMax*1.1, -dMax*1.1);
      glVertex3f(+dMax*1.1, +dMax*1.1, -dMax*1.1);
      glVertex3f(+dMax*1.1, +dMax*1.1, -dMax*1.1);
      glVertex3f(-dMax*1.1, +dMax*1.1, -dMax*1.1);
    glEnd();

    int i=1, j;
    while (i<dSize)
    {
        j=floor(i*1.0/dSize*7);
        glBegin(GL_LINES);
           glColor3f(r.at(j),g.at(j),b.at(j));
           glVertex3f( dx.at(i-1), dy.at(i-1), dz.at(i-1));
           glVertex3f( dx.at(i),   dy.at(i),   dz.at(i));
        glEnd();
        i++;
    }
}

void MyGLWidget::mousePressEvent(QMouseEvent *event)
{
    lastPos = event->pos();
}

void MyGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();

    if (event->buttons() & Qt::LeftButton) {
        setXRotation(xRot + 8 * dy);
        setYRotation(yRot + 8 * dx);
    } else if (event->buttons() & Qt::RightButton) {
        setXRotation(xRot + 8 * dy);
        setZRotation(zRot + 8 * dx);
    }

    lastPos = event->pos();
}

void MyGLWidget::keyPressEvent(QKeyEvent *e)
{
    if (e->key() == Qt::Key_1) setXRotation(xRot + 18);
    if (e->key() == Qt::Key_2) setYRotation(yRot + 18);
    if (e->key() == Qt::Key_3) setZRotation(zRot + 18);

    if (e->key() == Qt::Key_W) setYtran(dMax/10);
    if (e->key() == Qt::Key_S) setYtran(-dMax/10);
    if (e->key() == Qt::Key_A) setXtran(-dMax/10);
    if (e->key() == Qt::Key_D) setXtran(dMax/10);

    if (e->key() == Qt::Key_Q) setScale(0.1);
    if (e->key() == Qt::Key_E) setScale(-0.1);
}

void MyGLWidget::wheelEvent(QWheelEvent *e)
{
    if (e->delta()>0) setScale(0.1);
    if (e->delta()<0) setScale(-0.1);
}

static void qNormalizeAngle(int &angle)
{
    while (angle < 0)
        angle += 360 * 16;
    while (angle > 360)
        angle -= 360 * 16;
}

void MyGLWidget::setXRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != xRot) {
        xRot = angle;
        emit xRotationChanged(angle);
        updateGL();
    }
}

void MyGLWidget::setYRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != yRot) {
        yRot = angle;
        emit yRotationChanged(angle);
        updateGL();
    }
}

void MyGLWidget::setZRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != zRot) {
        zRot = angle;
        emit zRotationChanged(angle);
        updateGL();
    }
}

void MyGLWidget::setXtran(double x)
{
    xtran+=x;
    updateGL();
}

void MyGLWidget::setYtran(double x)
{
    ytran+=x;
    updateGL();
}

void MyGLWidget::setScale(double x)
{
    scal*=(1+x);
    updateGL();
}


Widget:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
       ui->setupUi(this);

       QFont myFont("Times",20);
       QFile file("data.txt");
       QVector<double> x(0),y(0),z(0),t(0);
       char buf[1000];
       double x1,x2,x3,x4;

       file.open(QIODevice::ReadOnly);
       sscanf(buf,"%lf %lf %lf %lf",&x1,&x2,&x3,&x4);
       x.fill(x1); y.fill(x2); z.fill(x3); t.fill(x4);

       while (!file.atEnd())
       {
           file.readLine(buf,sizeof(buf));
           sscanf(buf,"%lf %lf %lf %lf",&x1,&x2,&x3,&x4);
           x.append(x1); y.append(x2); z.append(x3); t.append(x4);
       }
       file.close();

       ui->touying1->addGraph();
       ui->touying1->graph(0)->setData(t,x);
       ui->touying1->xAxis->setLabel("t");
       ui->touying1->yAxis->setLabel("X");
       ui->touying1->xAxis->setLabelFont(myFont);
       ui->touying1->yAxis->setLabelFont(myFont);
       ui->touying1->rescaleAxes();

       ui->touying2->addGraph();
       ui->touying2->graph(0)->setData(t,y);
       ui->touying2->xAxis->setLabel("t");
       ui->touying2->yAxis->setLabel("Y");
       ui->touying2->xAxis->setLabelFont(myFont);
       ui->touying2->yAxis->setLabelFont(myFont);
       ui->touying2->rescaleAxes();

       ui->touying3->addGraph();
       ui->touying3->graph(0)->setData(t,z);
       ui->touying3->xAxis->setLabel("t");
       ui->touying3->yAxis->setLabel("Z");
       ui->touying3->xAxis->setLabelFont(myFont);
       ui->touying3->yAxis->setLabelFont(myFont);
       ui->touying3->rescaleAxes();

       ui->widget->setData(x,y,z);
       ui->widget->show();
}

Widget::~Widget()
{
    delete ui;
}

Widget.ui:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="0">
    <widget class="QCustomPlot" name="touying1" native="true"/>
   </item>
   <item row="0" column="1">
    <widget class="QCustomPlot" name="touying3" native="true"/>
   </item>
   <item row="1" column="0">
    <widget class="QCustomPlot" name="touying2" native="true"/>
   </item>
   <item row="1" column="1">
    <widget class="MyGLWidget" name="widget" native="true">
     <property name="focusPolicy">
      <enum>Qt::ClickFocus</enum>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <customwidgets>
  <customwidget>
   <class>MyGLWidget</class>
   <extends>QWidget</extends>
   <header>myglwidget.h</header>
   <container>1</container>
  </customwidget>
  <customwidget>
   <class>QCustomPlot</class>
   <extends>QWidget</extends>
   <header>qcustomplot.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

Main:

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.setWindowTitle("On a réussi~~單擊3D界面,旋轉:123或鼠標拖動;縮放:QE或鼠標滾輪;移動:WASD。");
    w.show();

    return a.exec();
}


Pro文件:

QT       += core gui opengl printsupport widgets

TARGET = PROJECT
TEMPLATE = app

SOURCES += main.cpp\
        widget.cpp \
    myglwidget.cpp \
    qcustomplot.cpp

HEADERS  += widget.h \
    myglwidget.h \
    qcustomplot.h

FORMS    += widget.ui

程序中測試採用密集的“螺旋線”,檢驗渲染和交互的流暢性。

所謂螺旋線,即長得像螺紋的3D曲線。在笛卡爾座標系中,比如可以表示爲:

x = 20cos(360*5t) 

y = 20sin(360*5t)

z = 25t

測試效果如下(旋轉:123或鼠標拖動;縮放:QE或鼠標滾輪;移動:WASD):









另外,程序的發佈版本也可以直接在百度網盤中下載,歡迎大家賜教!

下載地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章