Tecnología de desarrollo Qt: Notas de desarrollo de gráficos Q3D (3): Introducción al gráfico de superficie tridimensional Q3DSurface, demostración y explicación del código

Si el artículo es un artículo original, indique la fuente del artículo original al reproducirlo.
La dirección del blog de este artículo: https://hpzwl.blog.csdn.net/article/details/130264470

Estimados lectores, el conocimiento es infinito pero la mano de obra es limitada. Puede cambiar sus necesidades, encontrar profesionales o hacer su propia investigación.

Enciclopedia del blog de ciencia y tecnología Red Fatty Network: la colección de tecnología de desarrollo (incluida la tecnología práctica Qt, Raspberry Pi, 3D, OpenCV, OpenGL, ffmpeg, OSG, microcomputadora de un solo chip, combinación de software y hardware, etc.) se actualiza continuamente. .. (haga clic en el portal)

Columna de desarrollo de Qt: tecnología de desarrollo (haga clic en el portal)

Anterior: " Tecnología de desarrollo de Qt: Notas de desarrollo de gráficos Q3D (2): Introducción al histograma 3D de Q3DBar, demostración y explicación detallada del código "
Siguiente: Estén atentos...


prefacio

  qt proporciona q3d para el desarrollo 3D. Aunque este marco no ha sido ampliamente utilizado y no tiene tanto éxito, y su rendimiento también es muy deficiente, la visualización de aplicaciones ordinarias punto a punto aún es posible.
  Entre ellos se encuentran magníficos gráficos tridimensionales, que se pueden usar cuando la cantidad de datos no es grande.
  El histograma y el gráfico de dispersión q3d básicos se introdujeron anteriormente, y este artículo presenta el gráfico de superficie tridimensional básico.


Demostración: efecto de demostración de diagrama de dispersión de Q3DSurface

  inserte la descripción de la imagen aquí
  inserte la descripción de la imagen aquí
  inserte la descripción de la imagen aquí

enlace de descarga:

  Dirección de descarga del paquete de ejecución de demostración: https://download.csdn.net/download/qq21497936/87708061
  Descarga del grupo QQ: haga clic en el avatar principal del blog para ingresar a la página de inicio del blog, verifique el lado derecho, allí está el información de contacto del grupo QQ (haga clic en " Archivo " Buscar " q3d ", el grupo y las publicaciones del blog se actualizarán simultáneamente)
  Dirección de descarga de Baidu Netdisk: https://pan.baidu.com/s/1bWNR5E6Y9utu8iey9rIu0g?pwd=1234


Gráfico 3D proporcionado por Q3D

  Depende de QtDataVisualization. Al instalar qt, elija instalar el módulo QtDataVisualization.

Diagrama de dispersión Q3DScatter

  El rendimiento del gráfico de dispersión Q3D admite alrededor de 1000 puntos sin demora. Depende de la PC. ¿Cuál es el concepto de 1000 puntos? Se puede entender como: área de 10x10x10, un punto de datos para cada área.
  inserte la descripción de la imagen aquí

Histograma Q3DBars

  El histograma de Q3D es similar al gráfico de dispersión en rendimiento.
   inserte la descripción de la imagen aquí

Q3DMapa de relieve de plano de superficie, mapa de textura de plano, mapa de curva de plano

  El histograma de Q3D es similar al gráfico de dispersión en rendimiento.
  inserte la descripción de la imagen aquí


Q3DCurva del plano de superficie

Introducción

  La clase Q3DSurface proporciona métodos para renderizar imágenes de superficie 3D. Esta clase permite a los desarrolladores renderizar mapas de superficie 3D y verlos girando libremente la escena. Las propiedades visuales de las superficies, como los modos de dibujo y el sombreado, se pueden controlar a través de QSurface3DSeries.
  Q3DSurface admite la selección al mostrar esferas resaltadas en puntos de datos en los que el usuario hace clic con el botón izquierdo del mouse (cuando se usa el controlador de entrada predeterminado) o mediante la selección a través de QSurface3DSeries. El puntero de selección va acompañado de una etiqueta que, por defecto, muestra el valor del punto de datos y las coordenadas del punto.
El rango de valores y el formato de la etiqueta que se muestra en el eje se pueden controlar con QValue3DAxis.
  Para rotar el gráfico, mantenga presionado el botón derecho del mouse y muévalo. El zoom se realiza con la rueda del ratón. Ambos asumen que el controlador de entrada predeterminado está en uso.
  Si no se establecen ejes explícitamente en Q3DSurface, se crean ejes predeterminados temporales sin etiquetas. Estos ejes predeterminados se pueden modificar a través del descriptor de acceso de ejes, pero tan pronto como se establezca explícitamente cualquier eje para una orientación, se destruirá el eje predeterminado para esa orientación.

