Qt開發(fā)技術(shù):Q3D圖表開發(fā)筆記(一):Q3DScatter三維散點(diǎn)圖介紹、Demo以及代碼詳解
前言
??qt提供了q3d進(jìn)行三維開發(fā),雖然這個(gè)框架沒有得到大量運(yùn)用也不是那么成功,性能上也有很大的欠缺,但是普通的點(diǎn)到為止的應(yīng)用展示還是可以的。
??其中就包括華麗絢爛的三維圖表,數(shù)據(jù)量不大的時(shí)候是可以使用的。
Demo:Q3DScatter散點(diǎn)圖演示效果
??

???

??

Q3D提供的三維圖表
??依賴QtDataVisualization。在安裝qt的時(shí)候要選擇安裝QtDataVisualization模塊。
Q3DScatter散點(diǎn)圖
??Q3D的散點(diǎn)圖,性能大約支撐1000個(gè)點(diǎn)可以不卡頓,具體依賴pc,1000個(gè)點(diǎn)是什么 概念,可以理解為:10x10x10的區(qū)域,每個(gè)區(qū)域一個(gè)數(shù)據(jù)點(diǎn)。
??

Q3DBars柱狀圖
??Q3D的柱狀圖,性能跟散點(diǎn)圖類似。
??

Q3DSurface平面凹凸圖,平面紋理圖
??Q3D的柱狀圖,性能跟散點(diǎn)圖類似。
??

Q3DScatter散點(diǎn)圖
簡介
??Q3DScatter類提供了渲染3D散點(diǎn)圖的方法。能夠在3D中渲染散點(diǎn)圖,并通過自由旋轉(zhuǎn)場景來查看散點(diǎn)圖。
??旋轉(zhuǎn)是通過按住鼠標(biāo)右鍵并移動(dòng)鼠標(biāo)來完成的??s放由鼠標(biāo)滾輪完成。如果啟用,則通過鼠標(biāo)左鍵進(jìn)行選擇。通過單擊鼠標(biāo)滾輪,可以將場景重置為默認(rèn)攝影機(jī)視圖。在觸摸設(shè)備中,旋轉(zhuǎn)是通過點(diǎn)擊和移動(dòng)完成的,選擇是通過點(diǎn)擊并按住并縮放。
??如果沒有設(shè)置軸,將創(chuàng)建沒有標(biāo)簽的臨時(shí)默認(rèn)軸。這些默認(rèn)軸可以通過軸訪問器進(jìn)行修改,但是一旦為方向明確設(shè)置了任何軸,該方向的默認(rèn)軸就會(huì)被破壞。
??Q3DScatter支持同時(shí)顯示多個(gè)系列。
構(gòu)造最小Q3DS散點(diǎn)圖
??首先,構(gòu)建Q3DS散射器。由于在本例中我們將圖形作為頂級窗口運(yùn)行,因此需要清除Qt::FramelessWindowHint標(biāo)志,該標(biāo)志默認(rèn)設(shè)置為:
Q3DScatter scatter;scatter.setFlags(scatter.flags() ^ Qt::FramelessWindowHint);
??現(xiàn)在Q3DScatter已準(zhǔn)備好接收要渲染的數(shù)據(jù)。添加一系列3個(gè)QVector3D項(xiàng)目:
QScatter3DSeries *series = new QScatter3DSeries;QScatterDataArray data;data << QVector3D(0.5f, 0.5f, 0.5f) << QVector3D(-0.3f, -0.5f, -0.4f) << QVector3D(0.0f, -0.3f, 0.2f);series->dataProxy()->addItems(data);scatter.addSeries(series);
??最后,將其設(shè)置為可見:
scatter.show();
??創(chuàng)建和顯示此圖形所需的完整代碼是:
#include <QtDataVisualization>using namespace QtDataVisualization;int main(int argc, char **argv){
? ?QGuiApplication app(argc, argv);
? ?Q3DScatter scatter;
? ?scatter.setFlags(scatter.flags() ^ Qt::FramelessWindowHint);
? ?QScatter3DSeries *series = new QScatter3DSeries;
? ?QScatterDataArray data;data << QVector3D(0.5f, 0.5f, 0.5f)
? ? ? ? ? ?<< QVector3D(-0.3f, -0.5f, -0.4f)
? ? ? ? ? ?<< QVector3D(0.0f, -0.3f, 0.2f);
? ?series->dataProxy()->addItems(data);
? ?scatter.addSeries(series);
? ?scatter.show();
? ?return app.exec();}
??運(yùn)行效果:
??

