Un coucher de soleil à la Seyne-sur-Mer

Art

Dans ce premier projet de première spécialité NSI, intitulé Art génératif, nous allons expliquer comment nous avons réalisé un programme représentant un coucher de soleil inspiré des paysages de La Seyne-sur-Mer, avec les célèbres rochers « Les Deux Frères ». Ce projet nous a permis d’explorer différents concepts de programmation en Python, en utilisant notamment les modules turtle et random pour donner un paysage le plus réaliste possible.

Origines de la Seyne-sur-Mer

La Seyne-sur-Mer est une commune française située dans le département du Var, en région Provence-Alpes-Côte d’Azur. Elle compte environ 65 000 habitants, ce qui en fait la deuxième ville la plus peuplée du Var, après Toulon.

Parmi ses nombreuses zones touristiques, on trouve les « Deux Frères », nom donné à deux rochers emblématiques de la côte maritime, émergeant à la pointe du Cap Sicié et visibles depuis les plages. Le nom « Deux Frères » provient d’une légende locale.

Le Projet

Pour réaliser ce projet, nous avons décidé de créer un paysage inspiré des couchers de soleil de La Seyne-sur-Mer. L’objectif était d’utiliser le plus de concepts vus en classe, tels que les modules Turtle et Random, ainsi que l’utilisation de boucles. De plus, pour donner un effet plus naturel, la position et la taille des nuages et des étoiles sont générées de façon aléatoire.

Structure du script

Notre script est divisé en plusieurs parties, chacune ayant une fonction distincte représentant un élément du paysage (dégradé, soleil, étoiles, nuages et les Deux Frères). Ces fonctions sont appelées à la fin dans un ordre spécifique pour créer l’image finale.

Analyse du script

L’analyse du script se déroule en plusieurs étapes.

1. Tout d’abord, nous importons les modules nécessaires, notamment le module Turtle pour le dessin graphique et le module Random pour générer des valeurs aléatoires.

from turtle import *
from random import randint

2. Fonction dégradé de couleur

# Fonction dégradé de couleur
def degrade(couleur_debut, couleur_fin, etapes, decalage_y, effet_vague=False):
    r_diff = couleur_fin[0] - couleur_debut[0]
    g_diff = couleur_fin[1] - couleur_debut[1]
    b_diff = couleur_fin[2] - couleur_debut[2]
    penup()
    goto(-640, decalage_y)
    pendown()

Cette fonction degrade prend quatre arguments : couleur_debutcouleur_finetapes, et decalage_y. Elle calcule la différence entre les valeurs RGB des couleurs de début et de fin, ce qui est nécessaire pour créer un dégradé. Ensuite, elle utilise penup() pour lever le stylo afin de ne pas dessiner pendant le déplacement, et goto() pour se positionner sur l’écran. pendown() est ensuite utilisé pour recommencer à dessiner. Cette partie est essentielle pour établir la base du dégradé.

3. Boucle pour réaliser le dégradé

    for i in range(etapes):
        if effet_vague:
            # Effet  vague si activé
            valeur_vague = int(30 * (1 + (i % 20) / 20.0))
            couleur_actuelle = (
                int(couleur_debut[0] + (r_diff * i / etapes)),
                int(couleur_debut[1] + (g_diff * i / etapes)),
                int(couleur_debut[2] + (b_diff * i / etapes + valeur_vague)),
            )
        else:
            # Couleur effet de vague desactivé 
            couleur_actuelle = (
                int(couleur_debut[0] + (r_diff * i / etapes)),
                int(couleur_debut[1] + (g_diff * i / etapes)),
                int(couleur_debut[2] + (b_diff * i / etapes)),
            )

Cette partie de la fonction utilise une boucle pour parcourir le nombre d’étapes spécifié. Dans la première branche de la condition if, si effet_vague est activé, un effet de vague est appliqué à la couleur actuelle en ajoutant une variation à la composante bleue. La couleur actuelle est ensuite calculée en ajoutant une autre couleur à celle de départ.

Dans le bloc else, qui s’exécute lorsque l’effet de vague est désactivé, la couleur actuelle est calculée sans cet effet.

4. La limite des valeurs pour les couleurs

        # Limite des couleurs (valeur compris entre 0 et 255) 
        couleur_actuelle = (
            min(255, max(0, couleur_actuelle[0])),
            min(255, max(0, couleur_actuelle[1])),
            min(255, max(0, couleur_actuelle[2])),
        )

Cette partie du script assure que les valeurs RGB de couleur_actuelle restent comprises entre 0 et 255, comme le montre l’utilisation de min et max. Cela permet de générer des couleurs valides.

5. Les lignes du dégradé

        pencolor(couleur_actuelle)
        forward(1280)
        goto(-640, decalage_y - (360 / etapes) * (i + 1))

Ici, la couleur du stylo est définie sur couleur_actuelle avec pencolor(couleur_actuelle). Ensuite, le curseur Turtle se déplace en avant sur 1280 pixels (forward(1280)), puis se repositionne pour dessiner la prochaine ligne du dégradé en fonction de l’étape actuelle.

6. Le soleil

