Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. International
  3. French
  4. Système Solaire : Scène, View et items laissant une trace matérialisant leur trajectoire.
Forum Updated to NodeBB v4.3 + New Features

Système Solaire : Scène, View et items laissant une trace matérialisant leur trajectoire.

Scheduled Pinned Locked Moved Solved French
4 Posts 2 Posters 689 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Morgatte
    wrote on last edited by
    #1

    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;}
    
    
    
    1 Reply Last reply
    0
    • SGaistS SGaist

      Hi,

      Why are you calling planet->trailPath.moveTo(0, 0); for every "non-initial value" ?

      M Offline
      M Offline
      Morgatte
      wrote on last edited by
      #3

      @SGaist

      Ok I found a solution. That's work now.

      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi,

        Why are you calling planet->trailPath.moveTo(0, 0); for every "non-initial value" ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        M 1 Reply Last reply
        0
        • SGaistS SGaist

          Hi,

          Why are you calling planet->trailPath.moveTo(0, 0); for every "non-initial value" ?

          M Offline
          M Offline
          Morgatte
          wrote on last edited by
          #3

          @SGaist

          Ok I found a solution. That's work now.

          1 Reply Last reply
          0
          • M Morgatte has marked this topic as solved on
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #4

            Désolé, je viens de voir que j'avais répondu en Anglais !

            Quelle est la solution trouvée ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved