Qt development technology: Q3D chart development notes (3): Q3DSurface three-dimensional surface chart introduction, Demo and code explanation

If the article is an original article, please indicate the source of the original article when reprinting.
The blog address of this article: https://hpzwl.blog.csdn.net/article/details/130264470

Dear readers, knowledge is infinite but manpower is limited. You can either change your needs, find professionals, or do your own research.

Red Fatty Network Science and Technology Blog Encyclopedia: Development technology collection (including Qt practical technology, Raspberry Pi, 3D, OpenCV, OpenGL, ffmpeg, OSG, single-chip microcomputer, combination of software and hardware, etc.) is continuously being updated... (click on the portal)

Qt Development Column: Development Technology (click on the portal)

Previous: " Qt Development Technology: Q3D Chart Development Notes (2): Q3DBar 3D Histogram Introduction, Demo and Detailed Code Explanation "
Next: Stay tuned...


foreword

  qt provides q3d for 3D development. Although this framework has not been widely used and is not so successful, and its performance is also very lacking, ordinary point-to-point application display is still possible.
  Among them are gorgeous three-dimensional charts, which can be used when the amount of data is not large.
  The basic q3d scatter plot and histogram were introduced earlier, and this article introduces the basic three-dimensional surface plot.


Demo: Q3DSurface scatter plot demonstration effect

  insert image description here
  insert image description here
  insert image description here

download link:

  Demo running package download address: https://download.csdn.net/download/qq21497936/87708061
  QQ group download: Please click on the main avatar of the blog to enter the homepage of the blog, check the right side, there is the contact information of the QQ group, (click " File "Search for " q3d ", the group and blog posts will be updated simultaneously)
  Baidu Netdisk download address: https://pan.baidu.com/s/1bWNR5E6Y9utu8iey9rIu0g?pwd=1234


3D chart provided by Q3D

  Depends on QtDataVisualization. When installing qt, choose to install the QtDataVisualization module.

Q3DScatter scatter plot

  The performance of Q3D scatter plot can support about 1000 points without lagging. It depends on the PC. What is the concept of 1000 points? It can be understood as: 10x10x10 area, one data point for each area.
  insert image description here

Q3DBars histogram

  The histogram of Q3D is similar to the scatter plot in performance.
   insert image description here

Q3DSurface plane bump map, plane texture map, plane curve map

  The histogram of Q3D is similar to the scatter plot in performance.
  insert image description here


Q3DSurface Plane Curve

Introduction

  The Q3DSurface class provides methods for rendering 3D surface images. This class enables developers to render 3D surface maps and view them by freely rotating the scene. Visual properties of surfaces, such as drawing modes and shading, can be controlled through QSurface3DSeries.
  Q3DSurface supports selection by displaying highlighted spheres on data points that the user clicks with the left mouse button (when using the default input handler) or by selection via QSurface3DSeries. The selection pointer is accompanied by a label which, by default, shows the value of the data point and the coordinates of the point.
The value range and label format displayed on the axis can be controlled with QValue3DAxis.
  To rotate the graph, hold down the right mouse button and move the mouse. Zooming is done using the mouse wheel. Both assume the default input handler is in use.
  If no axes are explicitly set to the Q3DSurface, temporary default axes with no labels are created. These default axes can be modified via the axes accessor, but as soon as any axis for an orientation is explicitly set, the default axis for that orientation will be destroyed.

Construct a minimal Q3D planar graph

  First, construct the Q3D surface. Since in this example we are running the graphics as a top-level window, we need to clear the Qt::FramelessWindowHint flag, which is set by default:

Q3DSurface surface; 
surface.setFlags(surface.flags() ^ Qt::FramelessWindowHint);

  Now the Q3DSurface is ready to receive data to render. Create data elements to receive values:

QSurfaceDataArray *data = new QSurfaceDataArray;
QSurfaceDataRow *dataRow1 = new QSurfaceDataRow;
QSurfaceDataRow *dataRow2 = new QSurfaceDataRow;

  First feed the data to the row elements, then add their pointers to the data elements:

*dataRow1 << QVector3D(0.0f, 0.1f, 0.5f) << QVector3D(1.0f, 0.5f, 0.5f);
*dataRow2 << QVector3D(0.0f, 1.8f, 1.0f) << QVector3D(1.0f, 1.2f, 1.0f);
*data << dataRow1 << dataRow2;

  Create a new series and set data for it:

