TP — Art-C¶
Travaux pratiques · MP2I · 2021-2022 · C
Cours : Programmation impérative
Introduction¶
Ce TP prend la suite du TP4.5 dans son esprit mais va changer le point de vue. Dans le TP4.5, on a directement manipulé l'écran comme un tableau de pixels, avec ainsi des coordonnées entières. Ici on va considérer un écran logique qui correspond à la partie \([0,1]^2 \subset \mathbb{R}^2\). Contrairement à la convention en mathématiques, l'axe des \(y\) est orienté vers le bas. Voici donc quelques exemples de coordonnées dans ce système, la zone grisée correspondant à la zone du dessin :

L'avantage d'avoir des coordonnées indépendantes de la résolution, c'est qu'elles vont nous permettre de reproduire le dessin en plus ou moins grand selon la taille de la fenêtre.
Mise en place¶
On va procéder comme pour les TP précédents, je vous indique donc les
commandes à taper mais si vous avez compris vous devriez déjà les connaître.
Ouvrez un terminal, assurez-vous d'être dans votre répertoire personnel en
tapant cd si jamais il est déjà ouvert. Vous pouvez aussi créer un
répertoire TP pour placer les TP. Et maintenant :
- récupérez l'archive tp05.zip ;
unzip -d tp05 tp05.zipcd tp05make./tp05
Déjà, si ça se passe mal appelez-moi, mais normalement vous devriez voir une fenêtre avec quatre petites zones qui vont correspondre à quatre tableaux qu'on va vous demander de réaliser. L'objectif est de vous approprier le C, donc utilisez au maximum les variables, les boucles, …
Paramètres de lancement¶
Vous pouvez lancer le programme en tapant juste ./tp05 mais il est aussi
possible de lui fournir de 1 à 3 arguments. Par défaut, il ouvre une fenêtre
de \(800 \times 800\) pixels mais dont l'image affichée est 2 fois plus petite,
et la disposition initiale correspond aux quatre tableaux. Vous pouvez
basculer entre les quatre tableaux et chacun des tableaux en utilisant la
touche Espace.
Il est aussi possible d'appeler le programme ainsi :
./tp05 pixelsoùpixelsest un nombre entier qui va indiquer la résolution de la fenêtre, par défaut c'est 800 ;./tp05 pixels zoomoùzoomest le facteur de grandissement, par défaut c'est 2. Pour avoir un pixel dessiné = un pixel affiché, il faut passer 1. Pluszoomest petit et plus ça va prendre du temps pour afficher en cas d'animations ;./tp05 pixels zoom configoùconfigvaut soit 0 pour quatre tableaux, soitidans 1, 2, 3, 4 pour afficher le tableau correspondant. Par défaut, c'est 0.
Vous pourrez ainsi adapter la commande à lancer en fonction des capacités de vos ordinateurs et de la question à traiter.
Astuce : il est possible de retrouver les commandes précédemment entrées dans le shell à l'aide des touches fléchées haut et bas.
Organisation du code¶
Le code est organisé sur plusieurs fichiers pour la première fois. On a ainsi :
tp05.cqui contient la fonctionmainet se charge de gérer la création de la fenêtre et l'affichage ;primitives.cqui contient les primitives de dessin qu'on va utiliser dans ce TP et qui seront décrites au paragraphe suivant ;reproductions.cqui est le fichier que vous allez modifier et qui contient les quatre fonctions de dessin appelées danstp05.c.
On a également primitives.h et reproductions.h pour permettre de déclarer
les fonctions pouvant être appelées ailleurs.
Primitives¶
Tout d'abord, notons que nous allons travailler avec des coordonnées en
nombres flottants. Pour cela, on ne va pas utiliser le type float qui
correspond à des flottants sur 32 bits mais le type double qui correspond à
des flottants sur 64 bits. Ce sont en fait les nombres flottants utilisés par
le type float dans Python. En C, contrairement à OCaml, on ne fait pas de
différence sur les opérations. Il n'y a donc rien à faire mis à part déclarer
des double. Les fonctions mathématiques (sin, cos, sqrt, ...)
utilisent aussi des double par défaut.
Dans le TP 4.5, on a vu que c'était pénible de passer les couleurs à chaque
fonction avec trois arguments. Ici, on va se servir de la possibilité de
définir ses types en C pour définir un type couleur. Pour le moment, vous
n'avez pas besoin de savoir comment on fait. Tout ce que vous avez besoin de
savoir c'est :
- qu'on déclare une variable de ce type en écrivant juste
couleur c;; - qu'il y a une fonction
couleur rgb(unsigned int r, unsigned int g, unsigned int b);qui permet de créer une couleur. On peut donc écrirecouleur rouge = rgb(255, 0, 0);; - qu'on peut aussi directement faire un appel à
rgbdans un appel de fonction. Ainsi on peut écrireligne(0, 0, 1, 1, rgb(255, 0, 0));ouligne(0, 0, 1, 1, rouge);si on définit la couleur dans une variable. L'avantage étant d'éviter de se répéter et de donner un nom signifiant aux couleurs.
Pour dessiner, vous disposez des fonctions :
void ligne(double x1, double y1, double x2, double y2, couleur c);qui trace une ligne de couleurcentre les points(x1,y1)et(x2,y2);
void cercle(double x, double y, double r, couleur c);qui trace un cercle de couleurc, de centre(x,y)et de rayonr. Ici le rayon correspond aux dimensions dans \([0,1]\). Ainsi, pour faire un cercle inscrit dans le carré du dessin, il devra être de rayon 0.5 et on écriracercle(0.5, 0.5, 0.5, rouge);;
void cercle_plein(double x, double y, double r, couleur c);commecerclemais on remplit l'intérieur ;void remplit(double x, double y, couleur c);qui s'explique assez facilement avec l'outil que vous avez dû utiliser dans un logiciel de dessin : le pot de peinture. On part du pixel situé en(x,y)et on peint tout autour de la couleurcjusqu'à rencontrer une couleur différente de la couleur initiale de(x,y). Un exemple vous est fourni danstableau1;couleur melange(double t, couleur c1, couleur c2);icitest dans \([0,1]\) et va permettre de faire un mélange entre les deux couleurs. Sitvaut 0 on renvoiec1, sitvaut 1 on renvoiec2et pour les autres valeurs on fait une interpolation linéaire, c'est-à-dire un mélange entre1-tdec1ettdec2. Ça va permettre de faire des effets comme des dégradés ;double delta();: on a vu qu'on allait dessiner dans un espace indépendant de la résolution mais si on veut faire des lignes qui se touchent, il faudrait connaître la taille d'un pixel dans ces coordonnées. C'est exactement ce que renvoie cette fonction : la valeur \(\delta\) qui correspond à un pixel sur l'écran.
Exemples¶
Le fichier reproductions.c a déjà des programmes écrits pour vous permettre
de comprendre le fonctionnement des fonctions précédentes.
Note de style¶
Dans la suite, on va vous demander de reproduire des tableaux avec des programmes. L'objectif n'est pas de faire douze mille lignes idiotes mais de trouver une logique. Parfois en utilisant des boucles, des sous-fonctions, des tableaux pour ne pas se répéter. Il y aura donc une note de style en lisant votre code.
Tableau 1 - Piet Mondrian¶

