Introduction à la Visualisation 3D avec QtDataVisualization
La bibliothèque Qt offre le module QtDataVisualization pour la création de visualisations de données en trois dimensions. Bien que ce framework soit plus adapté aux applications où la performance n'est pas le critère le plus critique et pour des ensembles de données de taille modérée, il permet de concevoir des représentations graphiques 3D esthétiques et interactives, telles que des nuages de points, des diagrammes à barres et des surfaces.
Types de Graphiques 3D Disponibles
Le module QtDataVisualization propose plusieurs classes pour la visualisation en 3D :
Q3DScatter(Nuage de Points 3D) : Idéal pour représenter des ensembles de données composés de points individuels dans un espace tridimensionnel. La fluidité dépend du matériel, mais environ un millier de points est généralement gérable sans latence notable. Ceci correspond, par exemple, à une grille de 10x10x10 points.Q3DBars(Diagramme à Barres 3D) : Permet de visualiser des données catégorielles en utilisant des barres 3D. Ses performances sont comparables à celles deQ3DScatter.Q3DSurface(Surface 3D) : Utilisé pour afficher des fonctions mathématiques ou des données de hauteur sous forme de surface continue. Ses capacités sont similaires aux autres types de graphiques 3D.
Explorer le Q3DScatter
La classe Q3DScatter est conçue pour afficher des nuages de points dans un environnement 3D interactif. Les utilisateurs peuvent manipuler la scène de plusieurs manières :
- Rotation : Maintenez le bouton droit de la souris enfoncé et déplacez la souris.
- Zoom : Utilisez la molette de la souris.
- Sélection : Cliquez avec le bouton gauche de la souris (si cette fonctionnalité est activée).
- Réinitialisation de la vue : Cliquez sur la molette de la souris pour revenir à la vue de caméra par défaut.
Pour les appareils tactiles, la rotation s'effectue par glissement, la sélection par appui long, et le zoom par pincement.
Si des axes personnalisés ne sont pas définis, Q3DScatter en crée par défaut. Ces axes peuvent être modifiés via leurs accesseurs respectifs. Il est également possible d'afficher plusieurs séries de données simultanément.
Construction d'un Graphique Q3DScatter Minimal
Voici un exemple de code simple pour créer et afficher un nuage de points 3D basique. Ce programme nécessite le module QtDataVisualization.
#include <QGuiApplication>
#include <Q3DScatter>
#include <QScatter3DSeries>
#include <QVector3D>
#include <QScatterDataArray>
// Utilisation de l'espace de noms pour simplifier l'accès aux classes 3D
using namespace QtDataVisualization;
int main(int argc, char **argv)
{
QGuiApplication application(argc, argv);
// Crée une instance du graphique de nuage de points 3D
Q3DScatter *graphiqueNuage = new Q3DScatter();
// Pour une fenêtre autonome, on peut ajuster les drapeaux (si nécessaire)
// graphiqueNuage->setFlags(graphiqueNuage->flags() ^ Qt::FramelessWindowHint);
// Crée une série de points 3D à ajouter au graphique
QScatter3DSeries *serieDePoints = new QScatter3DSeries();
serieDePoints->setMeshSmooth(true); // Active un rendu plus lisse des marqueurs de points
// Définit les données pour le nuage de points
QScatterDataArray donneesInitiales;
donneesInitiales
<< QVector3D(0.2f, 0.8f, 0.5f)
<< QVector3D(-0.6f, -0.2f, -0.3f)
<< QVector3D(0.4f, -0.7f, 0.1f)
<< QVector3D(0.9f, 0.1f, 0.7f)
<< QVector3D(-0.1f, 0.5f, -0.8f);
// Ajoute les points à la série via le proxy de données
serieDePoints->dataProxy()->addItems(donneesInitiales);
// Ajoute la série au graphique 3D
graphiqueNuage->addSeries(serieDePoints);
// Affiche le graphique dans une fenêtre dédiée
graphiqueNuage->show();
return application.exec();
}
L'exécution de ce code affichera une fenêtre avec quelques points en 3D. Vous pourrez interagir avec elle pour faire pivoter la scène ou zoomer.
Guide de Démarrage pour un Projet Q3DScatter
Étape 1 : Vérification de l'Installation du Module
Avant de commencer, assurez-vous que le module QtDataVisualization est bien installé avec votre version de Qt. Vous pouvez le vérifier en consultant la documentation Qt ou en cherchant des classes comme Q3DScatter dans l'aide de votre IDE.
Étape 2 : Configuration du Fichier Projet (.pro)
Pour lier le module à votre projet, ajoutez la ligne suivante à votre fichier .pro :
QT += datavisualization
Étape 3 : Inclusion des Fichiers d'En-tête Nécessaires
Dans vos fichiers source (.h ou .cpp) où vous utiliserez les classes de visualisation 3D, incluez les en-têtes pertinents :
#include <Q3DScatter>
#include <QScatter3DSeries>
#include <QVector3D>
#include <QScatterDataArray>
#include <QAbstract3DGraph> // Pour les paramètres globaux du graphique
#include <Q3DCamera> // Pour la caméra
#include <Q3DTheme> // Pour les thèmes
Étape 4 : Déclaration de l'Espace de Noms
Pour éviter de préfixer chaque classe avec QtDataVisualization::, vous pouvez déclarer l'utilisation de l'espace de noms au début de votre fichier source :
using namespace QtDataVisualization;
Étape 5 : Cadre de Construction du Graphique 3D
Voici un exemple de structure pour un widget Q3DScatter plus complet, montrant la configuraton des axes, des séries de données et des propriétés d'affichage :
#ifndef SCATTERPLOT3DWIDGET_H
#define SCATTERPLOT3DWIDGET_H
#include <QWidget>
#include <Q3DScatter>
#include <QScatter3DSeries>
#include <QVector3D>
#include <QList> // Pour QList<QVector3D>
// Utilisation de l'espace de noms pour les classes de visualisation 3D
using namespace QtDataVisualization;
namespace Ui {
class ScatterPlot3DWidget;
}
class ScatterPlot3DWidget : public QWidget
{
Q_OBJECT
public:
explicit ScatterPlot3DWidget(QWidget *parent = nullptr);
~ScatterPlot3DWidget();
// Méthode publique pour mettre à jour les données du nuage de points
void updatePlotData(const QList<QVector3D>& newDataPoints);
protected:
// Initialise les composants du graphique 3D
void initializePlotComponents();
// Gère le redimensionnement du widget conteneur
void resizeEvent(QResizeEvent *event) override;
private:
Ui::ScatterPlot3DWidget *ui; // Interface utilisateur générée par Qt Designer
Q3DScatter *m_scatterPlot; // L'objet graphique de nuage de points 3D
QWidget *m_widgetContainer; // Le conteneur du graphique 3D
QScatter3DSeries *m_dataSeries; // La série de données pour le nuage de points
};
#endif // SCATTERPLOT3DWIDGET_H
#include "scatterplot3dwidget.h"
#include "ui_scatterplot3dwidget.h"
#include <Q3DTheme> // Pour les thèmes
#include <QAbstract3DGraph> // Pour ShadowQuality
#include <Q3DCamera> // Pour CameraPreset
#include <QtMath> // Pour qMin, qMax
#include <cfloat> // Pour FLT_MAX, FLT_MIN
ScatterPlot3DWidget::ScatterPlot3DWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ScatterPlot3DWidget),
m_scatterPlot(nullptr),
m_widgetContainer(nullptr),
m_dataSeries(nullptr)
{
ui->setupUi(this);
setWindowTitle("Exemple de Nuage de Points 3D avec Q3DScatter");
initializePlotComponents();
}
ScatterPlot3DWidget::~ScatterPlot3DWidget()
{
delete ui;
}
void ScatterPlot3DWidget::updatePlotData(const QList<QVector3D>& newDataPoints)
{
if (!m_dataSeries) {
return; // La série n'est pas initialisée
}
QScatterDataArray dataPointsArray;
float xMin = FLT_MAX, xMax = FLT_MIN;
float yMin = FLT_MAX, yMax = FLT_MIN;
float zMin = FLT_MAX, zMax = FLT_MIN;
// Initialise les bornes avec la première valeur si des points existent
if (!newDataPoints.isEmpty()) {
xMin = xMax = newDataPoints.at(0).x();
yMin = yMax = newDataPoints.at(0).y();
zMin = zMax = newDataPoints.at(0).z();
}
// Ajoute les points et met à jour les bornes des axes
for (const QVector3D& point : newDataPoints)
{
dataPointsArray << point;
xMin = qMin(xMin, point.x());
xMax = qMax(xMax, point.x());
yMin = qMin(yMin, point.y());
yMax = qMax(yMax, point.y());
zMin = qMin(zMin, point.z());
zMax = qMax(zMax, point.z());
}
// Définit les nouvelles données pour la série, remplaçant les anciennes
m_dataSeries->dataProxy()->setItems(dataPointsArray);
// Ajuste les plages des axes avec une petite marge pour la visibilité
const float margin = 0.1f; // Marge de 10%
m_scatterPlot->axisX()->setRange(xMin - margin, xMax + margin);
m_scatterPlot->axisY()->setRange(yMin - margin, yMax + margin);
m_scatterPlot->axisZ()->setRange(zMin - margin, zMax + margin);
}
void ScatterPlot3DWidget::initializePlotComponents()
{
m_scatterPlot = new Q3DScatter();
// Crée un conteneur pour le graphique 3D, parenté à ce widget
m_widgetContainer = QWidget::createWindowContainer(m_scatterPlot, this);
m_widgetContainer->setGeometry(this->rect()); // Positionne le conteneur
// Configuration des axes
m_scatterPlot->axisX()->setTitle("Axe X");
m_scatterPlot->axisY()->setTitle("Axe Y");
m_scatterPlot->axisZ()->setTitle("Axe Z");
m_scatterPlot->axisX()->setTitleVisible(true);
m_scatterPlot->axisY()->setTitleVisible(true);
m_scatterPlot->axisZ()->setTitleVisible(true);
// Crée une série de points pour le nuage 3D
m_dataSeries = new QScatter3DSeries(m_scatterPlot);
m_dataSeries->setMeshSmooth(true); // Active le lissage des points pour un rendu plus doux
m_dataSeries->setItemLabelVisible(true); // Rend les labels de points visibles
m_dataSeries->setItemLabelFormat(QStringLiteral("X:%2.1f Y:%2.1f Z:%2.1f")); // Format du label des points
// Ajoute la série au graphique 3D
m_scatterPlot->addSeries(m_dataSeries);
// Paramètres d'affichage globaux du graphique
m_scatterPlot->setShadowQuality(QAbstract3DGraph::ShadowQualityMedium); // Qualité moyenne des ombres
m_scatterPlot->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFrontLow); // Vue de caméra initiale
m_scatterPlot->activeTheme()->setGridEnabled(true); // Active l'affichage de la grille
m_scatterPlot->activeTheme()->setBackgroundEnabled(false); // Désactive l'arrière-plan par défaut
m_scatterPlot->activeTheme()->setLabelBackgroundEnabled(false); // Désactive l'arrière-plan des labels d'axes
// Données initiales pour la démonstration
QList<QVector3D> initialData;
initialData << QVector3D(1.0f, 1.0f, 1.0f) << QVector3D(1.0f, 2.0f, 3.0f) << QVector3D(1.0f, 3.0f, 5.0f)
<< QVector3D(3.0f, 1.0f, 1.0f) << QVector3D(3.0f, 2.0f, 3.0f) << QVector3D(3.0f, 3.0f, 5.0f)
<< QVector3D(5.0f, 1.0f, 1.0f) << QVector3D(5.0f, 2.0f, 3.0f) << QVector3D(5.0f, 3.0f, 5.0f);
updatePlotData(initialData); // Charge les données initiales
}
void ScatterPlot3DWidget::resizeEvent(QResizeEvent *event)
{
// Redimensionne le conteneur du graphique pour qu'il occupe tout l'espace du widget parent
if (m_widgetContainer)
{
m_widgetContainer->setGeometry(rect());
}
QWidget::resizeEvent(event); // Appel à la méthode de base
}
Résolution des Problèmes Courants
Problème : La Classe Q3DScatter est Introuvable
Symptôme : Le compilateur ou l'IDE affiche des erreurs indiquant que la classe Q3DScatter est indéfinie ou inconnue.
Cause : Les classes du module QtDataVisualization résident dans un espace de noms spécifique qui doit être explicitement importé ou qualifié.
Solution : Ajoutez la directive using namespace QtDataVisualization; au début de vos fichiers source où ces classes sont utilisées, ou qualifiez les noms de classe directement (par exemple, QtDataVisualization::Q3DScatter).