QSurface3DSeries *series = new QSurface3DSeries;
series->dataProxy()->resetArray(data);   
surface.addSeries(series);

  Finally, make it visible:

surface.show();

  The complete code required to create and display this plot is:

#include <QtDataVisualization>
using namespace QtDataVisualization;
int main(int argc, char **argv)
{
    
    
    QGuiApplication app(argc, argv);

    Q3DSurface surface;
    surface.setFlags(surface.flags() ^ Qt::FramelessWindowHint);
    QSurfaceDataArray *data = new QSurfaceDataArray;
    QSurfaceDataRow *dataRow1 = new QSurfaceDataRow;
    QSurfaceDataRow *dataRow2 = new QSurfaceDataRow;

    *dataRow1 << QVector3D(0.0f, 0.1f, 0.5f) << QVector3D(1.0f, 0.5f, 0.5f);
    *dataRow2 << QVector3D(0.0f, 1.8f, 1.0f) << QVector3D(1.0f, 1.2f, 1.0f);
    *data << dataRow1 << dataRow2;

    QSurface3DSeries *series = new QSurface3DSeries;
    series->dataProxy()->resetArray(data);
    surface.addSeries(series);
    surface.show();

    return app.exec();
}

  running result:
  insert image description here

  The scene can be rotated, zoomed in, and an item can be selected to see its position, but other interactions are not included in this minimal code example.


Q3Ddemo construction process analysis

Step 1: Confirm the installation of the QtDataVisualization module

  How to confirm it is to check whether there is a Q3dscatter class in the help file. Generally, the corresponding help file will be available only after the module is installed. If not, reinstall qt or install the module separately.
  insert image description here

Step 2: Add modules to the project configuration file

  Q3d is in the data visualization module and needs to be added in the pro or pri configuration file.

QT += datavisualization

  insert image description here

Step 3: Add the header files used

  Use to add header files to Q3DBar related classes, mainly use Q3DBar, QBar3DSeries, QBarDataRow and so on.

#include <Q3DBars>
#include <Q3DTheme>
#include <QBar3DSeries>
#include <QVector3D>

  insert image description here

Step 4: Add a Namespace

  At this time, the corresponding class still cannot be used, and the namespace needs to be added:

using namespace QtDataVisualization;

  insert image description here

Step 5: Q3D's icon base construction framework

  The following is the Q3DSurface basic construction process including comments (note the display of the axis, see " Pit 1 " at the end, pay attention to the surface rules of the data, see " Pit 2 "

_pQ3DSurface = new Q3DSurface();
_pContainer = QWidget::createWindowContainer(_pQ3DSurface, this);
// 设置轴文本
{
    
    
    // 注意笛卡尔坐标
    _pQ3DSurface->axisX()->setTitle("经度(°)");
    _pQ3DSurface->axisX()->setTitleVisible(true);
    _pQ3DSurface->axisY()->setTitle("高度(m)");
    _pQ3DSurface->axisY()->setTitleVisible(true);
    _pQ3DSurface->axisZ()->setTitle("纬度(°)");
    _pQ3DSurface->axisZ()->setTitleVisible(true);
}
// 设置轴范围
{
    
    
    // 注意笛卡尔坐标
    _pQ3DSurface->axisX()->setRange(0, 359);
    _pQ3DSurface->axisY()->setRange(0, 100);
    _pQ3DSurface->axisZ()->setRange(0, 359);
}

// 生成一个曲线
_pSurface3DSeries = new QSurface3DSeries(_pQ3DSurface);
// 设置渲染平滑
_pSurface3DSeries->setMeshSmooth(true);
// 设置渲染模式
//   DrawWireframe           : 绘制栅格
//   DrawSurface             : 绘制表面
//   DrawSurfaceAndWireframe : 绘制栅格和图表面
_pSurface3DSeries->setDrawMode(QSurface3DSeries::DrawSurface);

// 视图添加该曲线
_pQ3DSurface->addSeries(_pSurface3DSeries);
// 设置阴影质量
_pQ3DSurface->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
// 设置视角
_pQ3DSurface->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);
// 设置子网格
_pQ3DSurface->activeTheme()->setGridEnabled(true);

#if 1
// 添加模拟数据
QSurfaceDataArray *pSurfaceDataArray = new QSurfaceDataArray;
#if 1

