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的运算能力,将可能更进一步提升三维曲面图应用程序的整体性能。

如果您认为这篇文章对您有所帮助,请您一定立即点赞+喜欢+收藏,本文作者将能从您的点赞+喜欢+收藏中获取到创作新的好文章的动力。如果您认为作者写的文章还有一些参考价值,您也可以关注这篇文章的作者。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值