Corde, tangente et dérivée

Il s'agit dans cet exemple de tracer la courbe de la fonction f (x) = 0,5 x2, un point M et un point N mobiles sur l'axe des x puis A et B deux points de même abscisse sur la courbe de la fonction. Plus B se rapproche de A plus la corde se rapproche de la tangente.

Le programme affiche en outre le coefficient directeur de la droite (AB) et le coefficient directeur de la tangente donnée par le nombre dérivé.

tgte_derivee.png

Répertoire : tgte_derivee. Trois fichiers sont utilisés : main.cpp, fenetre.h et fenetre.cpp.

main.cpp

#include <QApplication>

#include "fenetre.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.

fenetre.h

#ifndef FENETRE_H
#define FENETRE_H

#include <QtGui>
#include "geo2D/courbe.h"
#include "geo2D/point_sur_droite.h"
#include <math.h>
#include <stdio.h>

class fderivee: public fonction {

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

class Fenetre: public QWidget {

    Q_OBJECT

public:
    repere *R;
    droite *ox, *AB;
    fonction *f;
    fderivee *df;
    courbe *c;
    point_sur_droite *M, *N;
    pt *A, *B;
    segment *AM, *BN;

On déclare ici tous les objets géométriques qui seront utilisés : le repère, la droite ox, support des points M et N, la fonction f, sa courbe c et la dérivée df qui servira à calculer le coefficient directeur de la tangente.

    bool presse;
    bool debut;

Indicateur signalant s'il y a un déplacement en cours et qu'on "peint" la fenêtre la première fois.

    Fenetre (QWidget *parent = 0);

protected:
    void paintEvent (QPaintEvent *);
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

};

#endif

On définit ici les quatre fonctions gérant le dessin et l'action de la souris (appui sur le bouton, déplacement, relâchement).

fenetre.cpp

/*
 * tgte_derivee
 *
 * trace la tangente à une courbe
 * affiche le coefficient directeur de la droite
 * et le nombre dérivé en ce point
 */

#include "fenetre.h"


bool fonction::def (double) {
    return true;
}

double fonction::image (double x) {
    return 0.25 * x * x;
}

bool fderivee::def (double) {
    return true;
}

double fderivee::image (double x) {
    return 0.5 * x ;
}

On définit ici la fonction f (x) = 0,25 x2 et sa dérivée f' (x) = 0,5 x comme sur-classe de la classe fonction.

Fenetre::Fenetre (QWidget *parent): QWidget (parent) {
    setGeometry (0, 0, 600, 450);
    setMouseTracking (true);
    setCursor (Qt::ArrowCursor);
    presse = false;
    debut = true;

Constructeur de la fenêtre principale : on indique sa taille, on donne la possibilité de gérer le déplacement de la souris sans qu'on ait besoin d'appuyer sur le bouton (setMouseTracking (true);), on fixe le curseur par défaut puis on initialise l'indicateur de déplacement et l'indicateur du début.

    double xM = 1.0;
    double xN = 4.0;
    R = new repere (300, 400, 600, 450, 50.0, 50.0, 1.0, 1.0);
    ox = new droite (0.0, 1.0, 0.0, NULL, R);
    M = new point_sur_droite (xM, 0.0, ox, "M", R);
    N = new point_sur_droite (xN, 0.0, ox, "N", R);
    f = new fonction;
    c = new courbe (f, NULL, R);
    df = new fderivee;

    A = new pt (xM, (*f).image (xM), "A", R);
    B = new pt (xN, (*f).image (xN), "B", R);
    AB = new droite (A, B, NULL, R);
    AM = new segment (A, M, NULL, R);
    BN = new segment (B, N, NULL, R);
}

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

void Fenetre::paintEvent (QPaintEvent *) {
    if (debut) {
        debut = false;
        setPalette (QPalette (QColor (255, 255, 255)));
        setAutoFillBackground (true);
    }

    QPainter painter (this);
    painter.setPen (Qt::red);
    (*R).trace (&painter);
    (*M).trace (&painter);
    (*N).trace (&painter);

    painter.setPen (Qt::black);
    (*c).trace (&painter);
    (*AM).trace (&painter);
    (*BN).trace (&painter);

    painter.setPen (Qt::blue);
    (*A).trace (&painter);
    (*B).trace (&painter);
    (*AB).trace (&painter);

On redessine ici la figure : on peint le fond en blanc la première fois puis on trace le repère en rouge puis les points M et N et enfin le reste en noir et bleu.

    double coef = - (*AB).a / (*AB).b;
    double nderiv = (*df).image ((*M).x);
    char str [256];
    sprintf (str, "Coefficient directeur de AB : %lf ; dérivée : %lf", coef, nderiv);
    painter.drawText (20, 20, QString::fromUtf8 (str));
}

On calcule le coefficient directeur de la droite et le nombre dérivé et on les affiche à l'écran.

void Fenetre::mousePressEvent (QMouseEvent *event) {
    int X = (*event).x ();
    int Y = (*event).y ();
    presse = (*M).select (X, Y) || (*N).select (X, Y);
    if (presse)
        setCursor (Qt::ClosedHandCursor);
}

On teste, dans cet ordre, si la souris est proche de M ou de N. Si c'est le cas l'indicateur de déplacement du point est positionné ainsi que le booléen presse. On change ensuite le curseur.

void Fenetre::mouseMoveEvent (QMouseEvent *event) {
    int X = (*event).x ();
    int Y = (*event).y ();
    if (presse) {
        if ((*M).bouge (X, Y)) {
            (*A).pt_x_y ((*M).x, (*f).image ((*M).x));
            (*AM).segment_pt_pt (A, M);
        }
        if ((*N).bouge (X, Y)) {
            (*B).pt_x_y ((*N).x, (*f).image ((*N).x));
            (*BN).segment_pt_pt (B, N);
        }
        (*AB).droite_pt_pt (A, B);
        update ();
    } else {
        if ((*M).zone (X, Y) || (*N).zone (X, Y))
            setCursor (Qt::PointingHandCursor);
        else
            setCursor (Qt::ArrowCursor);
    }
}

Si on bouge la souris sans appuyer sur le bouton en change simplement le curseur à proximité de M ou de N sinon on déplace le point A ou B et on recalcule la droite (AB).

void Fenetre::mouseReleaseEvent (QMouseEvent *) {
    (*M).stop ();
    (*N).stop ();
    presse = false;
    setCursor (Qt::PointingHandCursor);
}

On relâche de bouton de la souris : on remet alors tous les indicateurs de déplacement à FALSE puis on change le curseur.