---
exports:
- format: pdf
  output: TD.pdf
  template: ../../template/TD
- format: tex
  output: TDmd.tex
  template: ../../template/TD
jupytext:
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
kernelspec:
  display_name: C++17
  language: C++17
  name: xcpp17
---

# TD 10 : compilation séparée, graphiques

+++ {"nbgrader": {"grade": true, "locked": false, "points": 0, "grade_id": "10", "schema_version": 3, "solution": true}}

{raw:latex}`\enlargethispage{.5cm}`

::::{admonition} Exercice 1 : Compilation séparée

Annotez les quatre fichiers suivants en leurs attribuant leurs noms
respectifs parmi `factorielle-test.cpp`, `factorielle.cpp`,
`factorielle-exemple.cpp` et `factorielle.hpp`, en précisant leurs
rôles respectifs et en indiquant où se trouvent entête, définition,
documentation, tests et utilisation de la fonction `factorielle`.

:::{literalinclude} factorielle.hpp
:::

:::{literalinclude} factorielle.cpp
:::

:::{literalinclude} factorielle-test.cpp
:::

{raw:latex}`\clearpage`

:::{literalinclude} factorielle-exemple.cpp
:::

::::

/// BEGIN SOLUTION

Ensemble, ces quatre fichiers forment une bibliothèque, qui implante
une fonction factorielle, ainsi que des tests unitaires et un exemple
d'utilisation. Le premier fichier, `factorielle.hpp`, est le fichier
d'entête : il contient la déclaration (l'entête) de la fonction
factorielle, avec sa documentation. Ce fichier permet de pouvoir
compiler des programmes qui utilisent la fonction factorielle, même
sans avoir le code de la fonction factorielle. Pour cela il faut avoir
mis la ligne `#include "factorielle.hpp"` en début de programme. Le
second fichier, `factorielle.cpp`, contient la définition (le code) de
la fonction factorielle. Le suivant, `factorielle-test.cpp`, contient
les tests de la fonction factorielle, ainsi qu'un programme qui lance
ces tests. Enfin le dernier, `factorielle-exemple.cpp`, donne un
exemple de programme utilisant la fonction factorielle.

/// END SOLUTION

## Graphiques

En TP, nous utiliserons la bibliothèque `SFML` [^1], une bibliothèque
largement utilisée facilitant le développement de jeux ou
d'applications multimédias grâce à une grande panoplie de modules
(fenêtrage, graphismes, audio, réseau, ...), principalement développée
par Laurent Gomila. Nous allons nous en servir pour créer une fenêtre
et dessiner dedans.

La `SFML` n'étant pas immédiatement intuitive à utiliser, nous avons
écrit une micro bibliothèque composée de quelques primitives pour vous
simplifier les premiers pas. Cette bibliothèque, documentée dans
`primitives.hpp`, a vocation à être la plus transparente possible. À
vous de la lire en détail pour vous l'approprier et, par la suite,
vous en passer.

Voici un exemple de programme utilisant la `SFML` et notre
bibliothèque `primitives` :

:::{literalinclude} exemple-graphisme1.cpp
:::

Notez dans cet exemple le nouveau type `RenderWindow` représentant une
fenêtre et les fonctions `clear` pour effacer la fenêtre, `sleep` pour
attendre un temps donné et `draw_point` (qui vient de
`primitives.cpp`) pour dessiner un point.

+++ {"nbgrader": {"grade": true, "locked": false, "points": 0, "grade_id": "20", "schema_version": 3, "solution": true}}

::::{admonition} Exercice 2 : Premiers dessins

En vous inspirant de l'exemple fourni, écrivez des instructions
(fragments de programme) qui, respectivement,

1.  dessinent un point noir (*Black*) de coordonnées $(209, 71)$;

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION point
    :end-before: ND SOLUTION point
    :::
    /// END SOLUTION

2.  dessinent un segment blanc (*White*) reliant les
    points $(50, 100)$ et $(100, 100)$;

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION segment horizontal
    :end-before: ND SOLUTION segment horizontal
    :::
    /// END SOLUTION

3.  dessinent un segment rouge (*Red*) reliant les points $(100, 150)$ et
    $(100, 200)$;

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION segment vertical
    :end-before: ND SOLUTION segment vertical
    :::
    /// END SOLUTION

4.  dessinent le rectangle horizontal vide de contour rouge dont les sommets diagonaux
    sont $(100, 100)$ et $(200, 150)$;

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION rectangle rouge
    :end-before: ND SOLUTION rectangle rouge
    :::
    /// END SOLUTION

5.  dessinent un rectangle horizontal plein noir dont les sommets
    diagonaux sont $(200, 75)$ et $(250, 100)$;

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION rectangle noir
    :end-before: ND SOLUTION rectangle noir
    :::
    /// END SOLUTION

6.  dessinent un segment rouge reliant les points $(200, 150)$ et
    $(250, 200)$;

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION diagonale
    :end-before: ND SOLUTION diagonale
    :::
    /// END SOLUTION

7.  dessinent un cercle noir de centre $(207, 72)$ et de rayon
    $5$;  
    **Indication :** Utiliser les fonctions `cos` et `sin`.

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION cercle
    :end-before: ND SOLUTION cercle
    :::
    /// END SOLUTION

