Skip to content

Kaléidoscope

Énoncé

On se propose dans ce TP de travailler sur un générateur d'images SVG. On souhaite générer des images kaléidoscopiques comme celle ci-dessous.

exemple

On vous fournit le fichier principal du programme kaleidoscope.py et on vous demande d'écrire deux modules : dessin.py et triangle.py

Prenez le temps pour bien comprendre le programme principal fourni. En particulier, on vous demande de bien identifier les fonctions qui devront être implémentées dans les différents modules. Pour chacune des fonctions, veillez à bien comprendre les paramètres ainsi qu'à identifier ce qu'elle retourne.

Pour dessiner un triangle au format SVG, on se référera à la documentation en ligne : http://www.w3schools.com/graphics/svg_polygon.asp. Rajoutez donc une fonction pour générer des polygones à votre module svg.py :

1
2
3
4
5
6
7
8
def genere_polygone(points):
    """
    Retourne la chaîne de caractères correspondant à un élément SVG
    représentant un polygone. `points` est un tableau de points qui
    sont eux mêmes des tuples de deux nombres.
    """
    # TODO
    ...

Vous aurez également besoin de dessiner des triangles transparents. Pour cela, vous rajouterez la fonction suivante à votre module svg.py. Vous vous renseignerez auprès de votre moteur de recherche préféré pour trouver comment faire de la transparence en SVG.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def genere_balise_debut_groupe_transp(niveau_opacite):
    """
    Retourne la chaîne de caractères correspondant à une balise ouvrant un
    groupe d'éléments qui, dans son ensemble, sera partiellement transparent.
    Les éléments qui composent le groupe se masquent les uns les autres dans
    l'ordre d'apparition (ils ne sont pas transparents entre eux).
    `niveau_opacite` doit être un nombre entre 0 et 1. Ce groupe doit être
    refermé de la même manière que les groupes définissant un style.
    """
    # TODO
    ...

Pour effectuer la rotation d'angle α d’un point de coordonnées (x, y) autour d'un centre de rotation de coordonnées (xc, yc), plusieurs approches sont possibles. Si cette partie ne vous inspire pas, vous pouvez toujours utiliser la formule suivante :

x′ = (x - xc) × cos(α) - (y - yc) × sin(α) + xc

y′ = (x - xc) × sin(α) + (y - yc) × cos(α) + yc

Correction

Cliquez ici pour révéler la correction.

Voici le code d'une correction possible.

Fonction dans le module svg.py pour générer un polygone :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def genere_polygone(points):
    """
    Retourne la chaîne de caractères correspondant à un élément SVG
    représentant un polygone. `points` est un tableau de points qui
    sont eux mêmes des tuples de deux nombres.
    """
    coordonnees_points = ""
    for point in points:
        coordonnees_points += f"{point[0]}, {point[1]} "
    return f'<polygon points="{coordonnees_points}" />'

Fonction dans le module svg.py pour générer le début d'un groupe transparent :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def genere_balise_debut_groupe_transp(niveau_opacite):
    """
    Retourne la chaîne de caractères correspondant à une balise ouvrant un
    groupe d'éléments qui, dans son ensemble, sera partiellement transparent.
    Les éléments qui composent le groupe se masquent les uns les autres dans
    l'ordre d'apparition (ils ne sont pas transparents entre eux).
    `niveau_opacite` doit être un nombre entre 0 et 1. Ce groupe doit être
    refermé de la même manière que les groupes définissant un style.
    """
    return f'<g opacity="{niveau_opacite}">'

Fichier triangle.py :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""
Module pour manipuler des triangles.

Le module doit implémenter :

- une fonction triangle_aleatoire
- une fonction tourne_triangle_autour
"""
from random import randint
from math import cos, sin


def tourne_point(point, centre, angle):
    """Tourne le point donné"""
    x_tourne = (
        (point[0] - centre[0]) * cos(angle)
        - (point[1] - centre[1]) * sin(angle)
        + centre[0]
    )
    y_tourne = (
        (point[0] - centre[0]) * sin(angle)
        + (point[1] - centre[1]) * cos(angle)
        + centre[1]
    )
    return (x_tourne, y_tourne)


def tourne_triangle_autour(triangle, centre, angle):
    """Renvoie un nouveau triangle représentant le triangle donné tourné.

    Le triangle renvoyé est un tuple de taille 3 contenant des tuples de taille 2
    représentant chacun des points du triangle.
    """
    p1_tourne = tourne_point(triangle[0], centre, angle)
    p2_tourne = tourne_point(triangle[1], centre, angle)
    p3_tourne = tourne_point(triangle[2], centre, angle)
    return (p1_tourne, p2_tourne, p3_tourne)


def point_aleatoire(intervalle_x, intervalle_y):
    """Renvoie un nouveau point aléatoire dans les intervalles donnés"""
    return (
        randint(intervalle_x[0], intervalle_x[1]),
        randint(intervalle_y[0], intervalle_y[1]),
    )


def triangle_aleatoire(intervalle_x, intervalle_y):
    """Renvoie un nouveau triangle aléatoire dans le rectangle spécifié par les intervalles.

    Prend deux intervalles (chacun un couple de coordonnées) pour chaque dimension.
    Le triangle renvoyé est un tuple de taille 3 contenant des tuples de taille 2
    représentant chacun des points du triangle.
    """
    return (
        point_aleatoire(intervalle_x, intervalle_y),
        point_aleatoire(intervalle_x, intervalle_y),
        point_aleatoire(intervalle_x, intervalle_y),
    )

Fichier dessin.py :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"""Quelques fonctions utiles pour générer du SVG.

    - affiche_triangle
    - couleur_aleatoire
"""
from random import choice
import svg


def affiche_triangle(triangle, couleur):
    """Affiche le triangle donné, de la couleur donnée sur la sortie standard.

    Affichage avec une opacité de 0,5 (semi-transparent)
    """
    # Remarque : pour que les triangles soient transparents les uns
    # par rapport aux autres, chacun doit être dans son propre groupe
    # transparent.
    print(svg.genere_balise_debut_groupe_transp(0.5))
    print(svg.genere_balise_debut_groupe("none", couleur, 0))
    print(svg.genere_polygone((triangle[0], triangle[1], triangle[2])))
    print(svg.genere_balise_fin_groupe())
    print(svg.genere_balise_fin_groupe())


def couleur_aleatoire():
    """Renvoie une couleur svg aleatoire."""
    return choice(["red", "green", "blue", "orange", "yellow"])

Exercices