Étiquette : turtle

Art

Paysage : Le coucher de soleil en Python

Pour notre premier projet de NSI, qui a pour sujet l’art génératif, nous avons décidé de créer une image d’un coucher de soleil en bord de mer, en essayant de capitaliser un maximum sur l’ambiance générale de l’image, pour la rendre intéressante et détaillée. Cet article va vous présenter point par point le processus de création de ce projet. Bonne lecture !

La vidéo de présentation du projet :

Les autres pistes du projet

De nombreuses pistes ont été explorées quant à quoi faire comme projet de NSI. Il nous fallait trouver quelque chose de complexe, mais pas infaisable, ainsi que parlant et pas complètement hors sujet. 

Nous d’abord pensé à faire une ville futuriste, tirée du jeu vidéo Cyberpunk 2077, mais l’idée a été abandonnée de peur de ressembler au Paysage Synthwave. Puis nous nous sommes tournés vers la musique et à des albums tels que In Rainbows de Radiohead, In Absentia de Porcupine Tree, ou encore Ænima de TOOL, mais ces possibilités ont été rejetées de peur de ne pas être à la hauteur de l’œuvre originale.

Alors, nous nous sommes aventurés dans les anciens projets d’élèves avant de tomber sur l’idée d’un paysage et enfin de la mer, car c’est un environnement qui évoque à la fois de la nostalgie et de la joie  et qui parlera donc au plus grand nombre, mais qui représente également un certain challenge à représenter et donc, l’idée idéale.

Déroulement du projet

Ce projet a été conçu sur les deux semaines des vacances de la Toussaint 2024, avec les 3/4 du temps entièrement consacré au code et l’image, et les quelques derniers jours à la réalisation de cet article, ainsi que de la vidéo. Nous avons utilisé des IDE tels que Thonny et VS Code, ainsi que de l’outil en ligne Replit, afin de partager notre code, et tester nos fonctions.

Les étapes de création de notre image

Afin d’avoir une meilleure idée des couches et des objets dont notre image allait avoir besoin, nous avons commencé ce projet par un brouillon. Et bien que l’image finale ne ressemble en rien à ce qui était prévu, cela nous a quand même permis de commencer notre code et d’en construire la structure et les fonctions par la suite.

Une des premières choses que nous avons faite est une fonction essentielle de notre code, nommée go() et qui permet à la turtle de se « téléporter » sans laisser de trace, ce qui s’avèrera très utile pour la lisibilité du code, en plus d’économiser des lignes.

def go(x, y) :
    penup()
    goto(x, y)
    pendown()

Le Ciel

Après cela nous avons créé notre fonction ciel(), sûrement une des plus complexes du code, qui se compose de trois boucles. La première créée un fond ayant un dégradé de couleurs rappelant un ciel lors d’un coucher de soleil. Ici, il a été difficile de trouver une bonne manière de faire un dégradé qui prenne bien en compte nos deux couleurs, et beaucoup d’essai ont été nécessaires pour trouver une bonne formule.

Ensuite, la seconde fait apparaitre des étoiles avec le module random. Enfin, ainsi que des raies de couleur. L’utilisation de la fonction randint() du module random permet de faire en sorte que les étoiles sont à des positions quasiment toujours différentes.

Enfin, la dernière boucle a été trouvée de manière complètement accidentelle. En faisant des recherches pour la formule de la première boucle, nous nous sommes rendu compte qu’espacer l’ordonnée du retour « à la ligne », à la ligne 15, permettait des stries dans le ciel, ce qui constitue au final un détail important de notre image.

def ciel(col1, col2, larg, long) :

    colormode(255)
    h = -long / 2 + long // 6
    go(-larg / 2, h)

    for i in range(long) :

        r = col1[0] + (col2[0] - col1[0]) * i / long 
        g = col1[1] + (col2[1] - col1[1]) * i / long
        b = col1[2] + (col2[2] - col1[2]) * i / long

        pencolor(int(r), int(g), int(b))
        forward(larg)
        go(-larg / 2, h+i)

    for i in range(300) :

        x = randint(-640, 640)
        y = randint(-360, 360)
        taille = randint(1, 4)

        c = randint(200, 240)
        color(c,c,c)

        go(x, y)
        dot(taille)

    for i in range(long) :

        r = col1[0] + (col2[0] - col1[0]) * i / long
        g = col1[1] + (col2[1] - col1[1]) * i / long
        b = col1[2] + (col2[2] - col1[2]) * i / long

        pencolor(int(r), int(g), int(b))
        forward(larg)
        go(-larg / 2, h+i*10)


Le résultat de cette fonction est le suivant :

La Mer

La fonction de la mer est plus ou moins la même que celle du ciel, mais avec des valeurs différentes, retournant le dégradé, et le plaçant bien plus bas.

def mer(col1, col2, larg, long) :

    h = -270
    go(-larg / 2, h)

    for i in range(long) :

        r = col1[0] + (col2[0] - col1[0]) * i / long
        g = col1[1] + (col2[1] - col1[1]) * i / long
        b = col1[2] + (col2[2] - col1[2]) * i / long

        pencolor(int(r), int(g), int(b))
        forward(larg)
        go(-larg / 2, h+i)


On obtient alors ce dégradé, bien plus comprimé que le précédent, mais dont la partie inférieure est principalement cachée par les reliefs.

Le Soleil

Le Soleil a sûrement été la fonction la plus bizarre à créer de ce projet. En effet, bien qu’elle soit assez courte, trouver la bonne formule pour les couleurs des anneaux a demandé beaucoup d’essai sans trop savoir où aller, comme pour le ciel et son dégradé de couleur.

C’est après avoir créé un cercle central qu’elle change les couleurs et repart d’un point plus bas pour tracer un cercle plus grand, toujours de la même valeur (i*10) et que nous avons simplifié sous la forme d’une variable t, pour des questions de lisibilité.

def soleil(x, col) : 

    go(0, -250)
    color(col)
    begin_fill()
    circle(x)
    end_fill()

    for i in range(5) :

        t = i * 10

        r = max(col[0] - t, 0)
        g = max(col[1] - t * 3, 0)
        b = 100 - t * 2

        color(r, g, b)
        width(12)
        go(0, -250 - t)
        circle(x + t)

Nous avons aussi rajouté des effets sur la mer qui représente les reflets du soleil. Pour cela nous avons utilisé une boucle ainsi qu’une structure conditionnelle, dans une nouvelle fonction, appelée reflets(), qui est assez simple et qui sera par ailleurs réutilisée plus tard pour les reflets du bateau :

