QT数据可视化框架编程实战之三维曲面图 实时变化的三维曲面图 补天云QT技术培训专家
QT数据可视化框架编程实战之三维曲面图 实时变化的三维曲面图 补天云QT技术培训专家
简介
本文将介绍QT数据可视化框架编程实战之三维曲面图,本文通过构造一个数据实时变化的三维曲面图的应用实例来展示QT数据可视化框架的数据展示能力,同时还将给出这个应用实例的C++源码和QML源码。
文章目录
正文
QT三维曲面图展示实时变化数据的运行效果
QT数据可视化框架中的三维曲面图,展示实时变化的序列数据的运行效果截图如下所示:

运行效果的GIF动画如下所示:

运行效果和对应的源码浏览的视频如下所示:
QT数据可视化框架编程实战之三维曲面图 实时变化的三维曲面图 补天云QT技术培训专家
视频链接如下所示:
QT数据可视化框架编程实战之三维曲面图 实时变化的三维曲面图 补天云QT技术培训专家
QT三维曲面图展示实时变化数据的设计思路
QT数据可视化框架展示实时变化的三维曲面图,首先想到的就是动态的实时生成曲面图序列的数据点。考虑到数据点的数量可能比较多,那么为了提升运行效率,可以将实时生成曲面图序列的数据点的功能使用C++来实现,然后使用QT三维曲面图的QML组件来展示这些序列的数据,从而实现实时变化数据的展示。
为了不断生成变化的数据点,可以考虑使用QML定时器来定时更新数据点;为了及时的展示出变化之后的数据点,可以考虑使用定时器来定时刷新QT三维曲面图。
QT三维曲面图展示实时变化数据的C++主程序
butianyun.cpp文件如下所示:
int main(int argc, char *argv[])
{
qputenv("QSG_RHI_BACKEND", "opengl");
QGuiApplication app(argc, argv);
qmlRegisterType<ButianyunDataSource>("ButianyunDataSource", 1, 0, "ButianyunDataSource");
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/Butianyun3DSurface/Butianyun3DSurface.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
&app, []() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
QT三维曲面图展示实时变化数据的数据源C++源码
数据源使用C++代码来生成。
ButianyunDataSource.cpp文件和ButianyunDataSource.h文件实现了数据源生成功能。
(备注:本文广泛参考了QT框架提供的QT可视化框架的例程的源码)
生成新的数据点的C++代码如下所示:
void ButianyunDataSource::generateData(int cacheCount, int rowCount, int columnCount,
float xMin, float xMax,
float yMin, float yMax,
float zMin, float zMax)
{
if (!cacheCount || !rowCount || !columnCount)
{
return;
}
clearData();
// 重建缓存数据
m_data.resize(cacheCount);
for (int i = 0; i < cacheCount; ++i)
{
QSurfaceDataArray &array = m_data[i];
array.reserve(rowCount);
for (int j = 0; j < rowCount; ++j)
{
array.append(new QSurfaceDataRow(columnCount));
}
}
float xRange = xMax - xMin;
float yRange = yMax - yMin;
float zRange = zMax - zMin;
int cacheIndexStep = columnCount / cacheCount;
float cacheStep = float(cacheIndexStep) * xRange / float(columnCount);
// 每次生成数据时一次性生成多个序列数据
// 遍历缓存:缓存中的每一个序列数据就是用于某一次展示,也就是一个序列
auto *generator = QRandomGenerator::global();
for (int i = 0; i < cacheCount; ++i)
{
QSurfaceDataArray &cache = m_data[i];
float cacheXAdjustment = cacheStep * i;
float cacheIndexAdjustment = cacheIndexStep * i;
for (int j = 0; j < rowCount; ++j)
{
QSurfaceDataRow &row = *(cache[j]);
float rowMod = (float(j)) / float(rowCount);
float yRangeMod = yRange * rowMod;
float zRangeMod = zRange * rowMod;
float z = zRangeMod + zMin;
qreal rowColWaveAngleMul = M_PI * M_PI * rowMod;
float rowColWaveMul = yRangeMod * 0.2f;
for (int k = 0; k < columnCount; k++)
{
float colMod = (float(k)) / float(columnCount);
float xRangeMod = xRange * colMod;
float x = xRangeMod + xMin + cacheXAdjustment;
float colWave = float(qSin((2.0 * M_PI * colMod) - (1.0 / 2.0 * M_PI)) + 1.0);
float y = (colWave * ((float(qSin(rowColWaveAngleMul * colMod) + 1.0))))
* rowColWaveMul
+ generator->bounded(0.03f) * yRangeMod
+ generator->bounded(0.03f) * (zRange - zRangeMod);
int index = k + cacheIndexAdjustment;
if (index >= columnCount)
{
index -= columnCount;
x -= xRange;
}
row[index] = QVector3D(x, y, z);
}
}
}
}
刷新QT三维曲面图的序列的C++代码如下所示:
void ButianyunDataSource::update(QSurface3DSeries *series)
{
if (series && !m_data.isEmpty())
{
// 缓存数据的索引序号
if (++m_index >= m_data.size())
{
m_index = 0;
}
const QSurfaceDataArray &array = m_data.at(m_index);
int newRowCount = array.size();
int newColumnCount = array.at(0)->size();
// 重新序列重构数据
if (!m_resetArray || series->dataProxy()->rowCount() != newRowCount
|| series->dataProxy()->columnCount() != newColumnCount)
{
m_resetArray = new QSurfaceDataArray();
m_resetArray->reserve(newRowCount);
for (int i = 0; i < newRowCount; ++i)
{
m_resetArray->append(new QSurfaceDataRow(newColumnCount));
}
}
// 从缓存中拷贝数据到序列重构数据中
for (int i = 0; i < newRowCount; ++i)
{
const QSurfaceDataRow &sourceRow = *(array.at(i));
QSurfaceDataRow &row = *(*m_resetArray)[i];
std::copy(sourceRow.cbegin(), sourceRow.cend(), row.begin());
}
// 通知代理对象:序列的数据已经变化了,以便刷新界面
series->dataProxy()->resetArray(m_resetArray);
}
}
QT三维曲面图展示实时变化数据的QML源码
Butianyun3DSurface.qml文件源码如下所示:
Window {
width: 1920
height: 1000
visible: true
title: qsTr("QT数据可视化 补天云QT系列视频课程 补天云QT技术培训专家")
//数据源
ButianyunDataSource {
id: dataSource
}
//QML三维曲面
Surface3D {
id: surfaceGraph
anchors.fill: parent
//QML三维曲面的序列
Surface3DSeries {
id: surfaceSeries
drawMode: Surface3DSeries.DrawSurface
flatShadingEnabled: false
itemLabelFormat: "@xLabel, @zLabel: @yLabel"
itemLabelVisible: false
}
shadowQuality: AbstractGraph3D.ShadowQualityNone
selectionMode: AbstractGraph3D.SelectionSlice | AbstractGraph3D.SelectionItemAndColumn
theme: Theme3D {
type: Theme3D.ThemeIsabelle
backgroundEnabled: false
}
scene.activeCamera.cameraPreset: Camera3D.CameraPresetBehind
axisX.labelFormat: "%d ms"
axisY.labelFormat: "%d mm"
axisZ.labelFormat: "%d mm"
axisX.min: 0
axisY.min: 0
axisZ.min: 0
axisX.max: 1000
axisY.max: 1000
axisZ.max: 1000
axisX.segmentCount: 10
axisY.segmentCount: 10
axisZ.segmentCount: 10
measureFps: true
renderingMode: AbstractGraph3D.RenderDirectToBackground
//首次产生数据
Component.onCompleted: generateData();
}
property int cacheCount: 15
property int fps: 30
property int rowCount: 30
property int columnCount: 30
//产生数据的包装函数
function generateData() {
dataSource.generateData(cacheCount, rowCount,
columnCount,
surfaceGraph.axisX.min, surfaceGraph.axisX.max,
surfaceGraph.axisY.min, surfaceGraph.axisY.max,
surfaceGraph.axisZ.min, surfaceGraph.axisZ.max);
}
//定时器:定时重新产生数据
Timer {
interval: 1000
running: true
repeat: true
onTriggered: {
generateData();
}
}
//定时器:定时刷新曲面界面
Timer {
interval: 1000 / fps
running: true
repeat: true
onTriggered: {
dataSource.update(surfaceSeries);
}
}
}
总结
本文介绍了QT数据可视化框架编程实战之三维曲面图,本文通过构造一个数据实时变化的三维曲面图的应用实例来展示QT数据可视化框架的数据展示能力,同时还给出了这个应用实例的C++源码和QML源码。
本文介绍的技术路线也存在进一步优化改进的空间,比如本文使用C++代码来实时生成数据点,使用的是CPU的运算能力,如果能使用GLSL之类的shader代码来实时生成数据点,则可以充分发挥GPU的运算能力,将可能更进一步提升三维曲面图应用程序的整体性能。
如果您认为这篇文章对您有所帮助,请您一定立即点赞+喜欢+收藏,本文作者将能从您的点赞+喜欢+收藏中获取到创作新的好文章的动力。如果您认为作者写的文章还有一些参考价值,您也可以关注这篇文章的作者。
QT数据可视化框架编程实战之三维曲面图 实时变化的三维曲面图 补天云QT技术培训专家的更多相关文章
- D3js初探及数据可视化案例设计实战
摘要:本文以本人目前所做项目为基础,从设计的角度探讨数据可视化的设计的方法.过程和结果,起抛砖引玉之效.在技术方案上,我们采用通用web架构和d3js作为主要技术手段:考虑到项目需求,这里所做的可视化 ...
- 大数据学习day20-----spark03-----RDD编程实战案例(1 计算订单分类成交金额,2 将订单信息关联分类信息,并将这些数据存入Hbase中,3 使用Spark读取日志文件,根据Ip地址,查询地址对应的位置信息
1 RDD编程实战案例一 数据样例 字段说明: 其中cid中1代表手机,2代表家具,3代表服装 1.1 计算订单分类成交金额 需求:在给定的订单数据,根据订单的分类ID进行聚合,然后管理订单分类名称, ...
- Qt数据可视化(散点图、折线图、柱状图、盒须图、饼状图、雷达图)开发实例
目录 散点图 折线图 柱状图 水平柱状图 水平堆叠图 水平百分比柱状图 盒须图 饼状图 雷达图 Qt散点图.折线图.柱状图.盒须图.饼状图.雷达图开发实例. 在开发过程中我们会使用多各种各样的图 ...
- Webstorm+Webpack+echarts构建个性化定制的数据可视化图表&&两个echarts详细教程(柱状图,南丁格尔图)
Webstorm+Webpack+echarts ECharts 特性介绍 ECharts,一个纯 Javascript 的图表库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(I ...
- Qt编写数据可视化大屏界面电子看板系统
一.前言 目前大屏大数据可视化UI这块非常火,趁热也用Qt来实现一个,Qt这个一站式超大型GUI超市,没有什么他做不了的,大屏电子看板当然也不在话下,有了QSS和QPainter这两个无敌的工具组合, ...
- 前端数据可视化echarts.js使用指南
一.开篇 首先这里要感谢一下我的公司,因为公司需求上面的新颖(奇葩)的需求,让我有幸可以学习到一些好玩有趣的前端技术,前端技术中好玩而且比较实用的我想应该要数前端的数据可视化这一方面,目前市面上的数据 ...
- 使用bokeh-scala进行数据可视化
目录 前言 bokeh简介及胡扯 bokeh-scala基本代码 我的封装 总结 一.前言 最近在使用spark集群以及geotrellis框架(相关文章见http://www.cnbl ...
- 前端数据可视化echarts.js
一.echarts.js的优势与总体情况 echarts.js作为国内的IT三巨头之一的百度的推出一款相对较为成功的开源项目,总体上来说有这样的一些优点 1.容易使用 echarts.js的官方文档比 ...
- 前端er必须掌握的数据可视化技术
又是一月结束,打工人准时准点的汇报工作如期和大家见面啦.提到汇报,必不可少的一部分就是数据的汇总.分析. 作为一名合格的社会人,我们每天都在工作.生活.学习中和数字打交道.小到量化的工作内容,大到具体 ...
- 【Data Visual】一文搞懂matplotlib数据可视化
一文搞懂matplotlib数据可视化 作者:白宁超 2017年7月19日09:09:07 摘要:数据可视化主要旨在借助于图形化手段,清晰有效地传达与沟通信息.但是,这并不就意味着数据可视化就一定因为 ...
随机推荐
- 番外篇: go语言写的简要数据同步工具
go-etl工具 作为go-etl工具的作者,想要安利一下这个小巧的数据同步工具,它在同步百万级别的数据时表现极为优异,基本能在几分钟完成数据同步. 1.它能干什么的? go-etl是一个数据同步工具 ...
- es6高级~promise
1.Promise对象 Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值.其作用是为了解决回调地狱 回调地狱:回调函数的结果作为下一个回调函数的参数时,产生回调链,也称之为回调 ...
- JavaScript小面试~什么是深拷贝,什么是浅拷贝,深拷贝和浅拷贝的区别,如何实现深拷贝
深拷贝:就是在复制数据或者对象的时候,将其内存中值复制过来. 浅拷贝:就是在复制数据或者对象的时候,是将其引用复制过来. 深拷贝和浅拷贝的区别:深拷贝复制的是被复制数据或者对象的值,复制的数据或对象会 ...
- ElementUI Dialog 结合Vue实现对话框body“二分”布局
Dialog 结合Vue实现对话框body"二分"布局 需求描述 如下图, 把对话框body内容部分,分成上下两部分,其中上部分高度根据窗口大小动态调整,如果内容过多,则出现滚动条 ...
- holiday week3
本周开始进行小学期实验报告B 上周LOL打的rank分又掉了回去 星际争霸打到了铂金段位 JAVA预备在小学期完成之后开始正式学习 现已了解雏形 本周发布了一个视频https://www.bilibi ...
- java中一些空判断|ObjectUtils
为什么用ObjectUtils? 在java中判断对象是否为null,常常不止判断对象是否为null,如果对象是集合,数组,字符串等等特殊类型,还需要检查是否为空(元素个数为0或者长度为0)Objec ...
- Cloudflare教程:如何注册账户、购买域名、开启免费CDN服务?
Cloudflare介绍 什么是Cloudflare Cloudflare是一家总部位于旧金山的美国跨国科技企业,以向客户提供基于反向代理的内容分发网络(CDN)及分布式域名解析服务为主要业务. 目前 ...
- LeetCode654. 最大二叉树
题目链接:https://leetcode.cn/problems/maximum-binary-tree/description/ 题目叙述 给定一个不重复的整数数组 nums . 最大二叉树 可以 ...
- 记一次seata启动错误日志ErrMsg:failed to req API:/nacos/v1/ns/instance after all servers....
错误日志如下: java.lang.RuntimeException: ErrCode:500, ErrMsg:failed to req API:/nacos/v1/ns/instance afte ...
- RHCA rh442 007 hugetlbfs strace命令追踪 脏页设置 内存分配
内存管理 虚拟内存 --- 物理内存 应用程序申请虚拟内存 --- RAM + SWAP (真正主板上的设备) 他们之间有一张映射表 page table 页表 PTE: 页表条目 虚拟内存和物理内存 ...