# Fonction pour réaliser  le soleil
def soleil(position, rayon, couleur):
    penup()
    goto(position[0], position[1] - rayon)
    pendown()
    pencolor(couleur)
    fillcolor(couleur)
    begin_fill()
    setheading(90)
    circle(rayon, 180)
    end_fill()

Il n’y a pas de coucher de soleil sans le soleil. Nous avons donc créé la fonction soleil, qui dessine un demi-cercle à une position donnée et le remplit d’une couleur spécifiée.

7. Les étoiles

# Fonction pour réaliser  des étoiles dans le ciel disposer aléatoirement 
def etoiles():
    pensize(1)
    for _ in range(125):
        penup()
        x, y = randint(-700, 700), randint(0, 700)
        goto(x, y)
        pendown()
        couleur_etoile = (randint(230, 255), randint(230, 255), randint(230, 255))
        pencolor(couleur_etoile)
        dot(randint(1, 2))

Pour réaliser les étoiles, nous les avons disposées de façon aléatoire dans la partie supérieure, représentant le ciel. Nous avons également varié leur taille de manière aléatoire entre 1 et 2, afin d’ajouter un effet plus naturel au dessin. Ce processus pour les étoiles est réalisé 125 fois (for _ in range(125):)

8. Les nuages

# Fonction pour dessiner des nuages 
def nuages():
    penup()
    pencolor((200, 200, 200))  # Gris pastel
    for _ in range(15):
        x, y = randint(-600, 600), randint(100, 300)
        for _ in range(randint(5, 10)):
            offset_x = x + randint(-30, 30)
            offset_y = y + randint(-10, 10)
            goto(offset_x, offset_y)
            pendown()
            dot(randint(30, 60))
            penup()
            nouvelle_ombre = randint(190, 220)
            pencolor((nouvelle_ombre, nouvelle_ombre, nouvelle_ombre))
            for _ in range(randint(5, 10)):
                sous_offset_x = offset_x + randint(-20, 20)
                sous_offset_y = offset_y + randint(-10, 10)
                goto(sous_offset_x, sous_offset_y)
                pendown()
                dot(randint(10, 20))
                penup()

Pour réaliser les nuages, nous nous sommes inspirés d’une technique de dessin apprise en cours d’arts plastiques, consistant à dessiner plusieurs petits ronds et à les remplir avec trois nuances de gris différents. Les nuages sont disposés aléatoirement dans le ciel, avec des nuances de gris pastel, afin de rester cohérents avec le reste des couleurs du dégradé. Ils sont représentés par plusieurs points (dots) positionnés légèrement décalés pour créer une texture.

9. « Les Deux Frères »

# Fonction pour dessiner les "Deux Frères"
def les_deux_freres():
    penup()
    goto(200, 0)  # Position initiale pour les Deux Frères

    # Petit triangle à gauche
    fillcolor((140, 130, 120))
    begin_fill()
    pendown()
    setheading(60)
    forward(40)
    right(120)
    forward(40)
    right(120)
    forward(40)
    end_fill()
    penup()

    # Premier grand rocher
    goto(230, 0)
    fillcolor((120, 110, 100))
    begin_fill()
    pendown()
    setheading(60)
    forward(110)
    right(120)
    forward(110)
    right(120)
    forward(110)
    end_fill()
    penup()

    # Deuxième grand rocher 
    goto(310, 0)
    fillcolor((100, 90, 80))
    begin_fill()
    pendown()
    setheading(60)
    forward(120)
    right(120)
    forward(120)
    right(120)
    forward(120)
    end_fill()

Pour dessiner les Deux Frères, nous avons utilisé des triangles, représentant de manière stylisée les rochers. La couleur choisie est un gris sombre pour les rochers, afin de contraster avec le ciel. La position et l’orientation sont ajustées pour bien les intégrer dans le paysage.

10. Configuration de la fenêtre

# Configuration de la fenêtre Turtle
setup(1280, 720, 0, 0)
colormode(255)
speed(0)

Dans cette étapes du code nous délimitons la fenêtre afin d’avoir tous les éléments du décor dans la fenêtre afin de tous les apercevoir.

11. Execution des fonctions

# Création du coucher de soleil (océan + ciel)
degrade((0, 0, 255), (255, 255, 102), 720, 360)
degrade((255, 255, 102), (0, 0, 255), 720, 0, effet_vague=True)

# Dessin du soleil, des étoiles, des nuages et des îlots des Deux Frères
soleil((100, 100), 100, (255, 255, 102))
etoiles()
nuages()
les_deux_freres()
done()

Ici nous faisons appelle à tout les fonctions afin de réaliser le dessin.

Les difficultés rencontrées

Lors des nombreux tests réalisés, nous avons rencontré plusieurs difficultés, notamment avec les valeurs RGB et les fonctions dégradé et nuages, en raison de la complexité de leur création et des formules de calcul utilisées.

Source

Pour mener à bien ce projet, nous avons eu recours à nos connaissances personnelles ainsi qu’à Internet. Nous avons utilisé des sites comme NumWorks.com et Python.org pour apprendre de nouvelles choses, et nsi.xyz pour consulter les anciens projets afin de comprendre les attentes.

Télécharger le .py

L’image finale

Après beaucoup de tests et d’ajustements, voici le rendu final de notre projet que vous trouverez ci-dessous, résultat de tout le travail que nous y avons investi.