def reflets(x, y, larg, col, taille, n) :

    setheading(0)

    for i in range(n) :
        if n==7 :
            pencolor(col)
            pensize(taille)
            go(x - larg // 2, y - i * 20)
            forward(larg)
            larg -= 50 * i / 2
            taille -= 2
        else : 
            pencolor(col)
            pensize(taille)
            go(x - larg // 2, y - i * 8)
            forward(larg)
            larg -= 50 * i / 2
            taille-=1


On obtient alors ce résultat, de notre soleil sans mer en dessous :

La Plage

Pour faire la plage nous avons créé une fonction nommée plage où nous y avons créé une autre fonction nommée arrière_plan. La fonction fait se téléporter la tortue grâce à la fonction go() à des coordonnées qui sont contenues dans une liste, qui fut très laborieuse à faire (comme celles à venir). Ensuite, grâce aux fonctions begin_fill() et end_fill(), la forme créée est remplie d’une couleur contenue dans les structures conditionnelles.

def plage(x, y) :

    def arrière_plan(x, y) :

        go(x, y)
        color(40, 25, 25)

        points = [(x, y + 190),(x + 200, y + 150), (x + 250, y + 125), (x + 500, y + 100), (x + 642, y + 100), (x + 800, y + 80), (x + 1280, y+ 130), (x + 1280, y)]

        begin_fill()
        for x, y in points:
            go(x, y)
        end_fill()


    arrière_plan(x, y+75)

    go(x, y)
    begin_fill()

    for i in range(60) :

        pensize(10)
        color(28, 22, 19)
        forward(1280)
        y += 2
        go(x, y)

Les Reliefs

Pour créer cet effet de profondeur sur la plage nous avons utilisé une fonction utilisant le même principe que la fonction plage(). Le code reste très proche de l’autre fonction avec quelques différences. Par exemple, le paramètre n permet de choisir quelles listes, couleur et coordonnées le code choisi, afin de ne pas avoir à recréer des fonctions inutilement. Puis, le code parcours chaque point dans l’ordre et remplit la forme.

def reliefs(x, y, n) :

    if n == 1 :
        x,y = -640, -250
        go(x, y)
        color(28, 22, 19)

        points = [(x, y + 150), (x + 100, y + 100), (x + 200, y + 50), (x + 300, y + 30), (x + 400, y + 70), (x + 450, y + 60), (x + 475, y + 50), (x + 500, y + 40), (x + 600, y + 10), (x + 642, y + 20), (x + 700, y + 30), (x + 800, y + 30), (x + 900, y + 30), (x + 1000, y + 50), (x + 1100, y + 70), (x + 1200, y + 100), (x + 1280, y + 150), (x + 1280, y)]

        begin_fill()
        for x, y in points:
            go(x, y)
        end_fill()

    if n == 2 :
        x,y = -640, -400
        go(x, y)
        color(20, 14, 11)

        points = [(x, y + 250), (x + 200, y + 150), (x + 600, y + 125), (x + 900, y + 175), (x + 1200, y + 200), (x + 1280, y + 150), (x + 1280, y)]

        begin_fill()
        for x, y in points:
            go(x, y)
        end_fill()

    if n == 3 : 
        x,y = -640, -360
        go(x, y)
        color(28, 19, 14)

        points = [(x, y + 150),(x+250, y + 100),(x+750, y + 50), (x + 1280, y+150), (x + 1280, y)]

        begin_fill()
        for x, y in points:
            go(x, y)
        end_fill()

Nous l’avons appelé un total de 3 fois, créant ainsi une profondeur plus conséquente, même sans perspective et points de fuites concrets dans l’image.

reliefs(-640,-250, 1)
reliefs(-640,-400, 2)
reliefs(-640, -360, 3)


Avec la fonction plage() et des fonctions reliefs() combinées on obtient ce résultat :

Les Palmiers

Jusqu’ici, notre plage au bord de la mer ressemblait plus à un amas de rocher sans vie qu’au résultat escompté. Ainsi, pour donner un côté plus exotique à notre image nous avons décidé de rajouter des palmiers. Ils sont créés à l’aide de 2 fonctions : palmier() et feuille(). La fonction palmier permet de créer la base du palmier (le tronc). On remarque le paramètre r, qui sert à préciser l’inclinaison du palmier (0 = droite, 1 = gauche). Cette fonction est principalement composée de goto() qui ne sont pas remplaçables par notre fonction go() car elle ne tracerait pas les bords noirs.

À la fin de cette fonction nous appelons la fonction feuille. Elle crée des demi-cercles créant ainsi des feuilles de palmier avec les for angle in angles, ainsi que des détails à l’intérieur de celles-ci avec les for offset in offsets, qui constituent au final un détail essentiel de notre image.
Nous l’appelons 2 fois dans la fonction palmier, une fois pour le côté gauche et une autre fois pour le côté droit.

def palmier(x, y, col, r) :

    go(x, y)
    color(col)
    pensize(3)
    fillcolor(51, 32, 3)
    begin_fill()

    for i in range(10):

        if r > 0 :
            right(1)
            goto(x, y +  40)
            goto(x + 40, y + 38)
            goto(x + 40, y)
            goto(x, y)
            go(x, y + 40)
            x += 2
            y += 40

        else : 
            left(-7)
            goto(x, y +  40)
            goto(x + 40, y + 38)
            goto(x + 40, y)
            goto(x, y)
            go(x, y + 40)
            x -= 4
            y += 40

    end_fill()
    x, y = pos()
    go(x + 20, y - 1)
    color(0, 0, 0)
    fillcolor(58, 35, 5)
    begin_fill()
    circle(40)
    end_fill()

    go (x+20, y+41)
    feuilles(150,0, 0)
    feuilles(-160,1, 0)
def feuilles(long, dir, i):
    x, y = pos()

    if dir == 1:
        angles = [45, 90, 360]
        offsets_g = [99, -216, 189]
        offsets_d = [-101, -146, -192]
        col = [(11, 97, 1), (10, 77, 2), (5, 59, 0)]

        for angle in angles:
            color(col[i])
            setheading(angle)
            begin_fill()
            circle(long, 110)
            end_fill()
            go(x, y)
            i += 1

        for offset in offsets_g:
            color(6, 44, 2)
            setheading(angle + offset)
            circle(170, 92)
            go(x, y)

        for offset in offsets_d:
            color(6, 44, 2)
            setheading(angle + offset)
            circle(190, -85)
            go(x, y)

    elif dir == 0:
        angles = [135, 180, 90]
        col = [(11, 97, 1), (10, 77, 2), (5, 59, 0)]

        for angle in angles:
            color(col[i])
            setheading(angle)
            begin_fill()
            circle(long, 110)
            end_fill()
            go(x, y)
            i += 1


Et voici les deux palmiers que l’on obtient à la fin de l’exécution du script. Ils sont très légèrement différents pour éviter de créer une répétition :

Le Bateau

Pour représenter le bateau nous avons utilisé 2 fonctions : bateau() et reflets() décrite précédemment, avec des paramètres différents. Le script du bateau est assez peu lisible, mais il marche, et c’est le plus important. Il se constitue principalement de fonctions basiques de turtle afin de tracer les formes du bateau.

def bateau(x, y) :

    setheading(0)
    go(x,y)
    color(0,0,0)
    pensize(3)
    begin_fill()
    forward(40)
    left(45)
    forward(20)
    a, b = pos()
    setheading(0)
    go(x,y)
    left(135)
    forward(20)
    go(a,b)
    go(x,y)
    go(a-40,b)
    setheading(90)
    forward(40)
    right(135)
    forward(40)
    go(a-40,b)
    end_fill()
    hideturtle()


On obtient alors un petit bateau au loin comme celui-ci, qui n’est pas très détaillé, mais qui en donne assez bien l’illusion :

Les Oiseaux

Enfin, en touche finale, pour donner un côté vivant à notre image nous avons rajouté des oiseaux en forme de V. Les oiseaux ont un placement aléatoire grâce à la fonction randint() du module random et l’angle des ailes, ainsi que leur couleur (bien que donnant une différence très subtile) sont aléatoire, ce qui permet à l’image au global d’être moins monotone.

def oiseaux (n):

    for i in range(n) :

        x = randint(0, 250)
        y = randint(0,200)
        a = randint(2, 4)
        taille = a * 10
        angle = randint(50, 70)
        c = randint(0, 30)

        go(x,y)
        pensize(a)
        color(c,c,c)
        setheading(135)
        circle(taille, angle)
        go(x,y)
        setheading(45)
        circle(-taille, angle)
        hideturtle()

Ce script nous a donné comme résultat une image similaire à celle-ci, mais qui ne sera jamais vraiment la même, à cause des paramètres aléatoires de cette fonction. Cette dernière fonction conclue alors le principal de notre code !

Difficultés rencontrées

Durant ce projet, nous nous sommes confrontés à de nombreuses difficultés techniques, mais qui nous auront au final permis d’améliorer nos compétences en python.

Par exemple, un des premiers problèmes que nous avons dû résoudre fut celui du dégradé de couleur, qui a mis beaucoup de temps avant de marcher correctement, et de nombreux essais. De même, la gestion de la position aléatoire des oiseaux a été un défi, nécessitant de nombreux essais, car ils avaient tendance à se superposer ou à se cacher derrière le palmier droit. Le placement des reliefs et le détail des feuilles de palmiers ont aussi pris du temps, car ils demandaient des ajustements minutieux pour que l’image gagne en cohérence. Ce fut d’ailleurs aussi le cas avec les détails des feuilles de palmiers.

En résumé, le déboggage du code a pris du temps, mais il était nécéssaire pour parvenir à notre image finale !

Résultat final

C’est à la toute fin du code que nous appelons toutes ces fonctions dans un ordre précis (du plus éloigné au plus près) pour créer l’image finale :

ciel((255, 154, 92), (154, 0, 255), 1280, 1000)
soleil(250, (255, 203, 61))
mer((154, 0, 254), (255, 154, 92), 1280, 168)
reflets(0, -89, 425, (255, 203, 61), 14, 7)
plage(-640, -360)
reliefs(-640,-250, 1)
oiseaux(6)
reliefs(-640,-400, 2)
palmier(-425, -275, (0, 0, 0), 1)
palmier(380, -250, (0, 0, 0), -1)
reliefs(-640, -360, 3)
bateau(125, -96)
reflets(145, -105, 40, (0, 0, 0), 4, 3)


Tout ce code fut par la suite inséré dans le code fourni par nos enseignant et qui permet d’exporter cette image en .ps dans le format .png. Le code python complet (d’environ 390 lignes) se trouve plus bas, téléchargeable en version compressée.

Le script en .py

Voici le script python si vous voulez vous aussi vous amusez à le manipuler, ou simplement regarder sa construction dans son ensemble.

Merci d’avoir lu cet article ! Nous espérons qu’il vous aura été utile !

Avatar de Pierre B.
Avatar de Robin P.
Art

Extraction minière au sein de l’Himalaya

Le premier projet de la classe de 1ère NSI est « Image générative ». Ce projet consiste en la création d’une image sur thème libre. Pour notre image, on a choisi d’aborder les thèmes de la montagne, du ciel et de la mine. Nous avons voulu représenter ainsi, une mine présente au sein de la chaine de montagnes de l’Himalaya sous un ciel étoilé de nuit avec une lune en fond venant se glisser derrière la montagne.

Le fond

Afin de réaliser le fond de notre image, nous avons voulu réaliser un fond dégradé du bleu foncé vers le bleu clair afin de représenter la nuit tombante.

def fond():
    for i in range(720):
        r = 173 - round((i / (720 / 173)))  
        v = 216 - round((i / (720 / 216))) 
        b = 230 - round((i / (720 / 102)))
        pencolor(r, v, b)
        forward(1280)
        goto(-640, -360 + i)

fond()

Les étoiles

Ensuite pour réaliser l’ambiance de nuit tombante, nous avons fait le choix de rajouter des étoiles. Pour cela nous avons utilisé le module « randint » nous permettant de placer les étoiles de manière aléatoire.

def etoile():
    pencolor("#fff7cd")
    fillcolor("#fff7cd")
    for _ in range(130):
        penup()
        x = randint(-650, 650)
        y = randint(-360, 360)
        goto(x, y)
        pendown()
        begin_fill()
        circle(randint(1, 4))
        end_fill()
etoile()

Lune

Pour rester dans cette ambiance de nuit tombante nous avons rajouté une lune en fond à laquelle nous avons rajouté des taches pour que celle ci soit plus fidèle à la vrai lune.

def lune():
    penup()
    goto(10,-50)
    color("#EEF0F1")
    fillcolor("#EEF0F1")
    begin_fill()
    circle(220)
    end_fill()
lune()

def taches(x, y,z):
    for i in range(15):
        penup()
        goto(x, y)
        pendown()
        shapesize(z)
        pencolor("#000000")  
        fillcolor("#a4a4a4")  
        begin_fill()  
        circle(z)
        end_fill()
taches(100, 200,20)
taches(-110, 100,50)
taches(-90, 250,30)
taches(0, 200,15)
taches(70, 75,42)
taches(70, 270,24)
taches(150, 100,12)

Les montagnes

Ici nous avons créer des montagnes sous forme de chaine où logera par la suite notre grotte minière. Nous avons rajouter un rectangle afin de combler le trou entre les montagnes même si cela est peux conventionnel.

def triangle(x,y,z):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#757575") 
    fillcolor("#757575")
    begin_fill()
    for i in range(3):
        forward(500)
        left(120)    
    end_fill()
triangle(-235,-200,10)
triangle(70,-350,10)
triangle(-600,-350,10)
triangle(-450,-400,10)
triangle(-800,-500,10)
triangle(310,-500,10)
def rectangle():
    penup()
    goto(-110,-250)
    pendown()
    pensize(150)
    pencolor("#757575")
    forward(400) #Peu conventionnel
rectangle()

Ombre des montagnes

Afin de rajouter du réalisme à notre image nous avons décidé de rajouter une ombre derrière les montagnes en suivant presque le même schéma que celles ci.

def ombre(x,y,z):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#323232") 
    fillcolor("#323232")
    begin_fill()
    for i in range(3):
        forward(500)
        left(120)    
    end_fill()
ombre(-280,-200,10)
ombre(30,-350,10)
ombre(-640,-350,10)
ombre(-490,-400,10)
ombre(-840,-500,10)
ombre(270,-500,10)

Le sol

Nous avons décidé de faire un sol dégradé marron foncé afin de rappeler la couleur de la terre et aussi se rapprocher du modèle réel présent dans la réalité.

def sol():
    for i in range(107):
        r = round(101 + (30 - 60) * (i / 107))  
        v = round(67 + (1 - 20) * (i / 107))    
        b = round(33 + (1 - 20) * (i / 107))    
        pencolor(r, v, b)                     
        forward(1280)                        
        goto(-640, -360 + i)                
sol()

La grotte

La grotte était notre idée principale ainsi nous avons décidé de la mettre au centre. Pour marquer la profondeur de celle ci nous avons choisi le noir pour récréer l’obscurité de la grotte.

def entree(x,y,z):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#000000") 
    fillcolor("#000000")
    begin_fill()
    for i in range(3):
        forward(z)
        left(120)    
    end_fill()

entree(-120,-253,150)
entree(-90,-253,165)
entree(40,-253,50)

La neige

Toujours dans la dynamique de ressemblance à la réalité, nous avons fait le choix de rajouter au sommet des montagnes de la neige comme sur les sommet de l’Himalaya. Pour cela nous avons encore utilisé la fonction triangle que nous avons préalablement définie.

def neige(x,y,z,w):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#f7f7f7") 
    fillcolor("#f7f7f7")
    begin_fill()
    for i in range(3):
        forward(z)
        left(w)    
    end_fill()
neige(-49,120,130,120)
neige(-50,120,30,-120)
neige(-20,120,50,-120)
neige(35,120,15,-120)
neige(50,120,30,-120)

neige(273,0,95,120)
neige(273,0,30,-120)
neige(300,0,15,-120)
neige(310,10,40,-120)
neige(350,0,15,-120)

neige(-397,0,95,120)
neige(-397,0,30,-120)
neige(-340,0,15,-120)
neige(-365,5,25,-120)
neige(-328,0,25,-120)

neige(-225,-10,50,120)
neige(-225,-10,10,-120)
neige(-210,-10,20,-120)
neige(-190,-10,15,-120)

neige(-575,-110,50,120)
neige(-575,-110,10,-120)
neige(-560,-110,15,-120)
neige(-548,-107,10,-120)
neige(-540,-110,15,-120)

neige(535,-110,50,120)
neige(535,-110,18,-120)
neige(555,-110,9,-120)
neige(565,-110,20,-120)

Relief

Toujours dans une démarche de réalisme, nous avons voulu apporter un relief à, la montagne paraissant plate. Pour cela nous avons simplement tracé des traits prolongeant certaines arrête des montagnes.

def delimitation(x,y,z,w):
    pencolor("#2c2c2c")
    pensize(3)
    penup()
    goto(x,y)
    pendown()
    goto(z,w)
delimitation(-60,110,-208,-150)
penup()
delimitation(-402,0,-519,-210)
penup()
delimitation(270,-1,145,-210)

Chariot

En accord avec notre première idée, nous avons rajouté un chariot à la mine pour que de un l’image soit plus compréhensible mais aussi pour venir rajouter des détail à notre image. Nous avons fait le choix également de rajouter des rails pour celui ci.

Problèmes rencontrés

Nous avons eu de nombreux problèmes durant la création de notre image. En effet lors de faire la lune nous avions eu pour idée de rendre les taches aléatoire avec le module « randint » , mais cela n’allais pas car les taches se superposais et ne changeais pas de taille. Aussi lorsque nous avons fais le wagon nous réfléchissions a un moyen de le remplir réalistement mais nous n’avons pas trouver alors nous avons fais le choix de placer de simples triangles.

Sources

Afin de réaliser notre image, nous avons utilisé plusieurs sources : Tout d’abord nous avons utilisé chat gpt afin de déboguer certaines parties de notre code, ensuite nous avons utilisé le forum « stack overflow » pour trouver notre fond et réaliser notre dégradé, enfin nous avons utilisé le site « python guides » pour nous renseigner sur des commandes notamment sur l’utilisation du module « random » lors de la création des étoiles.

Projets

Perspective : Paris 2024

Dans le cadre de notre projet d’art génératif en Première NSI, nous avons décidé de concevoir un paysage en perspective qui représente Paris pendant les Jeux Olympiques de 2024. Notre objectif est de mêler des éléments architecturaux emblématiques de la ville avec l’ambiance olympique qui y règne.

Note : 4.5 sur 5.

Origine des JO

Cet été 2024 à Paris a eu lieu les JO. Les JO sont des événements sportifs internationaux majeurs, regroupant les sports d’été ou d’hiver, auxquels des milliers d’athlètes participent à travers différentes compétitions tous les quatre ans, pour chaque olympiade moderne.

Pour plus d’informations, nous vous conseillons cette vidéo explicative de l’origine des JO.

Le Projet

Revenons au projet. Nous avons choisi de créer une image des Champs Elysées pendant la période des JO 2024. Pour cela, nous utilisons les modules turtle et random. Le module turtle permet de dessiner l’image, tandis que le module random génère aléatoirement la taille et la position des étoiles dans le ciel. Nous avons également intégré un script pour exporter l’image générée par turtle en format .png, que vous pouvez retrouver ici.

Structure du script

Nous avons structuré le script en séparant chaque élément de l’image (fond dégradé, étoiles, route, trottoirs, arc de triomphe, anneaux olympiques, bâtiments, arbres) dans des fonctions distinctes. Ensuite, nous avons appelé ces fonctions dans un ordre spécifique, permettant ainsi à chaque élément de se superposer correctement dans son propre plan.

Analyse du script

Nous allons donc analyser notre script.

On commence d’abord par l’appel des modules utilisés et la mise en place turtle.

from turtle import *
from random import randint

# Vérification des modules importés
try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False

# Définir le titre de la fenêtre de turtle 
titre = "Perspective Paris 2024 - construite avec turtle"
title(titre+" | Au lycée, la meilleure spécialité, c'est la spé NSI")

colormode(255) # Permet l'utilisation de couleurs rgb
setup(1280, 720) # Définir la taille de la fenêtre en 720p 
speed(0) # La tortue va à la vitesse du lièvre
hideturtle() # La tortue active sa cape d'invisibilité

flash = True # False par défaut, on peut mettre True sinon, ou mieux 0x2A
if flash:
    wn = Screen()
    wn.tracer(0)

On utilise les modules turtle et random, en se concentrant uniquement sur la fonction randint de random. Le script inclut également une partie pour exporter une image générée par turtle. Cela permet de vérifier si l’utilisateur a installé le module PIL ; si ce n’est pas le cas, un message d’erreur s’affiche avec un lien pour l’installer, sans interrompre l’exécution du script. Ensuite, on définit le titre de la fenêtre qui affichera le rendu ainsi que sa taille. On configure également le type de couleurs utilisées (R,G,B), la vitesse de la tortue et on cache la tortue pour une présentation plus esthétique.

Puis, voici notre première fonction : le fond dégradé sur la partie haute de l’image.

def fond():
    red, green, blue = 0, 0, 100
    penup()
    hauteur = 0
    penup(), goto(-641, hauteur)
    while hauteur != 360:
        pendown()
        pencolor(round(red), round(green), round(blue))
        forward(1280)
        hauteur += 1
        goto(-640, hauteur)
        blue = blue - float(100 / 360)

Pour le fond, nous avons donc choisi d’utiliser un dégradé. Le script fait avancer la tortue sur une ligne d’un pixel de large et à la fin de chaque ligne, la tortue est envoyée à la ligne suivante grâce à un goto. À chaque déplacement, on ajuste progressivement les valeurs des couleurs, de façon arrondie (dans notre cas, on ajuste seulement la valeur du bleu) en fonction de la différence entre la couleur de début et celle de fin du dégradé.

Ensuite, vient la deuxième fonction, celle des étoiles dans le ciel.

def etoiles (x_max1, x_max2, y_max1, y_max2, r_max1, r_max2, nb_etoiles):
    for i in range(nb_etoiles):
        x, y, r = randint(x_max1,x_max2), randint(y_max1,y_max2), randint(r_max1,r_max2)
        pencolor("#FFFFFF"), begin_fill()
        penup(), goto(x, y), pendown()
        circle (r)
        fillcolor("#FFFFFF"), end_fill()

Pour les étoiles, leur position dans le ciel et leur taille, variant entre 1 et 3 pixels de rayon, sont déterminées aléatoirement avec la fonction randint du module random. Ensuite, un cercle est tracé à chaque position générée avec la taille correspondante. Ce processus est répété 100 fois dans une boucle for i in range, afin de créer 100 étoiles au total.

Vient ensuite la fonction pour dessiner la route et les trottoirs (le script suivant n’est qu’une partie du code complet, long et répétitif, il n’est donc pas nécessaire de commenter la suite).

def base_route(xi, yi, xf, yf, col_route, larg_debut_route, larg_fin_route):
    penup(), goto(xi, yi), pendown()
    pencolor(col_route)
    begin_fill(), fillcolor(col_route)
    goto(xi - (1 / 2 * larg_debut_route), yi), goto(xi + (1 / 2 * larg_debut_route), yi), goto(xf + (1 / 2 * larg_fin_route), yf)
    goto(xf - (1 / 2 * larg_fin_route), yf), goto(xi - (1 / 2 * larg_debut_route), yi)
    end_fill()
    
def ligne_entre_routes(xi, yi, xf, yf, col_lignes):
    penup(), goto(xi, yi), pendown()
    left(90)
    size = 20
    for i in range (357):
        pensize(round(size))
        size = size - float(15 / 360)
        pencolor(col_lignes)
        forward(1)
        
def marquage_gauche(xi, yi, xf, yf, col_lignes, long_marquages, larg_debut_route):
    longueur = 360
    penup(), goto(xi - 1 / 4 * larg_debut_route, yi), pendown()
    pensize(7), pencolor(col_lignes)
    right(40)
    k = 0
    while k * long_marquages < longueur - long_marquages:
        k += 2
        pendown(), forward(long_marquages), penup(), forward(long_marquages)

def trottoir_droite(xi, yi, xf, yf, col_trottoir, larg_debut_route, larg_fin_route, larg_debut_trot, larg_fin_trot):
    penup(), goto(xi + (1 / 2 * larg_debut_route), yi), pendown()
    pencolor(col_trottoir)
    pensize(2)
    begin_fill(), fillcolor(col_trottoir)
    goto(xi + (1 / 2 * larg_debut_route) + (1 / 2 * larg_debut_trot), yi), goto(xf + (1 / 2 * larg_fin_route) + (1 / 2 * larg_fin_trot), yf)
    goto(xf + (1 / 2 * larg_fin_route), yf), goto(xi + (1 / 2 * larg_debut_route), yi)
    end_fill()
    penup(), goto(xi + (1 / 2 * larg_debut_route) + 20, yi), pendown()
    pensize(3), pencolor("#6C757D")
    begin_fill(), fillcolor("#6C757D")
    goto(xf + (1 / 2 * larg_fin_route) + 7.5, yf), goto(xf + (1 / 2 * larg_fin_route), yf)
    goto(xi + (1 / 2 * larg_debut_route), yi), goto(xi + (1 / 2 * larg_debut_route) + 20, yi)
    end_fill()

def route_et_trottoir(xi, yi, xf, yf, col_route, col_trottoir, col_lignes, col_pavage, long_marquages, larg_debut_route,
larg_fin_route, larg_debut_trot, larg_fin_trot):
    base_route(xi, yi, xf, yf, col_route, larg_debut_route, larg_fin_route)
    ligne_entre_routes(xi, yi, xf, yf, col_lignes)
    marquage_droit(xi, yi, xf, yf, col_lignes, long_marquages, larg_debut_route)
    marquage_gauche(xi, yi, xf, yf, col_lignes, long_marquages, larg_debut_route)
    trottoir_droite(xi, yi, xf, yf, col_trottoir, larg_debut_route, larg_fin_route, larg_debut_trot, larg_fin_trot)
    trottoir_gauche(xi, yi, xf, yf, col_trottoir, larg_debut_route, larg_fin_route, larg_debut_trot, larg_fin_trot)

Pour la route et les trottoirs, nous commençons par tracer la base de la route en perspective en utilisant la fonction goto, puis nous ajoutons les marquages au sol. La ligne centrale entre les deux voies est progressivement affinée pour renforcer l’effet de perspective. Ensuite, les trottoirs de chaque côté sont tracés avec goto, en appliquant les mêmes proportions pour respecter la perspective. Enfin, une fonction finale regroupe toutes les fonctions constituant notre route et nos trottoirs.

Nous poursuivrons ensuite avec le codage de l’Arc de Triomphe (le script est encore long, il ne sera donc pas intégral ici).

def pilier_gauche(x, y, larg, long, col):
    pencolor(col)
    begin_fill(), fillcolor(col)
    penup(), goto(x - larg,y), pendown()
    right(70)
    for i in range(2):
        forward(larg), left(90), forward(long - 40), left(90)
    end_fill()
    
def atique_arc_de_triomphe(x, y, larg, long, col):
    pencolor(col)
    penup(), goto(x + larg, y + long - 40), left(90), pendown()
    begin_fill()
    circle((1 / 2 * larg), 180)
    for i in range(2):
        right(90), forward(larg)
    right(90), forward(3 / 2 * (long))
    for i in range(2):
        right(90), forward(larg)
    fillcolor(col), end_fill()
    
def rajout_atique(x, y, larg, long, col):
    pencolor(col)
    penup(), goto(x + (long), y + ((long - 40) + larg)), pendown()
    begin_fill(), fillcolor(col)
    right(90)
    for i in range(2):
        forward(larg - (1 / 2 * larg)), left(90), forward((long) + larg), left(90)
    end_fill()

def details_arc_de_triomphe(x, y, larg, long, col_detail):
    penup(), goto(x + (long), y + (long - 40 + larg)), pendown()
    pensize(5), pencolor(col_detail)
    left(90), forward(long + larg)

def arc_de_triomphe(x, y, larg, long, col):
    pilier_gauche(x, y, larg, long, col)
    pilier_droite(x, y, larg, long, col)
    atique_arc_de_triomphe(x, y, larg, long, col)
    rajout_atique(x, y, larg, long, col)
    details_arc_de_triomphe(x, y, larg, long, "#9C7F6E")

Pour l’Arc de Triomphe, nous avons choisi de le coder étape par étape : d’abord les piliers, puis l’attique, et enfin les détails. Les piliers sont représentés par de simples rectangles colorés, en utilisant les commandes begin_fill, fillcolor, et end_fill. Pour l’attique, nous avons dessiné un arc de cercle avec circle(rayon, 180) pour représenter la courbure. Enfin, toutes les fonctions constituant l’Arc de Triomphe sont appelées dans une fonction unique pour générer l’ensemble du monument.

Passons maintenant au code pour générer les anneaux olympiques.

list_col_anneau = ["#0D79FF", "#FFD900", "#000000", "#12C52D", "#FF0F0F"]

def anneau_haut(x,col,rayon,size):
    penup(), forward(x), pendown()
    pencolor(col), pensize(size), circle(rayon)
 
def anneau_bas(x,col,rayon,size):
    penup(), left(90), forward(x), pendown()
    pencolor(col), pensize(size), circle(rayon)

def anneaux(xf,yf,rayon,size):
    penup(), goto(xf,yf), pendown()
    anneau_haut(0,list_col_anneau[0],rayon,size)
    anneau_haut(2 * rayon + (size + 5),list_col_anneau[2],rayon,size)
    anneau_haut(2 * rayon + (size + 5),list_col_anneau[4],rayon,size)
    penup(), goto(xf - rayon - (1 / 5 * rayon), yf - rayon), right(90), pendown()
    anneau_bas(0,list_col_anneau[1],rayon,size)
    right(90)
    anneau_bas(2 * rayon + (size + 5),list_col_anneau[3],rayon,size)

Nous avons commencé par définir une liste des couleurs pour chaque anneau. Ensuite, les anneaux de la rangée supérieure ont été dessinés, suivis de ceux de la rangée inférieure, en utilisant la fonction circle. Enfin, nous avons regroupé le tout dans une fonction unique qui positionne les anneaux correctement.

Nous poursuivrons ensuite avec le script dédié à la lune et à ses cratères (le code des cratères étant répétitif, il ne sera pas présenté dans sa totalité).

def cratere1 (x, y, rayon_lune, col):
    x_crat1 = x
    y_crat1 = y + rayon_lune + (1 / 4 * rayon_lune)
    taille_crat1 = 1 / 3 * rayon_lune
    penup(), goto(x,y), goto(x_crat1,y_crat1), pendown()
    begin_fill(), pencolor(col)
    circle(taille_crat1)
    fillcolor(col), end_fill()

def crateres(x, y, rayon_lune, col):
    cratere1 (x, y, rayon_lune, col)
    cratere2 (x, y, rayon_lune, col)
    cratere3 (x, y, rayon_lune, col)
    cratere4 (x, y, rayon_lune, col)
    cratere5 (x, y, rayon_lune, col)

def lune(x, y, rayon_lune, col_lune):
    left(180)
    begin_fill()
    penup(), goto(x,y), pendown()
    pencolor(col_lune), circle(rayon_lune), fillcolor(col_lune), end_fill()
    crateres(x, y, rayon_lune, "#DEDCDA")

A propos de la lune et de ses cratères, premièrement, chaque fonction (cratere1 à cratere5) dessine un cratère à des positions spécifiques autour de la lune, en utilisant le rayon de la lune pour ajuster la taille et la position. Deuxièmement, la fonction crateres regroupe tous les cratères en une seule fonction. Et au final, la fonction lune dessine la lune en tant que cercle rempli, puis appelle la fonction crateres pour ajouter les cratères à la surface de la lune.

Nous allons maintenant aborder le codage des bâtiments.

def bat_droite(xi, yi, xf, yf, col, col_trace, hauteur):
    pencolor(col_trace), pensize(3)
    begin_fill(), fillcolor(col)
    penup(), goto(xi, yi), pendown()
    goto(xf, yf), goto(xf, hauteur), goto(1282, hauteur), goto(xi, yi)
    end_fill()
    penup(), goto(xf, hauteur), pendown()
    right(15), forward(500)

def bat_gauche(xi, yi, xf, yf, col, col_trace, hauteur):
    pencolor(col_trace), pensize(3)
    begin_fill(), fillcolor(col)
    penup(), goto(xi, yi), pendown()
    goto(xf, yf), goto(xf, hauteur), goto(-1282, hauteur), goto(xi, yi)
    end_fill()
    penup(), goto(xf, hauteur), pendown()
    left(210), forward(500)

Pour les bâtiments, les fonctions dessinent des structures à droite et à gauche, en utilisant des coordonnées spécifiées, une couleur de remplissage, une couleur de contour et une hauteur. Chaque fonction remplit le bâtiment et trace un toit incliné, créant ainsi un effet de perspective qui enrichit visuellement l’image.

Nous allons maintenant découvrir le script qui permet de dessiner des arbres le long des trottoirs.

def tronc(x, y, larg_tronc, col_tronc, long_tronc):
    begin_fill()
    penup(), goto(x,y), pendown()
    pencolor(col_tronc)
    for i in range(2):
        forward(larg_tronc), left(90), forward(long_tronc), left(90)
    fillcolor(col_tronc), end_fill()
  
def feuilles(x, y, col_feuilles, ray_feuilles, larg_tronc, long_tronc, col_tronc):
    begin_fill()
    penup(), goto(x + (1 / 2 * larg_tronc),y + long_tronc), pendown()
    pencolor(col_feuilles)
    for i in range(5):
        begin_fill()
        circle(ray_feuilles), left(72), forward(10)
        fillcolor(col_feuilles), end_fill()

def arbre(x, y, col_feuilles, ray_feuilles, larg_tronc, long_tronc, col_tronc):
    tronc(x, y, larg_tronc, col_tronc, long_tronc)
    feuilles(x, y, col_feuilles, ray_feuilles, larg_tronc, long_tronc, col_tronc)

# On place les arbres sur le trottoir
def arbres():
    x = -275
    y = -25
    ray_feuilles = 20
    larg_tronc = 22
    long_tronc = 80
    right(195)
    for i in range(14):
        arbre(x, y, "#009B1A", ray_feuilles, larg_tronc, long_tronc, "#7F2C00")
        x -= 25
        y -= 25
        ray_feuilles += float(2.5)
        larg_tronc += float(2.5)
        long_tronc += 10
    x = 258
    y = -25
    ray_feuilles = 20
    larg_tronc = 22
    long_tronc = 80
    for i in range(14):
        arbre(x, y, "#009B1A", ray_feuilles, larg_tronc, long_tronc, "#7F2C00")
        x += 22
        y -= 25
        ray_feuilles += float(2.5)
        larg_tronc += float(2.5)
        long_tronc += 10

Concernant les arbres, tout d’abord, la fonction tronc dessine le tronc d’un arbre en utilisant des coordonnées spécifiques, une largeur, une couleur et une longueur. Elle utilise une boucle pour créer un rectangle rempli représentant le tronc. Après, la fonction feuille dessine les feuilles de l’arbre. Elle positionne le curseur au-dessus du tronc et utilise une boucle pour créer plusieurs cercles qui représentent les feuilles, disposés en étoile autour de la partie supérieure du tronc. Suite à quoi la fonction arbre combine les fonctions tronc et feuilles pour dessiner un arbre complet à des coordonnées données. Pour couronner le tout, la fonction arbres place plusieurs arbres le long des trottoirs. Elle commence à des coordonnées spécifiques et utilise une boucle pour dessiner 14 arbres de chaque côté. La position, la taille des feuilles, la largeur et la longueur du tronc augmentent progressivement pour créer un effet de perspective, tandis que les arbres se déplacent vers le bas et de manière symétrique des deux côtés.

Enfin, nous appelons chaque fonction dans un ordre spécifique pour produire l’image finale.

# Appel de toutes les fonctions
fond()
etoiles(-640, 640, 0, 360, 1, 3, 100)
route_et_trottoir(0, -360, 0, 0, "#424345", "#ADB5BD", "#CECDC9", "#6C757D", 30, 800, 300, 1000, 375)
arc_de_triomphe(-50, 0, 100, 200, "#D4C4B0")
anneaux(70,300,30,7)
lune(250, 200, 50, "#F4F1ED")
bat_droite(900, -360, 337.5, 0, "#eae2b7", "#d4a373", 250)
bat_gauche(-900, -360, -337.5, 0, "#eae2b7", "#d4a373", 250)
arbres()

Et pour exporter l’image finale en .png il y a la suite du script pour exporter une image générée par turtle en .png utilisé au début du script.

if flash:
    wn.update() 

# Enregistrement de l'image finale
image = getcanvas()
nom_du_fichier_sans_extension=titre+"_"+hex(randint(2**30+2**25,2**30+2**25+2**24-1))[2:]
image.postscript(file=nom_du_fichier_sans_extension+".ps", colormode='color')
try:
    psimage = Image.open(nom_du_fichier_sans_extension+".ps")
    psimage.load(scale=2)
    psimage_resized = psimage.resize((1280, 720))
    psimage.save(nom_du_fichier_sans_extension+".png")
    print(nom_du_fichier_sans_extension+".png", psimage.size, "sauvegardé dans le dossier")    
 
# Vérification des modules importés
except:
    if not pillow_installed:
        print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
        print("https://nsi.xyz/py2png")
    else:
        print("Oops! - 'ghostscript' not installed- RTFM :")
        print("https://nsi.xyz/py2png")

exitonclick()

Le script va donc générer une image en .ps et la convertir en .png avec un nom généré aléatoirement.

Image finale

Télécharger le .py

Art

De l’art sur la NumWorks

Les calculatrices graphiques programmables sont bien plus que de simples outils pour les calculs. Elles ouvrent un monde de possibilités aux élèves, en permettant d’explorer les mathématiques d’une manière interactive et visuelle. Mais leur potentiel va au-delà des formules et des graphiques : elles peuvent être utilisées pour créer de l’art numérique, des animations, et même des jeux !

En programmant ces machines, les étudiants développent leur créativité tout en renforçant leurs compétences en logique et en résolution de problèmes. Ces calculatrices deviennent ainsi des alliées indispensables pour apprendre de manière ludique et innovante, et pour repousser les limites de l’imagination.

Depuis 2019, j’invite mes élèves à explorer leur potentiel créatif en réalisant des dessins uniques, soit avec l’application Grapheur, soit avec l’application Python de la calculatrice. Chaque année, leurs œuvres sont soumises à l’éditeur de la calculatrice, NumWorks, qui sélectionne la plus belle réalisation. L’auteur de cette création se voit offrir une coque au design original pour sa calculatrice. Si vous croisez un élève au lycée Louis Pasteur arborant une telle coque, il est fort probable qu’il soit lauréat de l’un de ces concours.

Certaines de ces réalisations sont également partagées sur les réseaux sociaux, notamment sur Instagram et X (anciennement Twitter). Une quinzaine de ces images ont même été sélectionnées et publiées, avec l’accord de leurs auteurs, dans un livre intitulé Découvrir la calculatrice graphique NumWorks édité en Français et en Anglais.

Il est vrai que se lancer dans la programmation sur une calculatrice graphique peut sembler déroutant au premier abord. Le défi de traduire des idées créatives en code peut déstabiliser, surtout pour ceux qui n’ont jamais exploré cet univers. Cependant, une fois les premières hésitations surmontées, les élèves découvrent rapidement le plaisir de voir leurs concepts prendre vie à l’écran. Ce processus, bien qu’exigeant, devient une source de satisfaction personnelle, les encourageant à se dépasser. En fin de compte, ils s’amusent tout en repoussant leurs propres limites, transformant un défi intimidant en une expérience enrichissante.

Tout à commencé en 2019 …

En 2019, après réflexion et concertation de l’équipe des enseignants de mathématiques, nous avons pris la décision collective de passer aux calculatrices NumWorks dans toutes nos classes. Pour familiariser les élèves avec cet outil, leur premier travail a été de réaliser un projet simple, destiné à leur faire découvrir les différentes fonctionnalités de la calculatrice. Sans attente particulière, j’ai été agréablement surpris par l’enthousiasme et la créativité dont ils ont fait preuve. Certaines productions, bien au-delà de ce que j’avais imaginé, ont révélé un potentiel insoupçonné chez les élèves, ouvrant la voie à des projets encore plus ambitieux par la suite.

Le titre du sujet était : Les mathématiques sont belles. Voici les 30 réalisations des élèves.

Certaines de ces images sont issues de scripts bien connus, adaptés et optimisés pour la NumWorks. Elles ont été réalisées à distance, en ligne, pendant le confinement de mars 2020. J’ai alors demandé à mes élèves de Terminale de constituer un jury pour évaluer ces créations, en insistant sur l’importance d’une bienveillance maximale dans leurs délibérations. Bien que les codes Python aient parfois été maladroits, ces erreurs faisaient partie intégrante du processus d’apprentissage. Se tromper, tâtonner, recommencer et s’améliorer sont autant d’étapes essentielles dans le développement de leurs compétences.

Quelques thread colorés publiés sur X (Twitter)

J’ai rejoint X (anciennement Twitter) durant le confinement, à l’origine pour passer le temps. Depuis, j’ai régulièrement partagé des threads mettant en avant les créations de mes élèves. En voici quelques exemples. (Un tableau à la fin de cet article propose davantage de liens.)

De l’art sur la NumWorks depuis 2020

Le tableau ci-dessous récapitule tous les fils de discussion publiés sur X (anciennement Twitter). Malheureusement, depuis le rachat de Twitter par Elon Musk, il n’est plus possible de consulter ces fils sans posséder un compte sur la plateforme. Cette restriction illustre bien les défis liés à l’utilisation d’outils fermés, qui peuvent rapidement se transformer en véritables obstacles à l’accès à l’information. 🥴

Création
(1er éd.)
Titre du travail à rendre
Classe cible
Thread X (Twitter)
2019
(2020)
Les mathématiques sont belles.
Seconde, mathématiques
2020 2021 2022 2023 2024 2025
2021
(2021)
Le Python et la Tortue.
1ère, spécialité NSI
2021 2022 2023 2024
2021
(2021)
Le python et les fractales
Tale, spécialité NSI
2021 2022 2023 2024
2022
(2022)
Les mathématiques sont belles ! ed. spéciale cercle
Tale, option Mathématiques Expertes
2022 2023 2024
2022
(2023)
Les mathématiques sont belles ! ed. spéciale polynôme
Tale, option Mathématiques Expertes
2023, 2024 2025
2022
(2024)
Un feu d’artifice en python
Tale, option Mathématiques Expertes
2024 2025
2023
(2023)
Le Python et la Tortue.
Seconde, SNT
2023 2024
2024
(2024)
Pixel Art en python
Tale, option Mathématiques Expertes
2024

Art

La Citrouille et la Tortue

Pour notre premier projet en classe de 1ère NSI, nous nous sommes basées sur le thème d’halloween.
Ici vous trouverez nos démarches pour créer cette image de style pop. Notre image est composée de quatre parties comportant chacune un fond et une citrouille de couleur différente.

Vidéo de présentation du projet :

Le projet :

Ce projet consiste à créer de l’art génératif grâce à un script python qui doit principalement utiliser des fonctions. Pour le réaliser, nous avons utilisé le module turtle pour tracer l’image et la fonction randint du module random pour pouvoir transformer notre image (.py) en png. Le thème de l’image générée était libre, elle pouvait même être abstraite !

Le processus de création :

Durant ce projet, nous sommes passées par plusieurs étapes pour concevoir l’image et répondre aux attendus.

Nous avons tout d’abord dû trouver une idée de l’image que l’on voulait créer. Pour cela, nous nous sommes inspirées de l’artiste américain Andy Warhol et de ses oeuvres comme « Shot Marilyns » et nous avons transposé son style dans le thème d’Halloween.

Après avoir dessiné un croquis à la main, nous avons créé le script d’une citrouille puis nous l’avons transformé en plusieurs fonctions pour pouvoir la reproduire en quatre exemplaires. Nous avons fait de même pour les rectangles.

Contrairement aux citrouilles et aux rectangles, nous avons tout de suite codé les lettres en tant que fonctions ce qui nous a permis d’aller plus vite dans la conception de l’image.

Enfin, nous avons dû organiser notre script rigoureusement pour que la tortue trace les éléments dans le bon ordre pour un rendu propre et travaillé.

Le code expliqué étape par étape :

Pour concevoir cette image, nous avons agi étape par étape. Nous avons donc relevé les différentes parties du code qui ont permis de tracer l’image. (Nous ne montrerons pas la mise en place des modules et comment nous avons généré des images automatiquement. Pour cela, vous pouvez vous rendre sur cet article.)

Le fond :

Tout d’abord, nous avons divisé l’écran en quatre parties égales et rectangulaires. Nous avons défini une fonction rectangle(x,y,color). Pour obtenir nos quatre parties distinctes, il suffit de mettre les coordonnées ainsi qu’une couleur en argument pour tracer les rectangles au bon endroit.

# trace les rectangles
def rectangle(x, y, color):
  up()
  goto(x, y)
  down()
  pencolor(color)
  fillcolor(color)
  begin_fill()
  for i in range(2):
    forward(640)
    right(90)
    forward(360)
    right(90)
  end_fill()

Nous appelons donc la fonction avec des coordonnées et des couleurs différentes pour tracer nos quatre rectangles.

rectangle(-640, 360, "#A8608E")
rectangle(-640, 0, "#25AE80")
rectangle(0, 360, "#C9BB32")
rectangle(0, 0, "#E1770C")

Résultat :

L’écriture « HAPPY HALLOWEEN » :

Ensuite, nous avons créé des fonctions pour chaque lettre différente composant l’expression « HAPPY HALLOWEEN » soit une fonction pour les lettres h, a, p, y, l, o, w, e et n. La lettre « o » est spéciale car nous avons voulu la représenter par une citrouille pour rester dans le thème d’Halloween. Ici, nous vous montrerons les fonctions lettre_h(x,y), lettre_o(x,y) et lettre_e(x,y).

# trace la lettre h en majuscule
def lettre_h(x,y):
  pensize(3)
  color("black")
  up()
  goto(x,y)
  setheading(90)
  down()
  forward(50)
  backward(25)
  right(90)
  forward(25)
  right(90)
  forward(25)
  backward(50)


# la lettre o est représentée par une citrouille
def lettre_o(x,y,f):
  pensize(3)
  color("black")
  fillcolor(f)
  up()
  goto(x,y+25)

  a = x
  b = y
  for i in range(2):
    up()
    goto(x, y)
    down()
    begin_fill()
    circle(25)
    end_fill()
    x += 25 / (35 / 15)
    y -= 25 / 14

  a = x + 25 / 1.4
  for i in range(2):
    up()
    goto(a, b)
    down()
    begin_fill()
    circle(25)
    end_fill()
    a -= 25 / (35 / 15)
    b -= 25 / 14

  goto(a + 25 / 14, b)
  begin_fill()
  circle(25)
  end_fill()

  setheading(0)
  up()
  goto(a, b + 25 * 2 + 2)
  down()
  pencolor("black")
  left(350)
  for i in range(4):
    left(40)
    forward(25 / (35 / 15))
    goto(a, b + 25 * 2 + 2)


# trace la lettre e en majuscule
def lettre_e(x,y):
  pensize(3)
  color("black")
  up()
  goto(x,y)
  setheading(90)
  down()
  forward(50)
  right(90)
  forward(25)
  backward(25)
  left(90)
  backward(25)
  right(90)
  forward(15)
  backward(15)
  left(90)
  backward(25)
  right(90)
  forward(25)

Après avoir créé toutes ces fonctions, nous les appelons dans un ordre précis pour écrire « HAPPY HALLOWEEN » et nous utilisons des boucles for pour que l’expression soit répétée et forme un motif. Nous rajoutons également la fonction stamp() qui permet de laisser l’empreinte de la tortue à la fin de la lettre « N ».

h = 20
for i in range(4):
  lettre_h(50,h)
  lettre_a(80,h)
  lettre_p(110,h)
  lettre_p(140,h)
  lettre_y(170,h)
  lettre_h(230,h)
  lettre_a(260,h)
  lettre_l(290,h)
  lettre_l(320,h)
  lettre_o(370,h,"#C9BB32")
  lettre_w(460,h)
  lettre_e(510,h)
  lettre_e(540,h)
  lettre_n(570,h)
  stamp()
  h += 90


h = -340
for i in range(4):
  lettre_h(50,h)
  lettre_a(80,h)
  lettre_p(110,h)
  lettre_p(140,h)
  lettre_y(170,h)
  lettre_h(230,h)
  lettre_a(260,h)
  lettre_l(290,h)
  lettre_l(320,h)
  lettre_o(370,h,"#E1770C")
  lettre_w(460,h)
  lettre_e(510,h)
  lettre_e(540,h)
  lettre_n(570,h)
  stamp()
  h += 90


h = 20
for i in range(4):
  lettre_h(-600,h)
  lettre_a(-570,h)
  lettre_p(-540,h)
  lettre_p(-510,h)
  lettre_y(-480,h)
  lettre_h(-420,h)
  lettre_a(-390,h)
  lettre_l(-360,h)
  lettre_l(-330,h)
  lettre_o(-280,h,"#A8608E")
  lettre_w(-190,h)
  lettre_e(-140,h)
  lettre_e(-110,h)
  lettre_n(-80,h)
  stamp()
  h += 90


h = -340
for i in range(4):
  lettre_h(-600,h)
  lettre_a(-570,h)
  lettre_p(-540,h)
  lettre_p(-510,h)
  lettre_y(-480,h)
  lettre_h(-420,h)
  lettre_a(-390,h)
  lettre_l(-360,h)
  lettre_l(-330,h)
  lettre_o(-280,h,"#25AE80")
  lettre_w(-190,h)
  lettre_e(-140,h)
  lettre_e(-110,h)
  lettre_n(-80,h)
  stamp()
  h += 90
shape("turtle")
stamp()

Résultat :

Le corps de la citrouille :

Puis, nous avons défini la fonction corps_citrouille(x,y,pen,fi) pour dessiner le corps de la citrouille. Celle-ci prend en paramètre la couleur et les coordonnées du corps. Le corps est constitué de plusieurs cercles assemblés dans un ordre précis pour que le remplissage s’effectue correctement.

# trace le corps de la citrouille
def corps_citrouille(x,y,pen,fi):
  pencolor(pen)
  pensize(5)
  fillcolor(fi)
  a = x
  b = y
  for i in range(2):
    up()
    goto(x,y)
    down()
    begin_fill()
    circle(70)
    end_fill()
    x += 30
    y -= 5

  a = x + 50
  for i in range(2):
    up()
    goto(a,b)
    down()
    begin_fill()
    circle(70)
    end_fill()
    a -= 30
    b -= 5

  goto(a + 5,b)
  begin_fill()
  circle(70)
  end_fill()

Nous appelons cette fonction avec des coordonnées et des couleurs différentes pour créer nos quatre corps de citrouille.

corps_citrouille(-380,110,"#E1C40C","#E3E013")
corps_citrouille(280,110,"#FF4017","#FF5733")
corps_citrouille(280,-260,"#502D9B","#6445A6")
corps_citrouille(-380,-260,"#26b510","#7EEb1E")

Résultat:

La tige de la citrouille :

De plus, nous avons conçu la tige à l’aide d’une autre fonction qui prend en compte les coordonnées et les couleurs de la tige. Pour la concevoir, nous avons d’abord tracé deux traits partant d’un même point puis nous les avons reliés pour effectuer le remplissage.

#  trace la tige de la citrouille
def tige_citrouille(x,y,pn,fl):
  setheading(0)
  up()
  goto(x,y)
  down()
  pencolor(pn)
  fillcolor(fl)
  begin_fill()
  right(160)
  for i in range(2):
    left(110)
    forward(30)
  goto(x,y)
  end_fill()
  begin_fill()
  right(20)
  for i in range(35):
    forward(1)
    right(2)
  end_fill()

Nous appelons ensuite cette fonction tige_citrouille(x,y,pn,fl) avec différentes coordonnées et couleurs pour bien positionner nos quatre tiges de citrouille.

tige_citrouille(-350,260,"#515146","#7A7A65")
tige_citrouille(310,260,"#0E6F12","#1B801F")
tige_citrouille(310,-110,"#8C0F37","#AD2953")
tige_citrouille(-350,-110,"#909207","#C2BD34")

Résultat :

Le visage :

Enfin, nous avons paramétré une fonction afin de lui créer un visage qui a pour arguments ses coordonnées. Le visage est composé de deux yeux qui sont des triangles, d’un nez qui est un triangle plus petit et d’une bouche également composée de formes géométriques.

# trace le visage de la citrouille
def visage(x,y):
  setheading(0)
  pensize(1)
  up()
  goto(x,y)
  down()
  pencolor("#000000")
  fillcolor("#000000")
  begin_fill()

# trace les deux yeux  
  for i in range(2):
    up()
    goto(x,y)
    down()
    for i in range(3):
      forward(30)
      left(120)
    x += 70
  end_fill()

# trace le nez 
  up()
  goto(x - 100,y - 22)
  down()
  begin_fill()
  for i in range(3):
    forward(22)
    left(120)
  end_fill()

# trace la bouche
  up()
  goto(x - 120,y - 35)
  down()
  begin_fill()
  l = 10
  for i in range(2):
    forward(l)
    right(45)
    forward(12)
    left(90)
    forward(12)
    right(45)
    l = 12
  forward(15)
  for i in range(90):
    forward(0.5)
    right(2)
  for i in range(2):
    right(45)
    forward(12)
    left(90)
    forward(12)
    right(45)
    forward(12)
  right(45)
  forward(12)
  left(90)
  forward(12)
  right(45)
  for i in range(90):
    forward(0.5)
    right(2)
  end_fill()

Nous devons donc appeler cette fonction visage(x,y) avec des coordonnées différentes pour aligner le visage sur le corps de chaque citrouille.

visage(-378,193)
visage(282,193)
visage(282,-177)
visage(-378,-177)

Résultat :

Les difficultés rencontrées :

La première difficulté a été de trouver la distance entre les lettres pour former l’expression « HAPPY HALLOWEEN ». Au début, nous les avions espacées de 30 pixels puis nous nous sommes aperçues que certaines lettres se chevauchaient. Après de nombreuses tentatives, nous sommes arrivées au rendu recherché.

Une autre difficulté a été de tracer les cercles qui composent le corps de la citrouille dans le bon ordre pour que le remplissage s’effectue correctement. En ayant compris la logique du remplissage nous sommes finalement parvenues à trouver cet enchaînement.

Enfin, nous avons dû trouver les emplacements de tous les éléments qui composent la citrouille (le corps, la tige et le visage). Ce processus a été très long et a nécessité de nombreux essais mais nous y sommes arrivées !

Sources :

Pour écrire ce script, nous avons utilisé nos connaissances ainsi que le site python.org pour trouver de nouvelles commandes en python. Nous avons également regardé des projets de l’année dernière comme ceux qui sont dans la catégorie art.

Image finale :

Voici le rendu final de notre projet après avoir fait des tests, corrigé nos erreurs et pris du plaisir à coder !

Télécharger le script en .py :

Ne vous inquiétez pas, nous avons pensé à vous ! Vous pouvez télécharger le script ci-dessous pour vous amuser à le modifier ou tout simplement le montrer à vos amis !

Art

Voiture de course 2D

« La compétence naît de la détermination à passer du stade du novice à celui du débrouillard, forgeant ainsi le chemin de l’expertise »

Par où commencer ?

Dans un premier temps, il faut trouver un thème à dessiner.

Quoi de mieux que de dessiner quelque chose qui nous passionne ; L’automobile pour ma part.

C’est partie pour aller sur paint et essayer des motifs. Puis au bout d’une dizaine d’essais

puisque je ne suis pas un dessinateur professionnel, j’arrive enfin à quelque chose de sympa pour moi.

La Programmation.

Une fois mon modèle  prêt, il me reste plus qu’à passer au codage !

La partie noire de ce projet pour moi, mais aussi la plus importante.

J’appréhendais ce moment en tant que débutant, j’avais seulement les simples bases de python et je me demandais comment j’allais faire, mais je me suis rappelé.

« La compétence naît de la détermination à passer du stade du novice à celui du débrouillard, forgeant ainsi le chemin de l’expertise. »

La première ligne était inefficace, mais au fil du codage, je commençais peu à peu à être en confiance.

Le châssis.

La partie la plus facile, mais la plus déterminante pour la suite.

Je commence par définir la fonction  « châssis » et au bout de quelques essais, j’arrive enfin à un début de dessin.

Ma première boucle for.

Pour ajouter des petits détails à ma voiture, j’ai décidé d’essayer de faire deux suspensions avec ma première boucle « for i in range »

Au début message d’erreur sur message d’erreur, mais grâce à la persévérance, j’ai réussi ma première boucle for qui m’a redonné motivation à continuer tout en m’apprenant les bases du python.

Un segment verticale où 4 cercle de diamètre 10 se déplace vers le haut de 7 sur l’axe de (y) à chaque range.

Code amortisseur:

def amortisseur():
    forward(35)
    Y =int(-155)
    for i in range(4):
        up()
        goto(360,Y)
        down()
        pencolor(Rouge)
        pensize(2)
        circle(10)
        up()
        Y = Y+7

On continue sur les boucles for.

Pour continuer, j’ai décidé d’ajouter un peu de contraste au dessin grâce à l’amélioration de mon codage que j’ai pu acquérir au cours du projet.

Au niveau des roues , j’ai ajouté des jantes à bâton avec la fonction (for i in range()) tout en rajoutant quelques détails comme la fumée au niveau de l’échappement et l’aileron a l’arrière de la voiture.

Code fume :

 def fume():
    Y=int(170)
    X=int(20)
    P=int(10)
    pensize(2)
    pencolor(black)
    for i in range(5):
            up()
            goto(Y,X)
            down()
            circle(P)
            X = X+10
            P = P+1
            for i in range(P):
                up()
                goto(Y,X)
                down()
                circle(P)
                Y= Y+8
                
    
print(fume())

Rendu final.

J’ai commencé ce projet en appréhendant mon niveau en code python.

Mais au fil des nombreuses fonctions définit et de nombreux essais, j’ai réussi à monter en niveau :

Au début, j’arrivais juste à donner des instructions à la tortue.

Pour finir par des boucles avec des instructions.

Donc ce projet m’a permis d’évoluer autant sur moi que mon niveau python m’apprenant qu’avec de la persévérance, on arrive à tous ou presque.

L’image n’est pas superbe, mais montre l’évolution Du débutant en herbe à l’expert débrouillard de python.

Vidéo du projet:

Télécharger le code :

Art

Sous les Rayons d’Or ; l’Arabie saoudite

L’art génératif est une fusion fascinante entre la créativité humaine et la puissance des algorithmes informatiques, nous vous invitons à plonger dans un univers où la machine devient artiste, créant des œuvres d’une beauté unique et imprévisible.

Notre Projet

Pour ce premier projet de NSI, nous avons décidé de représenter la ville de Riyad en python. Par conséquent, notre image rentre dans le thème de l’Architecture. Nous avons réalisé une ville assez moderne, avec des bâtiments de toutes formes et un soleil hors du commun, notre but étant de faire ressortir la ville luxueuse de Riyad, tout en apportant notre petite touche d’originalité. La vrais question étant comment nous sommes passé d’une simple idée à un résultat splendide ?

Les différentes étapes de la création de l’image

Pour être arrivé à notre résultat final, nous sommes passé par 4 étapes;

Tout d’abord voici le script python qui nous a permis d’obtenir un fond innovateur, les couleurs n’ont pas été choisi par hasard, en effet nous avons souhaité créer une ambiance qui évoque l’originalité sans oubliée le luxe notamment avec des arrondie et un dégradée de couleur reflétant l’étendue de la ville. Nous avons dans un premier temps définie la fonction disque pour dessiner un disque, rayon pour définir la taille des disques, x et y pour les coordonnées du centre et pour le dégradé de couleur nous avons fait appel a Background-color, enfin nous avons utilisé les fonctions arrondi_gauche et arrondi_droit pour dessiner des parties d’arcs.

def disque(rayon, x, y, couleur=(1, 1, 1)):
    penup()
    goto(x, y-rayon)
    pendown()
    pencolor(couleur)
    fillcolor(couleur)
    begin_fill()
    circle(rayon)
    end_fill()
    

x, y = (0,-250)
radius = (700)
color = ("#FA1D65")
disque(radius, x, y, color) 
t    
x, y = (0,-250)
radius = (600)
color = ("#F72367")
disque(radius, x, y, color)     

   
x, y = (0,-250)
radius = (500)
color = ("#F02E6B")
disque(radius, x, y, color)

x, y = (0,-250)
radius = (400)
color = ("#EA3970")
disque(radius, x, y, color)     

x, y = (0,-250)
radius = (300)
color = ("#E73F72")
disque(radius, x, y, color)

def arrondi_gauche():
    for i in range(120):
        left(1)
        forward(5/40)
        
def arrondi_droit():
    for i in range(100):
        right(1)
        forward(5/80)

Le fond est certes beau, mais nous n’avions toujours pas trouvée cette touche de beauté supplémentaire, c’est ce pourquoi nous avons rajouté des étoiles, nous avons utilisé un code python assez simple. Nous avons commencée par définir une nouvelle fonction étoile, puis nous avons placés 125 points grâce à la boucle for i in range ces points sont placés aléatoirement grâce à randint.

def etoile():
    pensize(1)
    pencolor("white")
    for i in range(125):
        penup()
        x,y = randint(-700,700), randint(-0,700)
        goto(x,y)
        pendown()
        circle(1)

Il est désormais temps de passer, au bâtiment, pour ce qui est des bâtiments nous avons voulus représenter des grattes ciel luxueux de différentes formes, pour ce faire nous avons créer des fonctions bat 1, bat 2 etc … nous avons ensuite définis leur largeur, longueur et hauteur jusqu’à que les bâtiments ressemble à la forme qui nous convenais et enfin nous les avons placés à des endroits différents.

def bat1(longueur,largeur, couleur=(1,1,1)):
    pendown()
    pencolor(couleur)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    right(90)
    forward(longueur/1.5)
    left(90)
    forward(longueur/2)
 
def bat5(longueur, largeur, couleur=(1,1,1)):
    etage(longueur, largeur/5)
    etage(longueur/2 , largeur/5)
    etage(longueur/3 , largeur/5)
    left(80)
    forward(longueur/2)

def etage(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)

def etage_inverse(longueur, largeur, couleur=(1,1,1)):
    forward(largeur)
    left(270)
    forward(longueur)
    left(90)
def bat5_inverse(longueur, largeur, couleur=(1,1,1)):
    right(160)
    forward(longueur/2)
    left(80)
    etage_inverse(longueur/3, largeur/5)
    etage_inverse(longueur/2 , largeur/5)
    etage_inverse(longueur, largeur/5)

def bat3(longueur, largeur, couleur=(1,1,1)):
   forward(longueur/3)
   left(90)
   forward(longueur)
   right(90)
   forward(largeur)
   right(90)
   forward(longueur/4)
   left(90)
   forward(largeur)
   right(90)
   forward(longueur/2)
   
def bat4(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(largeur/3)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    left(90)
    forward(longueur-30)
    right(90)
    forward(largeur+25)
    right(90)
    forward(longueur+20)
    
def bat2(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(largeur)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    right(90)
    forward(longueur/2)
    left(45)
    forward(longueur/5)
    right(225)
    forward(longueur/8)
    right(90)
    forward(largeur+8)
    right(90)
    forward(longueur+8)

def bat6(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(largeur)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    left(90)
    forward(longueur/3)
    right(90)
    forward(largeur)
    right(90)
    forward(longueur-130)
    left(90)
    forward(largeur)
    right(90)
    forward(longueur-50)
    left(35)
    forward(largeur*2)
    right(35)
    forward(longueur-75)

penup()
fillcolor("#313131")
begin_fill()
goto(-630,-450)
goto(-630,-450)
bat1(60,30, couleur=("#313131"))
bat5(150,80 , couleur=("#313131"))
bat5_inverse(150,80 , couleur=("#313131"))
bat3(100,50, couleur=("#313131"))
bat4(100,40, couleur=("#313131"))
bat2(180,65, couleur=("#313131"))
bat6(165,35, couleur=("#313131"))
left(90)

right(90)
bat4(150,50, couleur=("#313131"))
left(90)
bat3(150,50, couleur=("#313131"))
pendown()
goto(630,-460)
goto(-630,-450)
end_fill()

Enfin, il manquait la structure la plus importe, le soleil pour, le soleil on a imaginé un soleil assez original, nous l’avons d’abord dessinée, puis nous l’avons ensuite codée en python, pour ce faire nous nous sommes aidés du concours NumWorks et nous avons utilisé une boucle avec un pas de 1 qui dessine le soleil avec les instructions de forme et de taille donnés.

from math import *
penup()
goto(0, 0)
pendown()

for r in range(20, 80, 1):
    penup()
    pensize(4 if r % 2 else 1)
    for a in range(361):
        d = r + 5 * cos(radians(12 * a))
        x = d * cos(radians(a))
        y = d * sin(radians(a))
        goto(x, y)
        pendown() 
        

Image final

Les problèmes rencontrés

Il faut savoir que cette image n’est pas aussi facilement réalisable qu’elle ne le paraît, en effet nous avons rencontrés énormément d’obstacle à la création de cette image, notamment lorsque les bâtiments on été créer les tailles on été difficilement ajustable, nous avons dus rajouter plusieurs paramètres pour ajuster la taille des bâtiments ce qui nous a pris plusieurs heure. Nous avons également rencontrés de nombreux code d’erreur heureusement que toute les ressources étais à notre disposition, au final il suffisait de lire.

Notre ressentis sur ce premier projet

Nous avons beaucoup aimé ce premier projet, nous avons pris du plaisir à réaliser le projet, c’est une belle expérience et un coup de coeur, j’ai énormément appris en python pendant ses vacances et je trouve que ce qui est magique c’est d’apprendre en prenant du plaisir.

Télécharger le .py

Art

L’engrenage du temps

Dans notre projet de NSI de Novembre 2023, nos enseignants nous ont demandé de créer un programme informatique qui génère une image , en se concentrant sur le concept d’art génératif.

Présentation du sujet:

Partant du tableau des 42 thèmes abordés en classe, notre attention s’est focalisée sur la pendule, symbole puissant du temps. À partir de là, l’idée centrale du projet a émergé : “L’engrenage du temps” visant à représenter à l’aide de turtle notre image du temps .

Sur la représentation que nous avons, on peut observer plusieurs composants tels qu’une pendule, un engrenage, un dégradé et un disque. Nous allons les examiner en détail au fil de la présentation.

Analyse du script:

Le fond : 

def degradé():
    turtle.colormode(255)
    turtle.speed(0)
    global compt
    global fr
    global fg
    global fb
    while compt != 350 :
        turtle.pendown()
        turtle.pencolor(fr, fg, fb)
        turtle.pensize(3)
        turtle.forward(510)
        turtle.penup()
        turtle.right(180)
        turtle.forward(510)
        turtle.right(90)
        turtle.forward(1)
        turtle.right(90)
        fr += 1
        fg += 1
        fb += 1
        compt += 1
        if compt > 200:
            fr -= 1
            fg -= 1
            fb -= 1           

Pour commencer, nous avons programmer le fond avec un dégradé allant du noir au gris.

Dans la fonction dégradé il y a une boucle qui se répète 350 fois dans laquelle la tortue dessine ligne après ligne le dégradé en indentant les variables r,g,b de 1 a chaque ligne sans jamais dépasser la valeur 200.

Engrenages:

def n_engrenage(trait):
    turtle.left(90)
    turtle.forward(trait * 2)
    turtle.right(45)
    turtle.pencolor(couleur)
    turtle.pensize(8)
    turtle.fillcolor(couleur)
    turtle.begin_fill() 
    for i in range(12):
        turtle.forward(trait)
        turtle.right(120)
        turtle.forward(trait)
        turtle.left(90)
    turtle.end_fill()

La fonction “n_engrenage” dessine l’ engrenage à l’aide du module turtle.

La boucle “for” fait répéter 12 fois une suite d’instructions qui dessinent l’engrenage puis la fonction “turtle.fillcolor” viens définir la couleur de remplissage de l’engrenage qui débute et se finit grâce aux fonctions  “turtle.begin_fill” et “turtle.end_fill”.

Pendule: 

def disque(rayon, x, y, couleur=(1, 1, 1)):
    penup()
    goto(x, y - rayon)
    pendown()
    pencolor(couleur)
    fillcolor(couleur)
    begin_fill()
    circle(rayon)
    end_fill()

x = 25  
y = 175
radius = 30
color = (255, 255, 0)  

disque(radius, x, y, color)

import turtle

pen = turtle
pen.penup()
pen.goto(65, 190)
pen.pendown()
pen.pencolor("black")
pen.goto(175, 350)

import turtle #fonction courbe

t = turtle

t.penup()
t.goto(90,173)
t.pendown()
t.right(50)
for i in range(55):
    t.forward(1)
    t.right(1)


import turtle #fonction courbe 2

t2 = turtle

t2.penup()
t2.goto(100,180)
t2.pendown()

t2.right(290)
for i in range(75):
    t2.forward(1)
    t2.right(1)


turtle.hideturtle()

Pour fabriquer la pendule, nous avons commencé avec un plan donné par nos professeurs de NSI. Il comportait plusieurs disques placés de façon aléatoire. Ensuite, nous l’avons simplifié en utilisant les instructions « begin_fill() » et « end_fill() » pour remplir les disques. Ensuite, nous avons ajouté une simple ligne en spécifiant un point de départ et un point d’arrivée. Enfin, nous avons inclus deux courbes pour donner l’impression que la pendule bougeait.

Les problèmes rencontrés:

Parmis les nombreux problèmes rencontrés il y avait que l’exécution de la fonction dégradé prenait très longtemps a finir de s’exécuter (env 1min), pour ne pas perdre temps à relancer tout le code a chaque modification on a trouvé la solution de mettre un “#” devant la ligne qui exécutait la fonction dégradé ce qui permettait de faire passer cette ligne pour un commentaire et de simplement enlever le  # quand on voulait exécuter le script complet.

L’image final:

Art

Musique : The neighbourood wiped out !

En tant qu’admiratrices de l’album « wiped out ! » du groupe The Neighbourood, notre premier projet en NSI prend une dimension passionnante puisqu’on a choisi de représenter la pochette de cet album qui nous tient particulièrement à coeur.

Le commencement

Pour commencer, nous avons réalisé le fond noir et le cercle blanc qui se situe au centre. Nous avons ensuite placé le texte avec la bonne police d’écriture et la bonne taille au-dessus du cercle blanc. Nous devions aussi reproduire une petite maison à l’envers tout en bas de l’image en commençant par la base puis la cheminée et enfin le toit.

Les vagues et le sol

Pour créer les vagues, nous avons utilisé deux boucles for. Une première boucle sert à dessiner les arcs de cercle qui forment une ligne de vagues, puis une deuxième boucle permet de déplacer la tortue vers le bas pour dessiner la ligne de vagues suivantes. Cette approche répétitive nous permet de créer un motif de vagues continus en descendant d’une ligne à l’autre.

pensize(10)
goto(-300,0)
color("black")
pendown()
setheading(-35)

for i in range(9):
    for j in range(11):
         circle(35, 70)
         circle(-35, 70)
    penup()
    goto(-300, -20 * (i+1))
    pendown()

Il nous fallait aussi un sol qu’on a obtenu grâce à de nombreux cercles pour pouvoir ensuite déplacer la maison.

Le palmier avec les roches

Pour le palmier, on a d’abord dessiné des arcs de cercle pour créer le tronc incliné du palmier puis on a dessiné chaque feuille en utilisant la commande circle() avec des angles spécifiques pour créer la forme des feuilles. Les pierres ont été créées en combinant des formes géométriques superposées les unes aux autres.

L’oiseau

Pour dessiner un l’oiseau, on a dû crée les ailes, le corps, la queue, le bec et la tête de l’oiseau en utilisant des boucles, des lignes et des cercles.

Notre petite touche personnelle

Pour finir, on a rajouté notre petite touche personnelle, un ciel étoilé. Nous avons défini une fonction étoile pour générer 30 étoiles à des emplacements aléatoires.

def etoile():
    
    for i in range(5):
        forward(0.5)



pensize(2)
pencolor("white")

for i in range(30):
    x = randint(-400, 400)
    y = randint(100, 300)
    penup()
    goto(x, y)
    pendown()
    etoile()

CONCLUSION

Ce projet nous a permis de réaliser qu’on peut faire de très belle chose juste en ayant les bases de la programmation. On a pris beaucoup de plaisir à voir notre image se construire au fur et à mesure du temps. Cela nous a ouverts de nouvelles perspectives pour des projets futurs et nous avons hâte d’en apprendre davantage pour réaliser des créations encore plus techniques et impressionnantes.

RENDU FINAL

télécharger le .py

Art

Paysage japonais

Un paysage où un monument de la culture japonaise se mélange avec un fond naturel est magnifique. Et bien que le Japon soit le pays du soleil, levant nous allons le mettre en valeur avec, cette fois-ci, la lune, à travers des montagnes et des torii. Ces derniers symbolisent un portail entre l’enceinte sacrée et l’environnement profane. C’est pour cette raison qu’il y en a à l’entrée de certains sanctuaires.

Organisation du script

Notre script sera expliqué par étape, de l’arrière plan au premier. La fonction goto sera beaucoup utilisée afin de faire des tracés contrôlés ainsi que pensize() pour la largeur du tracé du stylo, color() pour choisir la couleur du crayon, circle() pour faire un cercle et for i in range pour faire des boucles.

L’arrière-plan

from turtle import*    
pensize (42)    
color("#FFFFFF")

a = -40   
col = ["#FFFFFF","#9BF7F7","#41F9FF","#00CDFF","#008FFF","#0059FF","#003AFF", "#4D00FF","#33079A", "#000000"]    
nb_col = len(col)    
color("#FFFFFF")   
goto(0, 50)    
circle(40)

a = 0  

for i in range (0,10,1):
    goto(0, 40-a)
    color(col[i%nb_col])
    circle(40+a)
    a = a +30
    goto(0, 40-a)
    circle(40+a)
    a = a +30
    goto(0, 40-a)
    circle(40+a)
    a = a +40

Ici, nous montrons que notre script est importé de Turtle, ce module nous permettant de contrôler un crayon pour tracer diverses formes géométriques.

Le fond de notre code n’est pas centré mais c’est fait exprès. Nous avons donc mis la taille du crayon à 42 avec la fonction : pensize (42), ensuite a = -40 nous a servis à déplacer le centre du cercle de base, soit, dans notre cas de le décaler vers la haut. Puis nous avons listé les différentes couleurs utilisées dans tous ces cercles avec col = [ ]. Le goto(0, 50) nous emmènera ensuite aux coordonnées données (donc (0, 50)) puis tracera des cercles de différentes tailles et de différentes couleurs grâce à la fonction cercle circle(40) et à la boucle for i in range (0,10,1):.

Les premières montagnes

color("#42392C")
goto(0, -80)
goto(100, 90)
goto(150,80)
goto(230,150)
goto(270,250)
goto(300,150)
goto(500,20)
goto(580,30)
goto(630,10)
goto(640,-40)
goto(0,-80) 

goto(0, -40)
goto(100,50)
goto(120,40)
goto(200,100)
goto(320,250)
goto(500,30)
goto(580,-10)
goto(630,20)
goto(640,-80)
goto(0,-70) 

goto(0, -40)
goto(120,40)
goto(200,80)
goto(320,230)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-60)
goto(0,-50) 

goto(0, -40)
goto(120,33)
goto(200,60)
goto(320,210)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-40)
goto(0,-20) 

goto(0, -40)
goto(120,20)
goto(200,50)
goto(320,190)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-30)
goto(0,-10) 

goto(0, -40)
goto(120,00)
goto(200,20)
goto(320,170)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-10)
goto(0,-00) 

goto(0, -40)
goto(120,00)
goto(200,10)
goto(320,160)
goto(580,00)
goto(630,000)
goto(640,-10)
goto(0,-00)  

goto(320,70)
goto(500,50)
goto(320,60)
goto(320,40)
goto(320,50)
goto(320,30) 

goto(0,-10)
goto(-200,50)
goto(-300,10)
goto(-430,160)
goto(-500,15)
goto(-600,250)
goto(-600,-10)

Nous comprenons ici que les goto sont et seront à l’honneur de ce script ! Ils sont simples à utiliser et donc à comprendre. La couleur des premières montagnes, elle, est encore une fois définie par color(« #42392C »).

Voici le résultat de tous ces goto ! Nous avons un début de montagne avec quelques imperfections mais pas d’inquiétudes ! Ce script fonctionne par plan donc comme un pochoir. Ici, les goto ont donc servis à diriger le stylo d’un point à un autre jusqu’à ce que nous ayons ce résultat

Encore des montagnes

color("#6F6556")
goto(0, 0)
goto(80,40)
goto(120,00)
goto(200,10)
goto(430,200)
goto(630,0)
goto(0,-00)

goto(0, 0)
goto(200,0)
goto(430,180)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(430,160)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(430,150)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,150)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,140)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,130)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,120)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,110)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,100)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,90)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,80)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,70)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,60)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,60)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,50)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,40)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,40)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,30)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,20)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,10)
goto(630,0)

