Système Solaire : Scène, View et items laissant une trace matérialisant leur trajectoire.
Unsolved
French
-
Bonjour,
Je me bats pour que mes items (des planètes laissent une trace derrière eux. Rien y fait.
J'utilise Une Scène avec une view dans laquelle mes planètes (des items) se déplacent.
Normalement avec un QGraphicsPathItem je devrais pouvoir laisser une trace mais rien y fait.Quelqu'un pourrait-il regarder ce qui cloche, le problème vient de la fonction void MainWindow::updateSimulation(){.........}
Voici mon code :
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGraphicsScene> #include <QTimer> #include <vector> #include <QSlider> #include <QGraphicsView> #include <QVBoxLayout> #include <QPushButton> #include "planetes.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void updateSimulation(); //void updateSimulation(int prevPosX, int prevPosY); void onZoomSliderValueChanged(int value); // Slot pour le zoom void onButtonRecentrer(); private: QGraphicsScene* m_scene; QGraphicsView* m_view; // Ajoutez la vue comme membre QSlider* m_zoomSlider; // Curseur pour gérer le zoom QPushButton* m_boutonRecentrage; QTimer* m_timer; std::vector<Planete*> m_planets; int prevPosX=0; int prevPosY=0; void setupScene(); void setupPlanets(); void rungeKuttaStep(double dt); }; #endif // MAINWINDOW_H
#include "mainwindow.h" #include <QGraphicsView> #include <QVBoxLayout> #include <cmath> // Constantes physiques et de mise à l'échelle const double G = 6.67e-20; // Constante gravitationnelle en km^3/(kg·s^2) (G en unités km) const double sceneScale = 1e-7; // Facteur d'échelle pour convertir les km en pixels // Structure pour stocker l'état d'une planète (pour l'intégration) struct State { double x, y, vx, vy; }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setupScene(); setupPlanets(); // Création du trail pour chaque planète et ajout à la scène for(auto planet : m_planets) { planet->trailItem = new QGraphicsPathItem(); QPen pen(Qt::white); // pen.setStyle(Qt::DotLine); pen.setStyle(Qt::SolidLine); pen.setWidth(3); // Augmente la largeur pour une meilleure visibilité planet->trailItem->setPen(pen); planet->trailItem->setZValue(-1); // pour que le trail reste derrière l'item de la planète m_scene->addItem(planet->trailItem); } // Ajout des items graphiques (les ellipses) à la scène for(auto planet : m_planets) { m_scene->addItem(planet->graphicsItem()); } // Création de la vue m_view = new QGraphicsView(m_scene); // Création du curseur de zoom m_zoomSlider = new QSlider(Qt::Horizontal); m_zoomSlider->setRange(1, 200); // Plage de zoom de 1x à 20x (vous pouvez ajuster) m_zoomSlider->setValue(100); // Valeur par défaut = zoom x10 connect(m_zoomSlider, &QSlider::valueChanged, this, &MainWindow::onZoomSliderValueChanged); m_boutonRecentrage = new QPushButton("Recentrer", this); // Création d'un widget central contenant la vue et le curseur QWidget* centralWidget = new QWidget(this); QVBoxLayout* layout = new QVBoxLayout(centralWidget); layout->addWidget(m_view); layout->addWidget(m_zoomSlider); layout->addWidget(m_boutonRecentrage); setCentralWidget(centralWidget); // Optionnel : centrer la vue sur le Soleil m_view->centerOn(m_planets[0]->graphicsItem()); // Timer pour la simulation m_timer = new QTimer(this); connect(m_timer, &QTimer::timeout, this, &MainWindow::updateSimulation); /* connect(m_timer, &QTimer::timeout, this, [this]() { int prevPosX = 0; // Remplace par une valeur appropriée int prevPosY = 0; // Remplace par une valeur appropriée updateSimulation(prevPosX, prevPosY); }); */ connect(m_boutonRecentrage, &QPushButton::clicked, this, &MainWindow::onButtonRecentrer); m_timer->start(5); // mise à jour toutes les 30 ms } MainWindow::~MainWindow() { for(auto planet : m_planets) delete planet; } void MainWindow::setupScene() { m_scene = new QGraphicsScene(this); // Définir le rectangle de la scène (à ajuster selon la taille souhaitée) m_scene->setSceneRect(-500, -600, 1000, 1000); m_scene->setBackgroundBrush(QColor(55, 55, 75, 255)); } void MainWindow::setupPlanets() { // Données : Nom ; Diamètre (km) ; Masse (kg) ; Vitesse au périhélie (km/s) ; Distance au périhélie (10^6 km) ; Intensité de la force (N) m_planets.push_back(new Planete("Soleil", 1392700, 1.989e30, 5, 0)); m_planets.push_back(new Planete("Mercure", 4880, 3.30e23, 58.98, 46.0)); m_planets.push_back(new Planete("Vénus", 12104, 4.87e24, 35.26, 107.5)); m_planets.push_back(new Planete("Terre", 12742, 5.97e24, 30.29, 147.1)); m_planets.push_back(new Planete("Mars", 6779, 6.42e23, 26.50, 206.7)); m_planets.push_back(new Planete("Jupiter", 139820, 1.90e27, 13.72, 740.6)); m_planets.push_back(new Planete("Saturne", 116460, 5.68e26, 10.18, 1353.6)); m_planets.push_back(new Planete("Uranus", 50724, 8.68e25, 7.11, 2748.9)); m_planets.push_back(new Planete("Neptune", 49244, 1.02e26, 5.50, 4452.9)); m_planets.push_back(new Planete("Astra Masif", 92, 1.989e31, -7.0, 2440.0)); } //void MainWindow::updateSimulation(int prevPosX, int prevPosY) void MainWindow::updateSimulation() { double dt = 86400; // pas de temps en secondes rungeKuttaStep(dt); for(auto planet : m_planets) { double sceneX = planet->x * sceneScale; double sceneY = planet->y * sceneScale; planet->graphicsItem()->setPos(sceneX, sceneY); // Ajouter la nouvelle position au chemin de la planète if (planet->trailPath.isEmpty()) { planet->trailPath.moveTo(sceneX, sceneY); } else { planet->trailPath.moveTo(0, 0); planet->trailPath.lineTo(planet->prevX * sceneScale, planet->prevY * sceneScale); } // Mettre à jour l'élément graphique de la trace planet->trailItem->setPath(planet->trailPath); } //qDebug() << m_planets[5]->getName() << "nombre d'éléments dans le chemin:" << m_planets[5]->trailPath.elementCount() << "posY" << m_planets[5]->y; } // Fonction qui calcule les dérivées de l'état (dx/dt = vx, dy/dt = vy, et l'accélération) std::vector<State> computeDerivatives(const std::vector<State>& states, const std::vector<Planete*>& planets) { size_t n = states.size(); std::vector<State> derivatives(n); for (size_t i = 0; i < n; i++) { derivatives[i].x = states[i].vx; derivatives[i].y = states[i].vy; double ax = 0; double ay = 0; // Somme des contributions de toutes les autres planètes for (size_t j = 0; j < n; j++) { if(i == j) continue; double dx = states[j].x - states[i].x; double dy = states[j].y - states[i].y; double distSq = dx * dx + dy * dy; double dist = std::sqrt(distSq); if(dist < 1e-5) continue; // éviter la singularité double factor = G * planets[j]->getMass() / (distSq * dist); ax += factor * dx; ay += factor * dy; } derivatives[i].vx = ax; derivatives[i].vy = ay; } return derivatives; } // Intégration par Runge-Kutta (ordre 4) sur un pas de temps dt void MainWindow::rungeKuttaStep(double dt) { size_t n = m_planets.size(); std::vector<State> currentStates(n); for (size_t i = 0; i < n; i++) { currentStates[i] = { m_planets[i]->x, m_planets[i]->y, m_planets[i]->vx, m_planets[i]->vy }; } // Calcul de k1 auto k1 = computeDerivatives(currentStates, m_planets); // k2 : état intermédiaire std::vector<State> states2(n); for (size_t i = 0; i < n; i++) { states2[i].x = currentStates[i].x + dt/2 * k1[i].x; states2[i].y = currentStates[i].y + dt/2 * k1[i].y; states2[i].vx = currentStates[i].vx + dt/2 * k1[i].vx; states2[i].vy = currentStates[i].vy + dt/2 * k1[i].vy; } auto k2 = computeDerivatives(states2, m_planets); // k3 : autre état intermédiaire std::vector<State> states3(n); for (size_t i = 0; i < n; i++) { states3[i].x = currentStates[i].x + dt/2 * k2[i].x; states3[i].y = currentStates[i].y + dt/2 * k2[i].y; states3[i].vx = currentStates[i].vx + dt/2 * k2[i].vx; states3[i].vy = currentStates[i].vy + dt/2 * k2[i].vy; } auto k3 = computeDerivatives(states3, m_planets); // k4 : état final estimé std::vector<State> states4(n); for (size_t i = 0; i < n; i++) { states4[i].x = currentStates[i].x + dt * k3[i].x; states4[i].y = currentStates[i].y + dt * k3[i].y; states4[i].vx = currentStates[i].vx + dt * k3[i].vx; states4[i].vy = currentStates[i].vy + dt * k3[i].vy; } auto k4 = computeDerivatives(states4, m_planets); // Mise à jour de l'état selon la formule RK4 for (size_t i = 0; i < n; i++) { m_planets[i]->prevX = m_planets[i]->x; m_planets[i]->prevY = m_planets[i]->y; m_planets[i]->x += dt/6 * (k1[i].x + 2*k2[i].x + 2*k3[i].x + k4[i].x); m_planets[i]->y += dt/6 * (k1[i].y + 2*k2[i].y + 2*k3[i].y + k4[i].y); m_planets[i]->vx += dt/6 * (k1[i].vx + 2*k2[i].vx + 2*k3[i].vx + k4[i].vx); m_planets[i]->vy += dt/6 * (k1[i].vy + 2*k2[i].vy + 2*k3[i].vy + k4[i].vy); } } void MainWindow::onZoomSliderValueChanged(int value) { double factor = value / 10.0; // Conversion pour obtenir un facteur décimal m_view->resetTransform(); m_view->scale(factor, factor); } void MainWindow::onButtonRecentrer() { /* for(auto planet : m_planets) { planet->x -= m_planets[0]->x; planet->y -= m_planets[0]->y; } m_planets[3]->x -= m_planets[0]->x; m_planets[3]->y -= m_planets[0]->y; m_planets[0]->x=0; m_planets[0]->x=0; */ m_view->centerOn(m_planets[0]->graphicsItem()); qDebug() << m_planets[0]->getName(); }
#ifndef PLANETES_H #define PLANETES_H #include <QString> #include <QGraphicsEllipseItem> #include <QGraphicsTextItem> #include <QGraphicsPathItem> class Planete { public: // Constructeur : pour le Soleil, perihelionVel et perihelionDist seront 0. Planete(const QString &name, double diameter, double mass, double perihelionVel, double perihelionDist); QString getName() const; double getMass() const; double getDiameter() const; // Variables d'état (position en km et vitesse en km/s) double x, y, prevX, prevY; double vx, vy; QGraphicsTextItem* label; // Ajout du label pour le nom QGraphicsEllipseItem* graphicsItem(); // Retourne l’item graphique associé (pour l’affichage dans la scène) QGraphicsPathItem* trailItem; // Ajout d'un attribut pour le tracé QPainterPath trailPath; // Ajout de cet attribut private: QString m_name; double m_diameter; double m_mass; QGraphicsEllipseItem* m_item; }; #endif // PLANETES_H
#include "planetes.h" #include <QBrush> #include <QPen> Planete::Planete(const QString &name, double diameter, double mass, double perihelionVel, double perihelionDist) : m_name(name), m_diameter(diameter), m_mass(mass) { // Initialisation des conditions if(name == "Soleil") { x = 0; y = 0; vx = 0; vy = 0; } else { // Position initiale : à distance de périhélie sur l'axe des X (conversion : donnée en 10^6 km -> km) x = perihelionDist * 1e6; y = 0; // Vitesse initiale perpendiculaire au rayon (sur l'axe des Y) vx = 0; vy = perihelionVel; } // Création de la représentation graphique // La taille visuelle est fixée arbitrairement (le Soleil sera plus grand) double visualRadius = (name == "Soleil") ? 10 : 4; m_item = new QGraphicsEllipseItem(-visualRadius, -visualRadius, 2 * visualRadius, 2 * visualRadius); // Choix de la couleur en fonction du nom if(name == "Soleil") { m_item->setBrush(QBrush(Qt::yellow)); } else if(name == "Mercure") { m_item->setBrush(QBrush(Qt::gray)); } else if(name == "Vénus") { m_item->setBrush(QBrush(Qt::magenta)); } else if(name == "Terre") { m_item->setBrush(QBrush(Qt::blue)); } else if(name == "Mars") { m_item->setBrush(QBrush(Qt::red)); } else if(name == "Jupiter") { m_item->setBrush(QBrush(Qt::darkYellow)); } else if(name == "Saturne") { m_item->setBrush(QBrush(Qt::darkGray)); } else if(name == "Uranus") { m_item->setBrush(QBrush(Qt::cyan)); } else if(name == "Neptune") { m_item->setBrush(QBrush(Qt::blue)); } else { m_item->setBrush(QBrush(Qt::white)); } m_item->setPen(QPen(Qt::NoPen)); // Création du label pour afficher le nom au-dessus de l’item label = new QGraphicsTextItem(m_name); label->setDefaultTextColor(Qt::white); label->setPos(-label->boundingRect().width()/2, -40); // Position relative à l’ellipse (par exemple, légèrement au-dessus) label->setParentItem(m_item); } QString Planete::getName() const {return m_name;} double Planete::getMass() const {return m_mass;} double Planete::getDiameter() const {return m_diameter;} QGraphicsEllipseItem* Planete::graphicsItem() {return m_item;}
-
Hi,
Why are you calling
planet->trailPath.moveTo(0, 0);
for every "non-initial value" ?