??場景可以被旋轉(zhuǎn)、放大,并且可以選擇一個(gè)項(xiàng)目來查看其位置,但在這個(gè)最小的代碼示例中不包括其他交互。通過熟悉所提供的示例(如散點(diǎn)示例)來了解更多信息。
Q3Ddemo構(gòu)建流程解析
步驟一:確認(rèn)安裝QtDataVisualization模塊
??如何確認(rèn),則是在幫助文件中查看是否有Q3dscatter類。一般是安裝了模塊才會(huì)有對應(yīng)的幫助文件。沒有則重新安裝qt或者單獨(dú)安裝該模塊。
??

步驟二:工程配置文件中加入模塊
??Q3d是在數(shù)據(jù)可視化模塊中,需要在pro或者pri配置文件中添加。
QT += datavisualization
??

步驟三:添加使用到的頭文件
??使用到Q3DScatter相關(guān)類中添加頭文件,主要使用到Q3DScatter和QScatter3DSeries等等。
#include <Q3DScatter>#include <Q3DTheme>#include <QScatter3DSeries>#include <QVector3D>
??

步驟四:添加命名空間
??這時(shí)候還是無法使用對應(yīng)的類,需要添加命名空間才行,查看最后“入坑一”:
using namespace QtDataVisualization;
??