goto(0,0)
goto(0,-10)
goto(-200,30)
goto(-300,00)
goto(-400,150)
goto(-500,5)
goto(-600,200)
goto(-600,-10)
goto(0,0)

Ces montagnes sont faites de la même manière que les premières : le changement de couleur avec color(« #6F6556 ») et les goto ! Voyons maintenant le résultat en image…

Et voilà nos montagnes finies ! Mais il reste encore quelques étapes pour donner un sens à notre titre.

Le sol bleu

up()
goto(0,-400)
down()
col = ["#000000","#33079A","#4D00FF", "#003AFF", "#0059FF","#008FFF", "#00CDFF", "#41F9FF","#9BF7F7", "#FFFFFF","#9BF7F7","#41F9FF","#00CDFF","#008FFF","#0059FF","#003AFF","#4D00FF","#33079A","#000000"]
nb_col = len(col) 
recup = 0
k = -50
for i in range (0,50):
    color(col[i%nb_col])
    for i in range (0,3):
        k += 40
        goto(1000-k,-35)
        goto(1300-k,-500)

Comme pour l’arrière-plan, les couleurs sont définies grâce à col = [ ].

Avec l’image, nous pouvons plus facilement comprendre la présence de la boucle for i in range (0,50) qui nous a aidé à répéter tous les traits positionnés en diagonale pour nous éviter de les faire un à un avec des goto par exemple !

Les torii

pensize(42)
up()
goto(160,-220)
down()

color("#FF7000")
goto(160,100)
goto(-160,100)
goto(-160,-220)
goto(-160,100)
goto(-220,100)
goto(220,100)
goto(160,100)
goto(160,160)
goto(160,100)
goto(-160,100)
goto(-160,160)
goto(-220,160)
goto(220,160)

pensize(25)
up()
goto(80,-150)
down()

color("#E76E00")
goto(80,20)
goto(-80,20)
goto(-80,-150)
goto(-80,20)
goto(-120,20)
goto(120,20)
goto(80,20)
goto(80,60)
goto(80,20)
goto(-80,20)
goto(-80,60)
goto(-120,60)
goto(120,60)

pensize(12)
up()
goto(40,-120)
down()

color("#CB6100")
goto(40,-30)
goto(-40,-30)
goto(-40,-120)
goto(-40,-30)
goto(-60,-30)
goto(60,-30)
goto(40,-30)
goto(40,-10)
goto(40,-30)
goto(-40,-30)
goto(-40,-10)
goto(-60,-10)
goto(60,-10)

pensize(6)
up()
goto(20,-100)
down()

color("#A95100")
goto(20,-60)
goto(-20,-60)
goto(-20,-100)
goto(-20,-60)
goto(-30,-60)
goto(30,-60)
goto(20,-60)
goto(20,-50)
goto(20,-60)
goto(-20,-60)
goto(-20,-50)
goto(-30,-50)
goto(30,-50)

Voici le code de nos torii. A chaque nouveau pensize( ), il y en a un nouveau ! Nous avons d’abord le placement du crayon avec up( ), goto( ) et down( ) dans cet ordre là. Cela permet de se déplacer en décidant quand nous voulons écrire.

Cette fois-ci, l’image est sans le fond pour mieux observer le choix de couleur ainsi que les tailles décroissantes.

Le résultat final

Et enfin, notre résultat ! Nous avons également rajouté deux ligne, une verte et une marron pour montrer le début des montagnes mais ces lignes servent aussi à cacher la délimitation qu’il y avait pour les traits droits en diagonale.

Télécharger le .py