1. Affichage de graphes de fonctions mathématiques

Objectif: Se familiariser avec la "librairie" lspxgraph pour dessiner des fonctions paramétriques dans une fenêtre X11.

Introduction

Comme vu dans le complément du cours sur l'affichage et la gestion de fenêtres sous les systèmes Unix, ceux-ci sont basée sur le système X Window (communément appelé X11 ou simplement X).

Pour que vous ne deviez pas vous occuper de toute l'interaction avec Xlib, on va utiliser une petite collection de fonctions appelée lspxgraph, dont les caractéristiques principales sont de fournir :

La librairie est conçue pour être facile à utiliser et l'implémentation devrait être compréhensible pour tous les étudiants.

Vue globale sur les fonctionnalités

Pour avoir une vue sur les fonctionnalités mises à disposition par une librairie, il faut lire le fichier d'en-tête principal. Dans notre cas, c'est le fichier lspxgraph.h :

#ifndef _INCLUDE_LSPXGRAPH_H_
#define _INCLUDE_LSPXGRAPH_H_

/** Window functions */
void createWindow(const char *name, int width, int height);
void closeWindow(void);
void flushWindow(void);
void clearWindow(void);

/** Graphic functions */
void setAxis(double xmin, double xmax, double ymin, double ymax);
void setColor(float red, float green, float blue);
void setLineWidth(int width);
void drawPoint(double x, double y);
void drawLine(double sx, double sy, double ex, double ey);
void drawString(double x, double y, const char *str);
void drawAxis(void);

#endif

Les lignes commençant par le caractère dièse (#) sont des commandes pour le préprocesseur du compilateur. Elles servent à éviter que les déclarations de fonctions soient inclues plusieurs fois à la compilation.

Nous nous rendons compte qu'il y a trois types de fonctions:

  1. Fonctions de gestion de fenêtres se terminant avec Window
  2. Fonctions de modification de propriétés (préfixé set)
  3. Fonctions de dessins (préfixé draw)

Programme d'exemple

Copiez le programme suivant dans un fichier ex1_points.c:

#include <stdlib.h>
#include <unistd.h>
#include "lspxgraph.h"

int main(void)
{
    int i;
    createWindow("Random points", 200, 200);

    for(i=0; i<10000; i++)
    {
        double x = (double)rand() / RAND_MAX;
        double y = (double)rand() / RAND_MAX;
        drawPoint(x, y);
        flushWindow();
    }

    sleep(5);
    closeWindow();
    return 0;
}

Notez les deux fichiers d'en-tête qui sont inclus au début du code:

Le programme utilise la fonction rand() pour générer des nombres aléatoires. Voilà le prototype :

int rand(void);

Cette fonction retourne un entier aléatoire entre 0 et RAND_MAX. La fonction ainsi que la constante RAND_MAX sont définies dans le fichier d'en-tête stdlib.h.

Avant de compiler et tester ce programme, vous devez télécharger les fichiers lspxgraph.c et lspxgraph.h et les mettre dans votre répertoire de travail.
Pour compiler, utilisez la commande suivante:

gcc -o main ex1_points.c lspxgraph.c -lm -lX11 -L/usr/X11R6/lib

Elle assure que la librairie lspxgraph, la librairie mathématique et la librairie X11 sont utilisées pour créer l'exécutable main. Avant même d'exécuter ce petit programme, vous pouvez vous rendre compte qu'il ouvre une fenêtre (de taille 200x200 pixel), dessine 10000 points aléatoires et attend 5 secondes avant de terminer.

Question 1.1 : Dans quel intervalle doivent se trouver les coordonnées (x, y) des points pour qu'ils soient affichés dans la fenêtre? (Hint: Réfléchissez ou lisez le code source de lspxgraph.c)

Manipulation 1.1 : Créez un programme similaire qui dessine des droites aléatoires (position, couleur et largeur du trait aléatoires).
Pour ce faire, étudiez le fichier d'en-tête lspxgraph.h (en particulier les fonctions setColor(), setLineWidth() et drawLine()).

Tracer des graphes de fonctions

Comme décrit dans l'introduction, la librairie lspxgraph est prévue pour dessiner des graphes de fonctions mathématiques. En particulier, elle utilise le même système de coordonnées. Ce système de coordonnées peut être modifié grâce à la fonction suivante :

void setAxis(double xmin, double xmax,
             double ymin, double ymax);

Si on veut afficher le graphe de la fonction cos() (qui est déclarée dans le fichier d'en-tête math.h et qui appartient à la librairie standard de C) dans le domaine 0..2π, il faut modifier les axes pour que tous les points (x,y) avec x∈[0..2π] et y∈[-1..1] soient inclus dans l'affichage. Ceci se fait par l'appel suivant :

setAxis(0, 2*PI, -1, 1);

Notez que vous devez définir vous-même la macro PI. Alternativement, vous pouvez utiliser la macro M_PI défini dans le fichier d'en-tête math.h. L'inconvénient est que M_PI n'existe pas sur toutes les plateformes.

Manipulation 1.2 : Créez un programme pour afficher le graphe de la fonction y=cos(x), x ∈[0, 2π]. Parcourez le domaine de définition des x avec une "taille de pas" de 0.05, calculez la fonction et dessinez les points avec drawPoint().

Manipulation 1.3 : Créez une fonction trace() qui prend comme argument un pointeur de fonction (p.ex. cos()), le domaine de définition de x et la taille de pas. Elle trace le graphe de la fonction passée en argument en connectant des segments de droites.
Vous pouvez vous inspirer du prototype suivant :

void trace(double (*f)(double x), double xmin,
            double xmax, double xincrement);

Manipulation 1.4 : Etendez le programme pour qu'il soit capable de tracer des fonctions paramétriques (données par deux fonctions x=fx(t), y=fy(t) qui calculent un point à partir d'un paramètre t). Testez le comportement avec:

trace(cos, sin, 0, 2*PI, 0.05);