8.  dessinent un disque jaune (*Yellow*) de centre $(275, 37)$ et de rayon
    $25$;  
    **Indication :** Utiliser la définition d'un disque.

    /// BEGIN SOLUTION
    :::{literalinclude} premier-dessin.cpp
    :start-after: GIN SOLUTION disque
    :end-before: ND SOLUTION disque
    :::
    /// END SOLUTION

::::

+++ {"nbgrader": {"grade": true, "locked": false, "points": 0, "grade_id": "30", "schema_version": 3, "solution": true}}

::::{admonition} Exercice 3 : $\clubsuit$ Fonctions de dessin

Notre bibliothèque `primitives` contient entre autres les fonctions
suivantes :

    /** Affiche une ligne de couleur entre deux positions données
     * @param w une fenêtre ouverte dans laquelle dessiner
     * @param pos1 les coordonnées du premier point de la ligne
     * @param pos1 les coordonnées du dernier point de la ligne
     * @param color la couleur de la ligne
     */
    void draw_line (RenderWindow& w, Point pos1, Point pos2, Color color);

    /** Affiche un cercle coloré vide
     * @param w une fenêtre ouverte dans laquelle dessiner
     * @param center la position du centre du cercle
     * @param r le rayon du cercle
     * @param color la couleur du trait
     */
    void draw_circle (RenderWindow& w, Point center, int r, Color color);

    /** Affiche un cercle coloré plein 
     * @param w une fenêtre ouverte dans laquelle dessiner
     * @param center la position du centre du cercle
     * @param r le rayon du cercle
     * @param color la couleur du trait et du remplissage
     */
    void draw_filled_circle(RenderWindow& w, Point center, int r, Color color);

À noter qu'elles prennent la fenêtre où dessiner comme premier
paramètre (`w`). Le symbole `&` indique que cette fenêtre est passée
par référence afin que les fonctions puissent la modifier. Vous pouvez
essentiellement ignorer ce détail technique dont vous verrez les
tenants et les aboutissants au deuxième semestre.

Notez aussi les variables de type `Point`. Ces dernières représentent
des coordonnées. On peut créer un point et accéder à ses coordonnées
comme suit :

```
Point p = {42, 2713};
int x = p.x; // 42
int y = p.y; // 2713
```

Techniquement parlant, il s'agit d'un *enregistrement* (*struct* en
anglais); vous en verrez les détails au deuxième semestre.

Dans notre bibliothèque, ces fonctions sont implémentées via des
appels directs à des fonctions de la `SFML`. Par exemple :

:::{literalinclude} primitives.cpp
:start-after: BEGIN draw_filled_circle
:end-before: END draw_filled_circle
:::

1.  Réimplantez ces fonctions, en n'utilisant que des
    appels à `draw_point`.

    /// BEGIN SOLUTION
    :::{literalinclude} cercle-correction.cpp
    :start-after: BEGIN cercle
    :end-before: END cercle
    :::
    
    :::{literalinclude} disque-correction.cpp
    :start-after: BEGIN disque
    :end-before: END disque
    :::
    
    :::{literalinclude} segment-correction.cpp
    :start-after: BEGIN segment
    :end-before: END segment
    :::
    /// END SOLUTION

::::

{raw:latex}`\clearpage`


+++ {"nbgrader": {"grade": true, "locked": false, "points": 0, "grade_id": "40", "schema_version": 3, "solution": true}}

::::{admonition} Exercice 4 : Souris et clavier

Voici maintenant un fragment de programme interactif utilisant la
bibliothèque `SFML` via notre bibliothèque `primitives` pour réagir à
des actions avec la souris ou le clavier :

:::{literalinclude} exemple-graphisme2.cpp
:start-after: BEGIN
:end-before: END
:::

1.  En vous inspirant du programme précédent, écrivez un programme qui
    attend que l'utilisateur clique sur deux points de l'écran puis
    qui trace le segment les reliant.

    /// BEGIN SOLUTION
    :::{literalinclude} souris-et-clavier-1-correction.cpp
    :start-after: BEGIN souris_clavier1
    :end-before: END souris_clavier1
    :::
    /// END SOLUTION

2.  Écrivez un programme qui attend que l'utilisateur clique sur
    quatre points puis qui dessine le quadrilatère ayant ces quatre
    points comme sommets.

    /// BEGIN SOLUTION
    :::{literalinclude} souris-et-clavier-2-correction.cpp
    :start-after: BEGIN souris_clavier2
    :end-before: END souris_clavier2
    :::
    /// END SOLUTION

3.  Écrivez un programme qui dessine des polygones de la façon
    suivante : l'utilisateur clique sur des points successifs. À
    chaque clic, le programme relie les deux derniers points. Si
    l'utilisateur clique près du point initial, le polygone se ferme,
    et le programme commence un nouveau polygone.
 
    /// BEGIN SOLUTION
    :::{literalinclude} souris-et-clavier-3-correction.cpp
    :start-after: BEGIN souris_clavier3
    :end-before: END souris_clavier3
    :::
    /// END SOLUTION

::::

[^1]: <https://www.sfml-dev.org>