Construya un gráfico plano Q3D mínimo

  Primero, construya la superficie Q3D. Dado que en este ejemplo estamos ejecutando los gráficos como una ventana de nivel superior, debemos borrar el indicador Qt::FramelessWindowHint, que está configurado de manera predeterminada:

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

  Ahora el Q3DSurface está listo para recibir datos para renderizar. Crear elementos de datos para recibir valores:

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

  Primero alimente los datos a los elementos de fila, luego agregue sus punteros a los elementos de datos:

*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;

  Cree una nueva serie y establezca datos para ella:

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

  Por último, hazlo visible:

surface.show();

  El código completo requerido para crear y mostrar este gráfico es:

#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();
}

  resultado de ejecución:
  inserte la descripción de la imagen aquí

  La escena se puede rotar, acercar y se puede seleccionar un elemento para ver su posición, pero otras interacciones no se incluyen en este ejemplo de código mínimo.


Análisis del proceso de construcción Q3Ddemo

Paso 1: Confirme la instalación del módulo QtDataVisualization

  Cómo confirmarlo es verificar si hay una clase Q3dscatter en el archivo de ayuda. Generalmente, el archivo de ayuda correspondiente estará disponible solo después de instalar el módulo. De lo contrario, reinstale qt o instale el módulo por separado.
  inserte la descripción de la imagen aquí

Paso 2: agregar módulos al archivo de configuración del proyecto

  Q3d está en el módulo de visualización de datos y debe agregarse en el archivo de configuración pro o pri.

QT += datavisualization

  inserte la descripción de la imagen aquí

Paso 3: agregue los archivos de encabezado utilizados

  Úselo para agregar archivos de encabezado a las clases relacionadas con Q3DBar, use principalmente Q3DBar, QBar3DSeries, QBarDataRow, etc.

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

  inserte la descripción de la imagen aquí

Paso 4: Agregar un espacio de nombres

  En este momento, la clase correspondiente aún no se puede usar y se debe agregar el espacio de nombres:

using namespace QtDataVisualization;

  inserte la descripción de la imagen aquí

Paso 5: marco de construcción base de iconos de Q3D

  El siguiente es el proceso de construcción básico de Q3DSurface, incluidos los comentarios (tenga en cuenta la visualización del eje, consulte " Pit 1 " al final, preste atención a las reglas de superficie de los datos, consulte " 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();

código fuente de demostración

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());
    }
}

Plantilla de proyecto v1.2.0

  inserte la descripción de la imagen aquí


en el hoyo

Hoyo 1: El sistema de coordenadas xyz es incorrecto

pregunta

  error de mapeo de precisión x, dimensión y, altura z (altitud)
  inserte la descripción de la imagen aquí

razón

  x, y, z en realidad siguen el conjunto de coordenadas cartesianas

resolver

  Primero comprenda las coordenadas, y luego la dirección del eje z, los datos también deben reemplazarse (organizados de acuerdo con x, y, z, cambiados a x, z, y)
 &emso;inserte la descripción de la imagen aquí

Entrada 2: la superficie curva se muestra incorrectamente

pregunta

  Error de asignación de visualización de datos

razón

  Los puntos en una superficie deben seguir la regla de 4 puntos en una superficie, que es similar al principio de opengl relacionado con 3 puntos en una superficie y 4 puntos en una superficie.
  inserte la descripción de la imagen aquí

  inserte la descripción de la imagen aquí
  

resolver

  Entre filas y filas adyacentes, se debe formar una superficie.Después de la modificación, se mostrará de la siguiente manera:

  inserte la descripción de la imagen aquí
  inserte la descripción de la imagen aquí


Anterior: " Tecnología de desarrollo de Qt: Notas de desarrollo de gráficos Q3D (2): Introducción al histograma 3D de Q3DBar, demostración y explicación detallada del código "
Siguiente: Estén atentos...


Si el artículo es un artículo original, indique la fuente del artículo original al reproducirlo.
La dirección del blog de este artículo: https://hpzwl.blog.csdn.net/article/details/130264470

Supongo que te gusta

Origin blog.csdn.net/qq21497936/article/details/130264470
Recomendado
Clasificación