Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

wiki:mpls:processing-avec-python [2019/12/03 10:38] (Version actuelle)
Ligne 1: Ligne 1:
 +====== Processing avec python ======
 +
 +===== Initiation à la programmation en python avec Processing.py =====
 +
 +L'​activité proposée consiste à s'​initier à la programmation avec le langage //python// en exploitant un contexte particulier favorisant la réalisation de créations artistiques numériques. [[http://​processing.org|Processing]] est un projet né de la volonté de faciliter la création d'​oeuvres numériques interactives à destination d'​artistes,​ pas nécessairement informaticiens. Ce projet a été développé avec le langage //Java//, mais suite à son succès et au besoin d'​utiliser les créations dans différents contextes (particulièrement web), des déclinaisons dans d'​autres langages de programmation sont apparues, comme [[http://​p5js.org|P5.js]] (//​JavaScript//​) et plus récemment [[http://​py.processing.org/​|Processing.py]] (//​python//​).
 +
 +//python// étant utilisable de manière plus souple que //Java// (concepts orientés objects incontournables pour ce dernier), il nous a semblé plus judicieux d'​opter pour ce langage pour une initiation aux bases de la programmation. Le choix de //​Processing//​ repose sur la volonté de présenter l'​activité de programmation comme un outil fantastique d'​expression permettant de créer des objets numériques (interactifs).
 +
 +L'​atelier proposé est structuré en deux parties:
 +  * un premier temps permettant d'​introduire progressivement les concepts fondamentaux de la programmation,​
 +  * un second temps orienté vers la résolution de problèmes en s'​attaquant à la réalisation de différentes "​oeuvres numériques"​ :)
 +
 +===== Premier temps: initiation aux bases de la programmation avec Processing =====
 +
 +Plutôt qu'une présentation formelle et conceptuelle,​ nous vous proposons de procéder à un apprentissage dirigé par des exemples afin de favoriser la mise en oeuvre pratique dès l'​introduction des premiers concepts. ​
 +
 +==== Notion d'​instruction,​ de séquence d'​instructions,​ de variable et d'​affectation ====
 +
 +Voici donc un premier exemple de programme avec Processing.py:​
 +
 +{{url>​https://​trinket.io/​embed/​python/​c71c0a8b78 100%,356px noscroll noborder}}
 +
 +Ce premier exemple permet déjà d'​illustrer de nombreuses notions de programmation :
 +  * d'​abord,​ on constate que différentes couleurs embellissent le code source. En particulier,​ les lignes apparaissant en vert correspondent à des phrases en langage naturel et donc à destination des humains et pas de la machine. Ce sont des **commentaires** et la machine les détectent car il y a le caractère ''#''​ en début de ligne et les ignorent totalement.
 +  * en tout début de programme, plusieurs lignes débutent par le mot ''​from''​. Cela correspond à l'//​importation//​ de fonctions existantes (ici, de fonctions mathématiques de base et de celles liées à l'​usage de Processing). Dans la suite de cette activité, **il faudra toujours débuter vos programmes par ces deux lignes** :)
 +  * à l'​opposé,​ tout à la fin du programme, il y a l'​expression ''​run()''​. Cela correspond à l'​appel d'une fonction existante (dans Processing). Les parenthèses ont leur importance : c'est ce qui permet de transmettre ou pas des informations à une fonction. Ici la fonction ''​run''​ ne nécessite pas d'​information particulière,​ elle ne possède donc pas de //​paramètre//​. Dans la suite de cette activité, **il faudra toujours terminer vos programmes par cet appel à la fonction ''​run''​** qui déclenche l'​exécution de Processing, ou plus précisément qui va appeler la fonction ''​setup''​.
 +  * concentrons-nous maintenant sur ce qui nous permet de définir une nouvelle fonction : ''​def setup():''​. Le mot-clé ''​def''​ permet d'​indiquer la définition d'une nouvelle fonction qui se nommera ici ''​setup''​ et qui ne nécessite pas de paramètre. **ATTENTION** : les '':''​ font partie de la //syntaxe// de définition d'une fonction, il ne faut pas oublier de les mettre après la parenthèse fermante !
 +    * les lignes suivantes constituent le //corps// de la fonction et décrivent le traitement qu'​elle réalise.
 +    * **ATTENTION** : contrairement à d'​autres langages utilisant des symboles particuliers pour indiquer le début ou la fin d'une fonction (comme ''​{''​ et ''​}''​ en //Java// par exemple), //python// repose juste sur //​l'​indentation//​ c'​est-à-dire l'​introduction d'un décalage permettant d'​identifier les instructions appartenant au corps de la fonction.
 +
 +Assez de théorie : **appuyez sur le bouton ''​Run''​** afin de voir ce que produit ce premier programme :)
 +
 +Sans connaître Processing, le nommage des fonctions permet d'en déduire assez facilement leur comportement. Par contre, il peut-être plus délicat de déduire la signification des différents paramètres. Pour rendre l'​algorithme plus lisible, nous allons introduire quelques //​variables//​ qui expliciteront ce à quoi correspondent les différents paramètres des différentes fonctions.
 +
 +{{url>​https://​trinket.io/​embed/​python/​6cd8ca45a3 100%,356px noscroll noborder}}
 +
 +Une variable permet de stocker une information et comme vous le constatez en python, il n'est pas nécessaire de préciser la nature de l'​information (i.e. le //type//). Contrairement à une variable mathématique,​ il est possible de changer la valeur de la variable lors du déroulement de l'​algorithme et surtout le symbole ''​=''​ ne correspond pas à la notion d'​égalité,​ mais à l'​affectation,​ c'​est-à-dire l'​opération permettant de stocker une valeur dans une variable.
 +
 +Il existe aussi un certain nombre de variables prédéfinies dans Processing auxquelles vous pouvez accéder directement. Par exemple, la taille de l'​écran définie grâce à la fonction ''​size(width,​ height)''​ initialise des variables correspondantes ''​width''​ et ''​height''​ que vous pouvez utiliser ensuite dans votre algorithme pour paramétrer vos dessins par rapport à la taille de la zone de dessin.
 +
 +Nous allons maintenant examiner l'​algorithme ci-dessous. A votre avis, que va-t-il se produire ? Vérifiez votre intuition en exécutant le programme.
 +
 +{{url>​https://​trinket.io/​embed/​python/​0ad597cb1b 100%,356px noscroll noborder}}
 +
 +**Surprise ?!** L'​algorithme appelle trois fois la fonction ''​ellipse''​ mais seules deux ellipses apparaissent ! **Pourquoi ?**
 +Modifiez l'​algorithme ci-dessus afin que trois disques soient dessinés, chacun décalé de 50 pixels vers le bas et la droite ?
 +
 +Ceci illustre une utilisation importante et récurrente de la notion de variable : la notion d'​accumulateur. En effet, il est souvent pratique de réutiliser la même variable pour la faire évoluer en fonction de sa valeur actuelle. Assurez-vous d'​avoir exploité cette notion d'​accumulateur (c'est le cas si les variables ''​x''​ et ''​y''​ sont les seules à apparaître pour les deux premiers paramètres de la fonction ''​ellipse''​.
 +
 +==== Première structure de contrôle : notion de répétition ====
 +
 +Même si votre algorithme fonctionne, un informaticien ressentirait sûrement une certaine frustration face à une solution faisant appel trois fois à la même fonction. Plus précisément,​ c'est le fait d'​avoir une forte redondance qui est frustrant et il est probable que l'on puisse supprimer cette redondance. Pour cela, il faudrait pouvoir //effectuer le dessin d'un disque trois fois// (en faisant varier l'​origine du disque). Afin de pouvoir effectuer de tels répétitions,​ nous avons besoin d'​exprimer ce qui doit être répété et le nombre de fois qu'il faut effectuer la ou les actions.
 +
 +La structure de contrôle ''​for x in range(from, to[, step]):''​ permet de répéter ''​(to-1-from)''​ fois les instructions contenues dans le corps de la boucle (éventuellement avec un pas (//step//) différent de 1). En fait, la fonction ''​range''​ énumère les éléments à partir de la valeur ''​from''​ jusqu'​à la valeur ''​to''​ exclue. Il est aussi possible d'​énumérer en extension les éléments à parcourir avec la syntaxe suivante: ''​for x in [0, 50, 100]:''​. Les éléments à parcourir sont définies à l'​intérieur d'une //liste//, une des structures de données les plus utilisées avec les //​dictionnaires//​ (presque le même sens que l'​usage usuel ;)).
 +
 +{{url>​https://​trinket.io/​embed/​python/​7f7dd85014 100%,356px noscroll noborder}}
 +
 +Maintenant que les principales notions d'​algorithmique ont été présentées (instruction,​ séquence d'​instructions,​ variable et affectation,​ répétition... il ne nous manque plus que l'​alternative et la notion de fonction !), passons à la création de quelques dessins.
 +
 +** Dessinons (le début d')un quadrillage **
 +
 +On souhaite dessiner le début d'un quadrillage comme l'​illustre la figure ci-dessous ([[https://​trinket.io/​python/​3213a1b4d4|solution]]):​
 +
 +{{ :​wiki:​mpls:​processing:​quadrillage1.png?​200 |}}
 +
 +{{url>​https://​trinket.io/​embed/​python/​1ac2bb978a 100%,356px noscroll noborder}}
 +
 +** Dessinons un quadrillage **
 +
 +Comment faut-il modifier légèrement l'​algorithme ci-dessus afin de produire un quadrillage en deux dimensions comme l'​illustre la figure ci-dessous ([[https://​trinket.io/​python/​d8890cd5ed|solution]]) ? 
 +
 +{{ :​wiki:​mpls:​processing:​quadrillage2.png?​200 |}}
 +
 +==== Processing : passage en mode cinéma pour les animations ====
 +
 +Nous avons pour l'​instant réalisé des dessins non animés. Or, Processing est plutôt destiné aux oeuvres numériques interactives. Afin de produire ces animations, Processing repose sur le même principe que l'​animation classique. Chaque plan est dessiné séparément et les plans sont affichés successivement à raison de 25 images par seconde. Pour ce faire, Processing définit la fonction ''​draw''​ qui est appelée automatiquement tous les 25ième de seconde (par la fonction ''​run''​),​ ce qui permet de rafraîchir la zone graphique et produire une animation. Voici un exemple simple :
 +
 +{{url>​https://​trinket.io/​embed/​python/​7865068eba 100%,356px noscroll noborder}}
 +
 +Dans cet exemple, on demande que la fonction ''​draw''​ soit appelée tous les 1/4 de seconde (cf. ''​frameRate(4)''​),​ et l'on dessine un carré avec pour origine (le coin supérieur gauche) la position en temps réel du pointeur de la souris déterminée grâce aux fonctions ''​mouseX''​ et ''​mouseY''​. Comme l'on ne demande pas à effacer la zone graphique, les carrés s'​affichent les uns au dessus des autres. Que suffirait-il de modifier dans le programme ci-dessus pour donner l'​illusion du déplacement d'un carré en fonction du positionnement de la souris ?
 +
 +Cet exemple nous amène à expliquer une nuance éludée précédemment concernant la notion de variable. En effet, maintenant que nous disposons de deux fonctions (''​setup''​ et ''​draw''​) pour nos créations, la question d'un partage d'​information entre ces deux fonctions devient nécessaire. Ainsi, en supposant que l'on souhaite faire varier la couleur du carré dans l'​exemple précédent de manière "​jolie",​ il faut disposer de la couleur précédente pour calculer la couleur que prendra le carré afin de produire un dégradé. Si l'on définit une variable ''​rect_color''​ dans la fonction ''​setup'',​ cette variable n'​existera que lorsque la fonction ''​setup''​ sera en cours d'​exécution,​ dès que l'on passera à la fonction ''​draw'',​ elle sera détruite. En effet, une variable n'​existe que dans le bloc dans lequel elle est définie. Du coup, si l'on déplace la variable à l'​extérieur des fonctions ''​setup''​ et ''​draw'',​ cela devient une variable //​globale//,​ accessible depuis les deux fonctions ! L'​exemple ci-dessous illustre ce principe:
 +
 +{{url>​https://​trinket.io/​embed/​python/​3f98472b39 100%,450px noscroll noborder}}
 +
 +Si vous regardez ce qui se passe dans la //console// (petite zone située en dessous de la zone graphique), vous remarquerez que des nombres défilent : ils correspondent aux valeurs que prend la variable ''​rect_color''​. En attendant suffisamment longtemps, vous constaterez que l'on arrive à des valeurs négatives, ce qui n'est pas l'​idéal pour une composante de couleur qui est censée être définie dans l'​intervalle [0,255]... Ce problème va nous permettre d'​introduire la deuxième structure de contrôle : l'​alternative. En effet, il serait préférable de détecter la situation où une composante devient négative pour repartir dans l'​autre sens (et réciproquement lorsque l'on dépasse 255). Pour cela, nous avons besoin de la notion de //​condition//​ (une expression booléenne, c'​est-à-dire ne pouvant prendre que la valeur ''​true''​ ou ''​false''​) et de la notion d'​alternative,​ ''​if //​condition//: ​  else: '',​ permettant d'​exprimer des expressions du type "​**si** //condition est vraie// **alors** exécuter la première blanche, **sinon** exécuter la seconde branche"​. L'​exemple ci-dessous illustre l'​utilisation d'une alternative afin de garantir que l'on reste dans l'​intervalle valide pour une composante RGB :
 +
 +{{url>​https://​trinket.io/​embed/​python/​8e69b6a06a 100%,450px noscroll noborder}}
 +
 +Comme vous le constatez, lorsque la composante ''​r''​ arrive à 0, elle est réaffectée à 255 et l'on perçoit le changement de couleur qui revient au jaune.
 +
 +==== La notion de fonction ====
 +
 +Il ne manque nous manque plus maintenant que la notion de fonction pour disposer de la boîte à outils de base permettant déjà de nombreuses créations (il restera ensuite la programmation orienté objets ;)). Nous utilisons déjà deux fonctions prédéfinies par Processing ''​setup''​ et ''​draw'',​ que l'on redéfinit pour chaque programme. Lorsqu'​un traitement doit être effectué plusieurs fois, il peut être judicieux de le définir comme une nouvelle instruction,​ cela permet d'​enrichir le langage dont nous disposons pour exprimer nos algorithmes. La notion de fonction permet la définition d'​algorithmes réutilisables dans différents contextes.
 +
 +Une fonction est définie par son //nom//, sa //liste de ses paramètres//​ (si elle en a besoin) et son //corps// (les instructions qui décrivent ce que réalise cette fonction). Supposons que l'on souhaite disposer d'une instruction permettant de retourner une couleur choisit aléatoirement. Cette fonction ne nécessite pas de paramètre pour effectuer son traitement, qui repose sur le tirage aléatoire de trois entiers dans l'​intervalle [0,255] pour chacune des composantes RGB.
 +
 +{{url>​https://​trinket.io/​embed/​python/​5b25d803c9 100%,450px noscroll noborder}}
 +
 +Cet algorithme définit deux fonctions en plus des classiques ''​setup''​ et ''​draw''​ : la fonction ''​rnd(max)''​ et ''​rainbow()''​. La fonction ''​rnd''​ possède un paramètre indiquant la borne supérieure maximale (exclue) et a pour comportement de retourner un entier tiré aléatoirement dans l'​intervalle [0, max[. La fonction ''​rainbow''​ n'a pas de paramètre et utilise la fonction ''​rnd''​ afin de générer une couleur aléatoirement en tirant au hasard les trois composantes R, G et B. Finalement, la fonction ''​rainbow''​ est utilisé dans la fonction ''​draw''​ afin de changer la couleur lors de l'​affichage de chaque carré.
 +
 +Pour terminer sur cet exemple, voyons comment nous pourrions réinitialiser l'​affichage lorsque l'​utilisateur appuie sur une touche. Pour cela, il nous faut définir une fonction bien spécifique qui sera appelée automatiquement par Processing lorsque l'​utilisateur sollicitera une des touches du clavier : la fonction ''​keyPressed()''​ ou ''​keyPressed(event)''​.
 +
 +{{url>​https://​trinket.io/​embed/​python/​5b17714b6b 100%,450px noscroll noborder}}
 +
 +
 +===== Deuxième temps: vos propres créations ! =====
 +
 +Vous disposez maintenant de tous les éléments pour vous lancer dans vos propres créations :)
 +
 +Si vous souhaitez explorer les fonctions prédéfinies de Processing, il y a [[https://​processing.org/​reference/​|la référence disponible ici]].
 +
 +A vous de jouer !
 +