L'Astroïde avec un "timer" pour contrôler l'animation

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 dès le démarrage : une nouvelle image est calculée toutes les 50ms.

astroide2.png

Répertoire : astroide2. 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 <QtGui>

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

class fonction1: public fonction {

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

Il faut deux fonctions car x2/3 + y2/3 = k équivaut à y = (k - x2/3)3/2 ou y = - (k - x2/3)3/2.

class Astroide: public QWidget {

    Q_OBJECT

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

On déclare ici tous les objets géométriques qui seront utilisés.

    bool deplace;

    Astroide (QWidget *parent = 0);

protected:
    void paintEvent (QPaintEvent *);
};

class Fenetre: public QWidget {

    Q_OBJECT

public:
    QPushButton *bouton;
    Astroide *ast;

    Fenetre (QWidget *parent = 0);

public slots:
    void action ();
};

La fenêtre principale contient le bouton et la feuille de dessin ast.

astroide.cpp

/*
 * astroide2
 *
 */

#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).

Astroide::Astroide (QWidget *parent): QWidget (parent) {

    QTimer *timer = new QTimer (this);
    connect (timer, SIGNAL (timeout ()), this, SLOT (update ()));
    timer -> start (50);

On constuit un "timer" qui envoie un signal tous les 50 ms. A chaque "timeout" on redessine la figure. L'instruction connect relie chaque "timout" à la méthode update.

    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, "M", 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.

    setWindowTitle (QString::fromUtf8 ("L'Astroïde"));
    resize (500, 500);
}

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

void Astroide::paintEvent (QPaintEvent *) {
    if (angle == 0.0) {
        setPalette (QPalette (QColor (255, 255, 255)));
        setAutoFillBackground (true);
    }

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

    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.

On ajoute 0.02 à l'angle que fait le petit cercle avec l'axe des abscisses puis on recalcule les coordonnées des points qui se sont déplacés.

Et enfin on redessine le tout.

void Fenetre::action () {
    if (ast -> deplace) {
        ast -> deplace = false;
        bouton -> setText ("Ok");
    } else {
        ast -> deplace = true;
        bouton -> setText ("Stop");
    }
}

Un "clic" sur le bouton : onchange l'indicateur deplace puis le texte du bouton.

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

    ast = new Astroide (parent);

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

Constructeur de la fenêtre principale : on crée le bouton associé à la méthode action() puis la feuille de dessin. On dispose enfin ces deux objets verticalement dans la fenêtre.