Question 1
Reproduire ce tableau dans la fonction tableau1.
Tableau 2 - Victor Vasarely¶

Question 2
Reproduire ce tableau dans la fonction tableau2.
Tableau 3 - Vassily Kandinsky¶

Question 3
Reproduire ce tableau dans la fonction tableau3.
Animation¶
Vous avez pu voir que chaque fonction tableaui prend un paramètre time.
Celui-ci est un nombre flottant dans \([0,1]\) qui va de 0 à 1 en une minute
puis reprend la valeur 0. Vous pouvez vous en servir pour changer votre
tableau en fonction du temps en calibrant l'animation sur une minute. On
pourra utiliser les fonctions de math.h comme sin, cos, …
Par exemple, il suffit de considérer \(\theta = 2\pi \frac{60\, time}{N}\) pour parcourir \([2k\pi, 2(k+1)\pi]\) en exactement \(N\) secondes. Il suffit alors de calculer \(\cos(\theta), \sin(\theta)\) pour avoir un point qui tourne autour d'un cercle en \(N\) secondes.
Question 4
Choisissez un des tableaux précédents et animez-le.
Tableau 4 : Vous¶
Question 5
Voilà, maintenant vous êtes libres de faire votre propre tableau dans la
fonction tableau4, et celui-ci devra être animé. Je vous ai mis un
exemple, il n'a aucune raison de vous servir de base. Vous pouvez le
supprimer ou le déplacer.