步驟五:Q3D的圖標(biāo)基礎(chǔ)構(gòu)建框架
??下面是包含注釋的Q3DScatter基礎(chǔ)構(gòu)建流程,其他兩種圖類似:
_pQ3DScatter = new Q3DScatter();_pContainer = QWidget::createWindowContainer(_pQ3DScatter, this);// 設(shè)置軸文本{
? ?_pQ3DScatter->axisX()->setTitle("X");
? ?_pQ3DScatter->axisY()->setTitle("Y");
? ?_pQ3DScatter->axisZ()->setTitle("Z");}// 設(shè)置軸范圍{// ? ? ? ?_pQ3DScatter->axisX()->setRange(0, 10);// ? ? ? ?_pQ3DScatter->axisY()->setRange(0, 10);// ? ? ? ?_pQ3DScatter->axisZ()->setRange(0, 10);}// 生成一個(gè)曲線_pScatter3DSeries = new QScatter3DSeries(_pQ3DScatter);// 設(shè)置渲染平滑_pScatter3DSeries->setMeshSmooth(true);// 視圖添加該曲線_pQ3DScatter->addSeries(_pScatter3DSeries);// 設(shè)置陰影質(zhì)量_pQ3DScatter->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);// 設(shè)置視角_pQ3DScatter->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);// 設(shè)置子網(wǎng)格_pQ3DScatter->activeTheme()->setGridEnabled(true);#if 1// 添加模擬數(shù)據(jù)QScatterDataArray data;data << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
? ? << QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
? ? << QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);// 添加數(shù)據(jù)(自動(dòng)沖掉之前的數(shù)據(jù))_pScatter3DSeries->dataProxy()->addItems(data);#endif#if 1// 模擬QList<QVector3D> listVector3D;#if 0listVector3D << ?QVector3D(5, 1,1) << QVector3D(5, 1, 2) << QVector3D(5, 1, 3)
? ? ? ? ? ? << QVector3D(5, 2,1) << QVector3D(5, 2, 2) << QVector3D(5, 2, 3)
? ? ? ? ? ? << QVector3D(5, 3,1) << QVector3D(5, 3, 2) << QVector3D(5, 3, 3);#elselistVector3D << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
? ? ? ? ? ? << QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
? ? ? ? ? ? << QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);#endif
Demo源碼
Q3dScatterWidget.h
#ifndef Q3DSCATTERWIDGET_H#define Q3DSCATTERWIDGET_H#include <QWidget>#include <Q3DScatter>#include <Q3DTheme>#include <QScatter3DSeries>#include <QVector3D>using namespace QtDataVisualization;namespace Ui {class Q3dScatterWidget;}class Q3dScatterWidget : public QWidget{
? ?Q_OBJECTpublic:
? ?explicit Q3dScatterWidget(QWidget *parent = 0);
? ?~Q3dScatterWidget();public:
? ?void setData(QList<QVector3D> listVector3D);protected:
? ?void initControl();protected:
? ?void resizeEvent(QResizeEvent *event);private:
? ?Ui::Q3dScatterWidget *ui;private:
? ?Q3DScatter *_pQ3DScatter; ? ? ? ? ? ? ? // q3d散點(diǎn)視圖
? ?QWidget *_pContainer; ? ? ? ? ? ? ? ? ? // q3d窗口容器
? ?QScatter3DSeries *_pScatter3DSeries; ? ?// q3d散點(diǎn)圖數(shù)據(jù)};#endif // Q3DSCATTERWIDGET_H
Q3dScatterWidget.cpp
#include "Q3dScatterWidget.h"#include "ui_Q3dScatterWidget.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")Q3dScatterWidget::Q3dScatterWidget(QWidget *parent) :
? ?QWidget(parent),
? ?ui(new Ui::Q3dScatterWidget),
? ?_pQ3DScatter(0),
? ?_pContainer(0),
? ?_pScatter3DSeries(0){
? ?ui->setupUi(this);
? ?QString version = "v1.0.0";
? ?setWindowTitle(QString("q3d散點(diǎn)圖示例 %1(作者:長沙紅胖子 QQ:21497936 WX:15173255813 www.hpzwl.com").arg(version));
? ?initControl();}Q3dScatterWidget::~Q3dScatterWidget(){
? ?delete ui;}void Q3dScatterWidget::setData(QList<QVector3D> listVector3D){
? ?double xMin, xMax, yMin, yMax, zMin, zMax;
? ?QScatterDataArray data;
? ?for(int index = 0; index < listVector3D.size(); index++)
? ?{
? ? ? ?// 添加模擬數(shù)據(jù)
? ? ? ?data << listVector3D.at(index);
? ? ? ?// 計(jì)算范圍
? ? ? ?if(index == 0)
? ? ? ?{
? ? ? ? ? ?xMin = listVector3D.at(index).x();
? ? ? ? ? ?xMax = listVector3D.at(index).x();
? ? ? ? ? ?yMin = listVector3D.at(index).y();
? ? ? ? ? ?yMax = listVector3D.at(index).y();
? ? ? ? ? ?zMin = listVector3D.at(index).z();
? ? ? ? ? ?zMax = listVector3D.at(index).z();
? ? ? ?}else {
? ? ? ? ? ?if(xMin > listVector3D.at(index).x() + 1e-8)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?xMin = listVector3D.at(index).x();
? ? ? ? ? ?}
? ? ? ? ? ?if(xMax < listVector3D.at(index).x() - 1e-8)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?xMax = listVector3D.at(index).x();
? ? ? ? ? ?}
? ? ? ? ? ?if(yMin > listVector3D.at(index).y() + 1e-8)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?yMin = listVector3D.at(index).y();
? ? ? ? ? ?}
? ? ? ? ? ?if(yMax < listVector3D.at(index).y() - 1e-8)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?yMax = listVector3D.at(index).y();
? ? ? ? ? ?}
? ? ? ? ? ?if(zMin > listVector3D.at(index).z() + 1e-8)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?zMin = listVector3D.at(index).z();
? ? ? ? ? ?}
? ? ? ? ? ?if(zMax < listVector3D.at(index).z() - 1e-8)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?zMax = listVector3D.at(index).z();
? ? ? ? ? ?}
? ? ? ?}
? ?}
? ?// 添加數(shù)據(jù)(自動(dòng)沖掉之前的數(shù)據(jù))
? ?_pScatter3DSeries->dataProxy()->addItems(data);
? ?// 計(jì)算范圍 x軸范圍要大于等于y軸
? ?if(xMax - xMin < yMax - yMin)
? ?{
? ? ? ?xMax = xMin + (yMax - yMin);
? ?}
? ?_pQ3DScatter->axisX()->setRange(xMin, xMax);
? ?_pQ3DScatter->axisY()->setRange(yMin, yMax);
? ?_pQ3DScatter->axisZ()->setRange(zMin, zMax);}void Q3dScatterWidget::initControl(){
? ?_pQ3DScatter = new Q3DScatter();
? ?_pContainer = QWidget::createWindowContainer(_pQ3DScatter, this);
? ?// 設(shè)置軸文本
? ?{
? ? ? ?_pQ3DScatter->axisX()->setTitle("X");
? ? ? ?_pQ3DScatter->axisY()->setTitle("Y");
? ? ? ?_pQ3DScatter->axisZ()->setTitle("Z");
? ?}
? ?// 設(shè)置軸范圍
? ?{// ? ? ? ?_pQ3DScatter->axisX()->setRange(0, 10);// ? ? ? ?_pQ3DScatter->axisY()->setRange(0, 10);// ? ? ? ?_pQ3DScatter->axisZ()->setRange(0, 10);
? ?}
? ?// 生成一個(gè)曲線
? ?_pScatter3DSeries = new QScatter3DSeries(_pQ3DScatter);
? ?// 設(shè)置渲染平滑
? ?_pScatter3DSeries->setMeshSmooth(true);
? ?// 視圖添加該曲線
? ?_pQ3DScatter->addSeries(_pScatter3DSeries);
? ?// 設(shè)置陰影質(zhì)量
? ?_pQ3DScatter->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
? ?// 設(shè)置視角
? ?_pQ3DScatter->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);
? ?// 設(shè)置子網(wǎng)格
? ?_pQ3DScatter->activeTheme()->setGridEnabled(true);#if 1
? ?// 添加模擬數(shù)據(jù)
? ?QScatterDataArray data;
? ?data << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
? ? ? ? << QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
? ? ? ? << QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);
? ?// 添加數(shù)據(jù)(自動(dòng)沖掉之前的數(shù)據(jù))
? ?_pScatter3DSeries->dataProxy()->addItems(data);#endif#if 1
? ?// 模擬
? ?QList<QVector3D> listVector3D;#if 0
? ?listVector3D << ?QVector3D(5, 1,1) << QVector3D(5, 1, 2) << QVector3D(5, 1, 3)
? ? ? ? ? ? ? ? << QVector3D(5, 2,1) << QVector3D(5, 2, 2) << QVector3D(5, 2, 3)
? ? ? ? ? ? ? ? << QVector3D(5, 3,1) << QVector3D(5, 3, 2) << QVector3D(5, 3, 3);#else
? ?listVector3D << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
? ? ? ? ? ? ? ? << QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
? ? ? ? ? ? ? ? << QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);#endif
? ?// 添加數(shù)據(jù)
? ?setData(listVector3D);#endif}void Q3dScatterWidget::resizeEvent(QResizeEvent *event){
? ?if(_pContainer)
? ?{
? ? ? ?_pContainer->setGeometry(rect());
? ?}}
工程模板
??

入坑
入坑一:找不到Q3DScatter類
問題
??

原因
??有命名空間。
解決
using namespace QtDataVisualization;