L'astroïde - avec un "thread"

C'est une courbe d'équation x2/3 + y2/3 = k que décrit un point d'un cercle qui roule sans glisser à l'intérieur d'un cercle de rayon 4 fois plus grand. L'animation est lancée ou arrêtée dès l'appui sur le bouton ok. L'animation se fait dans une boucle séparée (un thread) dont le démarrage et l'arrêt est régi par des "clic" sur le bouton "Ok".

astroide1.png

Répertoire : astroide. Trois fichiers : main.cpp, astroide.h et astroide.cpp.

main.cpp

#include <QApplication>

#include "astroide.h"

int main (int argc, char *argv []) {
     QApplication app (argc, argv);
     Fenetre f;
     f.show();
     return app.exec ();
}

On crée l'application app, le fenêtre principale f puis on lance la boucle d'exécution app.

astroide.h

#ifndef ASTROIDE_H
#define ASTROIDE_H

#include 

#include "geo2D/cercle.h"
#include "geo2D/courbe.h"

class fonction1: public fonction {

public:
    bool def (double);
    double image (double x);
};

class Dessin: public QWidget {

    Q_OBJECT

public:
    repere *R;
    pt *O, *M, *P;
    cercle *c, *c1;
    double angle;
    fonction *f;
    fonction1 *f1;
    courbe *cf;
    courbe *cf1;

On définit ici les objets graphiques

    Dessin (QWidget *parent = 0);

protected:
    void paintEvent (QPaintEvent *);
};

class Boucle: public QThread {

    Q_OBJECT

public:
    Dessin *canvas;
    void run ();


};

La boucle de tracé est mise dans un "thread" séparé. Le pointeur vers canvas sert à la modification de l'image et run() est la boucle d'exécution.

class Astroide: public QWidget {

    Q_OBJECT

public:
    QPushButton *bouton;
    Dessin *canvas;
    Boucle *bcl;
    bool deplace;

    Astroide (QWidget *parent = 0);

public slots:
    void action ();
};

La fenêtre principale contient les pointeurs vers le bouton "Ok", la feuille de dessin et la boucle d'exécution. Tout "clic" sur le bouton entraîne l'exécution de la méthode action().

astroide.cpp

/*
 * astroide1
 *
 */


#include "astroide.h"

bool fonction::def (double x) {
    return (x >= -4) && (x <= 4);
}

double fonction::image (double x) {
    if (x < 0.0)
        x = - x;
    return pow (2.5198420998 - pow (x, 0.6666666666666), 1.5);
}

bool fonction1::def (double x) {
    return fonction::def (x);
}

double fonction1::image (double x) {
    return - fonction::image (x);
}

Définition de 2 fonctions : la première est f (x) = (k - x2/3)3/2et la seconde f1 (x) = - f(x).

void Boucle::run () {
    while (true) {
        msleep (50);

        canvas -> angle += 0.02;
        canvas -> M -> pt_x_y (3.0 * cos (canvas -> angle), 3.0 * sin (canvas -> angle));
        canvas -> c1 -> cercle_pt_r (canvas -> M, 1);
        canvas -> P -> pt_x_y (canvas -> M -> x + cos (canvas -> angle * 3), canvas -> M -> y + sin (- canvas -> angle * 3));

        canvas -> update ();
    }
}

Boucle chargée de l'animation : on attend 50 ms, on ajoute 0,02 radians à l'angle (Ox, OM) on met à jour les éléments du graphique puis on redessine la figure.

Dessin::Dessin (QWidget *parent): QWidget (parent) {
    setGeometry (0, 0, 500, 500);
    R = new repere (250, 250, 500, 500, 50.0, 50.0, 1.0, 1.0);
    O = new pt (0.0, 0.0, NULL, R);
    c = new cercle (O, 4, NULL, R);
    M = new pt (3.0, 0.0, NULL, R);
    c1 = new cercle (M, 1, NULL, R);
    P = new pt (4, 0, "P", R);
    angle = 0.0;
    f = new fonction;
    cf = new courbe (f, NULL, R);
    f1 = new fonction1;
    cf1 = new courbe (f1, NULL, R);
}

On crée ici les objets géométriques.

 

On donne un titre à la fenêtre, sans oublier le fromUtf8 à cause du ï puis on dimensionne la fenêtre.

void Dessin::paintEvent (QPaintEvent *) {
    if (angle == 0.0) {
        setPalette (QPalette (QColor (255, 255, 255)));
        setAutoFillBackground (true);
    }
    QPainter painter (this);
    painter.setPen (Qt::red);
    R -> trace (&painter);
    painter.setPen (Qt::green);
    cf -> trace (&painter);
    cf1 -> trace (&painter);
    painter.setPen (Qt::blue);
    c -> trace (&painter);
    c1 -> trace (&painter);
    P -> trace (&painter);
}

La première fois on peint le fond en blanc puis on dessine la figure..

void Astroide::action () {
    if (deplace) {
        bouton -> setText ("Ok");
        bcl -> terminate ();
    } else {
        bouton -> setText ("Stop");
        bcl -> start ();
    }
    deplace = ! deplace;
}

Méthode invoquée à chaque "clic" sur le bouton. On lance (start()), ou au contraire, au arrête le processus bcl (méthode terminate()). On change aussi le texte du bouton.

Astroide::Astroide (QWidget *parent): QWidget (parent) {
    bouton = new QPushButton ("Ok", this);
    bouton-> minimumSize ();
    connect (bouton, SIGNAL (clicked ()), this, SLOT (action ()));
    deplace = false;

On crée le bouton "Ok" et on associe le "clic" sur ce bouton à la méthode action() qui se trouve dans la même classe (this).

    canvas = new Dessin (parent);

    bcl = new Boucle ();
    bcl -> canvas = canvas;

    QVBoxLayout *vboite = new QVBoxLayout;
    vboite -> addWidget (bouton);
    vboite -> addWidget (canvas);
    setLayout (vboite);
    setGeometry (0, 0, 550, 550);
}

On crée la feuille de dessin nommée canvas et la boucle. On monte enfin le bouton et le canvas verticalement dans la fenêtre principals.