#if 1
// 这是 z 纬度
for(int n = 0; n < 360; n++)
{
    
    
    QSurfaceDataRow *pSurfaceDataRow  = new QSurfaceDataRow;
    // 这是 x 经度
    for(int m = 0; m < 360; m++)
    {
    
    
       // 注意与笛卡尔坐标进行映射
       *pSurfaceDataRow << QVector3D(m, n / 7 + m / 7, n);
    }
    *pSurfaceDataArray << pSurfaceDataRow;
}
#else
for(int n = 0; n < 360; n++)
{
    
    
    QSurfaceDataRow *pSurfaceDataRow  = new QSurfaceDataRow;
    // 这是 x 经度
    for(int m = 0; m < 360; m++)
    {
    
    
       // 注意与笛卡尔坐标进行映射
       *pSurfaceDataRow << QVector3D(m, qrand() % 100, n);
       LOG << n << m;
    }
    *pSurfaceDataArray << pSurfaceDataRow;
}
#endif
#else
QSurfaceDataRow *pSurfaceDataRow1  = new QSurfaceDataRow;
QSurfaceDataRow *pSurfaceDataRow2  = new QSurfaceDataRow;
QSurfaceDataRow *pSurfaceDataRow3  = new QSurfaceDataRow;
// 行与行之间,要形成一个四点成面
*pSurfaceDataRow1 << QVector3D(0, 0, 0)  << QVector3D(359, 20, 0);
*pSurfaceDataRow2 << QVector3D(50, 20, 179)  << QVector3D(359, 40, 179);
*pSurfaceDataRow3 << QVector3D(100, 80, 359)  << QVector3D(359, 100, 359);
*pSurfaceDataArray << pSurfaceDataRow1 << pSurfaceDataRow2 << pSurfaceDataRow3;
#endif
// 添加数据(自动冲掉之前的数据)
_pSurface3DSeries->dataProxy()->resetArray(pSurfaceDataArray);
#endif
_pQ3DSurface->addSeries(_pSurface3DSeries);
_pQ3DSurface->show();

Demo source code

Q3dSurfaceWidget.h

#ifndef Q3DSURFACEWIDGET_H
#define Q3DSURFACEWIDGET_H

#include <QWidget>
#include <Q3DSurface>
#include <Q3DTheme>
#include <QSurface3DSeries>
#include <QVector3D>


using namespace QtDataVisualization;

namespace Ui {
    
    
class Q3dSurfaceWidget;
}

class Q3dSurfaceWidget : public QWidget
{
    
    
    Q_OBJECT

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

protected:
    void initControl();


protected:
    void resizeEvent(QResizeEvent *event);

private:
    Ui::Q3dSurfaceWidget *ui;

private:
    Q3DSurface *_pQ3DSurface;          // q3d平面曲线图
    QWidget *_pContainer;           // q3d窗口容器
    QSurface3DSeries  *_pSurface3DSeries ;    // q3d柱状图数据
};

#endif // Q3DSURFACEWIDGET_H

Q3dSurfaceWidget.cpp

#include "Q3dSurfaceWidget.h"
#include "ui_Q3dSurfaceWidget.h"
#include <Q3DTheme>


#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")

Q3dSurfaceWidget::Q3dSurfaceWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Q3dSurfaceWidget),
    _pQ3DSurface(0),
    _pContainer(0),
    _pSurface3DSeries(0)
{
    
    
    ui->setupUi(this);

    QString version = "v1.0.0";

    initControl();
}

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


void Q3dSurfaceWidget::initControl()
{
    
    
    _pQ3DSurface = new Q3DSurface();
    _pContainer = QWidget::createWindowContainer(_pQ3DSurface, this);

    // 设置轴文本
    {
    
    
        // 注意笛卡尔坐标
        _pQ3DSurface->axisX()->setTitle("经度(°)");
        _pQ3DSurface->axisX()->setTitleVisible(true);
        _pQ3DSurface->axisY()->setTitle("高度(m)");
        _pQ3DSurface->axisY()->setTitleVisible(true);
        _pQ3DSurface->axisZ()->setTitle("纬度(°)");
        _pQ3DSurface->axisZ()->setTitleVisible(true);
    }
    // 设置轴范围
    {
    
    
        // 注意笛卡尔坐标
        _pQ3DSurface->axisX()->setRange(0, 359);
        _pQ3DSurface->axisY()->setRange(0, 100);
        _pQ3DSurface->axisZ()->setRange(0, 359);
    }

    // 生成一个曲线
    _pSurface3DSeries = new QSurface3DSeries(_pQ3DSurface);
    // 设置渲染平滑
    _pSurface3DSeries->setMeshSmooth(true);
    // 设置渲染模式
    //   DrawWireframe           : 绘制栅格
    //   DrawSurface             : 绘制表面
    //   DrawSurfaceAndWireframe : 绘制栅格和图表面
    _pSurface3DSeries->setDrawMode(QSurface3DSeries::DrawSurface);

    // 视图添加该曲线
    _pQ3DSurface->addSeries(_pSurface3DSeries);
    // 设置阴影质量
    _pQ3DSurface->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
    // 设置视角
    _pQ3DSurface->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);
    // 设置子网格
    _pQ3DSurface->activeTheme()->setGridEnabled(true);

#if 1
    // 添加模拟数据
    QSurfaceDataArray *pSurfaceDataArray = new QSurfaceDataArray;
#if 1

#if 1
    // 这是 z 纬度
    for(int n = 0; n < 360; n++)
    {
    
    
        QSurfaceDataRow *pSurfaceDataRow  = new QSurfaceDataRow;
        // 这是 x 经度
        for(int m = 0; m < 360; m++)
        {
    
    
           // 注意与笛卡尔坐标进行映射
           *pSurfaceDataRow << QVector3D(m, n / 7 + m / 7, n);
        }
        *pSurfaceDataArray << pSurfaceDataRow;
    }
#else
    for(int n = 0; n < 360; n++)
    {
    
    
        QSurfaceDataRow *pSurfaceDataRow  = new QSurfaceDataRow;
        // 这是 x 经度
        for(int m = 0; m < 360; m++)
        {
    
    

           // 注意与笛卡尔坐标进行映射
           *pSurfaceDataRow << QVector3D(m, qrand() % 100, n);
           LOG << n << m;
        }
        *pSurfaceDataArray << pSurfaceDataRow;
    }
#endif
#else
    QSurfaceDataRow *pSurfaceDataRow1  = new QSurfaceDataRow;
    QSurfaceDataRow *pSurfaceDataRow2  = new QSurfaceDataRow;
    QSurfaceDataRow *pSurfaceDataRow3  = new QSurfaceDataRow;
    // 行与行之间,要形成一个四点成面
    *pSurfaceDataRow1 << QVector3D(0, 0, 0)  << QVector3D(359, 20, 0);
    *pSurfaceDataRow2 << QVector3D(50, 20, 179)  << QVector3D(359, 40, 179);
    *pSurfaceDataRow3 << QVector3D(100, 80, 359)  << QVector3D(359, 100, 359);
    *pSurfaceDataArray << pSurfaceDataRow1 << pSurfaceDataRow2 << pSurfaceDataRow3;
#endif

    // 添加数据(自动冲掉之前的数据)
    _pSurface3DSeries->dataProxy()->resetArray(pSurfaceDataArray);

#endif
    _pQ3DSurface->addSeries(_pSurface3DSeries);
    _pQ3DSurface->show();

}

void Q3dSurfaceWidget::resizeEvent(QResizeEvent *event)
{
    
    
    if(_pContainer)
    {
    
    
        _pContainer->setGeometry(rect());
    }
}

Project template v1.2.0

  insert image description here


into the pit

Pit 1: The xyz coordinate system is wrong

question

  x-precision, y-dimension, z-height (altitude) mapping error
  insert image description here

reason

  x, y, z actually follow the Cartesian coordinate set

solve

  First understand the coordinates, and then the z-axis direction, the data should also be replaced (arranged according to x, y, z, changed to x, z, y)
 &emso;insert image description here

Entry 2: The curved surface is displayed incorrectly

question

  Data display mapping error

reason

  Points into a surface need to follow the rule of 4 points into a surface, which is similar to the principle of opengl related 3 points into a surface and 4 points into a surface.
  insert image description here

  insert image description here
  

solve

  Between adjacent rows and rows, a surface should be formed. After modification, it will be displayed as follows:

  insert image description here
  insert image description here


Previous: " Qt Development Technology: Q3D Chart Development Notes (2): Q3DBar 3D Histogram Introduction, Demo and Detailed Code Explanation "
Next: Stay tuned...


If the article is an original article, please indicate the source of the original article when reprinting.
The blog address of this article: https://hpzwl.blog.csdn.net/article/details/130264470

Guess you like

Origin blog.csdn.net/qq21497936/article/details/130264470