Profitez-en, après celui là c'est fini

Autofictif

novembre 29th, 2008 Posted in Lecture, Link-dropping | 9 Comments »

Un peu de littérature pour nous reposer de la programmation — même si la programmation n’a pas tout à fait rien à voir avec la littérature (bon sujet d’article futur, tiens).
Averti, si je m’en souviens, par le scénariste Appollo, j’ai découvert un jour l’existence de l’Autofictif, le blog d’Éric Chevillard. En attendant que Jean-Charles Massera crée son propre site, ça sera sans doute le seul blog d’écrivain que je suis sûr et certain de visiter quotidiennement. Il faut dire que Chevillard est d’une régularité extraordinaire. Chaque jour, qu’il pleuve, qu’il vente, ou qu’il neige, l’écrivain produit trois aphorismes. Beaucoup d’humour, mais aussi quelques phrases que l’on pourrait graver dans le marbre, qui évoquent la condition humaine ou qui semblent extraits d’un roman jamais paru.
Quelques exemples, pris (presque) complètement au hasard :

Je décris mon mal en faisant usage des termes médicaux appropriés, mais le médecin semble passablement agacé par ma maîtrise de sa langue en quoi consistait sans doute tout le soin qu’il comptait me prodiguer.

Comme un poisson dans l’eau. Dans la crainte perpétuelle du court-bouillon.

Il est fréquent de voir des comédiens vieillissants faire de la publicité pour des entreprises de pompes funèbres. Je serais fort curieux d’entendre l’argumentaire des agences qui les sollicitent.

Ma mort n’arrivera qu’aux autres.

Le violeur de l’ONU était bourguignon, titre le journal local, non sans chauvinisme.

Le pape croit en Dieu, évidemment. Mais, plus étonnant, on dirait bien qu’il croit aussi au pape. Alors pourtant que c’est lui, le pape ! Comment peut-on être dupe à ce point ? !

La mort est une survivance archaïque des époques barbares.

Il faudrait que je me tienne vraiment en très haute estime pour ne pas trouver légèrement excessive malgré tout la jubilation de ma fille à chaque fois que j’apparais.

Quand je me sens d’humeur maussade, je n’ai qu’à chatouiller ma fille. La brave petite ne refuse jamais de rire à ma place.

Le chat fait miaou, le coq fait cocorico, le chien fait ouah, le mouton fait bêêêê, la vache fait meuh, la girafe fait pouët.

Le langage rudimentaire des textos nous permet enfin de converser au téléphone avec les Australopithèques.

La Vierge m’est apparue il y a quelques jours, mais je ne suis pourtant pas si naïf et je m’étonne d’avoir gobé ça. Seule explication plausible : elle m’aura fait boire avant.

On confond souvent les chiens téléguidés, reliés à leur maître par un fil, et les chiens télécommandés qui obéissent aux ordres à distance.

Tu commandes une bière. Le garçon en énumère douze. Tu choisis avec une mine de connaisseur la seule dont tu as compris le nom.

L’éléphant qui te charge, renverse-le sur le dos ; il aura toutes les peines du monde à se relever, si seulement il y parvient. Et alors tu seras loin.

Voici donc à quoi se résume l’activité humaine : extraire l’or de la mine pour l’enfouir dans le jardin.

Les fantômes n’existent pas. Il n’y en a pas, il n’y en a jamais eu. C’est d’ailleurs ce qui rend leurs apparitions si effrayantes.

Bien présomptueux, le sot qui garde le silence.

Chacun de ses milliers d’aphorismes règle une fois pour toutes la question de l’homme et il n’y a plus à y revenir.

Tous les matins, je vais donc lire les trois aphorismes du jour, comme chaque midi je vais chercher le courrier dans ma boite-aux-lettres, c’est devenu un rite. Le site n’est pas spécialement beau à regarder et son flux rss tronque les paragraphes, mais ça reste toujours un plaisir de s’y rendre. L’auteur, malgré une douzaine de publications aux éditions de Minuit se présente régulièrement (toujours sur son site) comme un écrivain sans public ou à peu près. Son blog, si on l’en croit, a plus de lecteurs :

Cette page quotidienne rencontre un succès qui me vexe. Voudrait-on perfidement me faire savoir que mes travaux d’écritures ne sont lisibles qu’à dose homéopathique ?

Processing, neuvième cours

novembre 29th, 2008 Posted in Processing | 2 Comments »

Processing ne sert pas qu’à produire des images fixes, comme on l’a vu avec la fonction draw() que nous allons à nouveau employer ici.
Parmi les « sens » (les périphériques d’entrée) de processing, les deux plus évidents sont la souris et le clavier de l’ordinateur. Il en existe bien d’autres, accessibles directement ou par le biais de librairies externes : micro, webcam, réseau, etc. Pour l’instant, nous allons parler de la souris.
Une première chose à savoir est que la position de la souris sur un écran ou dans une fenêtre de programme est toujours relative au coin supérieur gauche de cet espace.

Les coordonnées de la souris

Ce simple exemple sera sans doute suffisamment éloquent :

void draw(){
  point(mouseX, mouseY);
}

Si vous saisissez ce code dans processing et que vous cliquez sur le bouton « play », un point noir sera dessiné sous votre curseur de souris, ce qui fait que vous dessinerez sur l’écran. Nous connaissons déjà la fonction draw(), qui est exécutée x fois par seconde, et la fonction point(x,y) qui dessine un point à l’emplacement (x,y). Ici, x et y sont remplacés par deux variables système, mouseX et mouseY qui sont, respectivement, la coordonnée horizontale de la souris (abscisse) et sa coordonnée verticale (ordonnée).
Nous pouvons remplacer le point par une ellipse, et repeindre la scène en noir à chaque cycle, afin que l’ellipse ne dessine pas sur la scène mais semble bouger avec la souris.

void draw(){
  background(0);
  ellipse(mouseX, mouseY,20,20);
}

Compliquons encore un peu plus notre programme en ajoutant un script setup :

void setup(){
   smooth(); noStroke();background(0);
}

void draw(){
  background(0);
  ellipse(mouseX, mouseY,20,20);
}

Cette fois, même résultat (une ellipse semble suivre la souris) mais l’affichage est amélioré puisque l’on a supprimé le trait de contour (stroke), peint la scène en noir dès le départ (background) et activé l’anti-aliasing (smooth). On aurait aussi pu changer la couleur de remplissage de l’ellipse, par exemple en écrivant dans le setup fill(255,0,0); (l’ellipse apparaîtrait alors en rouge).
On remarque au passage que Processing n’accepte comme coordonnées de la souris que des valeurs correspondant à la fenêtre d’affichage. Au passage, signalons que l’on peut masquer le curseur avec la commande noCursor();
La position de la souris peut être utilisée pour d’autres choses que pour faire bouger un objet, bien entendu. On peut par exemple demander que l’écran ait un fond d’une certaine couleur si la position verticale du curseur de la souris est inférieure à 50 pixels et d’une autre couleur sinon.

void draw(){
  if(mouseY<50){ background(255);} else { background(0);}
}

Au passage nous venons de découvrir une nouvelle fonction, le test conditionnel (if), qui permet d’agir d’une manière ou d’une autre en fonction d’un paramètre donné. Nous y reviendrons.
Les créateurs de Processing ont pensé à y ajouter deux variables système extrêmement utiles : pmouseX et pmouseY. Ces deux variables servent à stocker la position précédente de la souris. Si mon curseur se trouvait à (10,11) au moment précédent (il y a 1/20e de seconde si nous sommes à 20 images par seconde par ex.) et qu’il se trouve à (13,12) sur l’image suivante, pmouseX aura la valeur de 10, pmouseY la valeur de 11, mouseX la valeur de 13 et mouseY la valeur de 12. Un petit calcul de la distance parcourue nous permettra d’estimer la vélocité de la souris sur l’écran par exemple.

Le clic

Les utilisateurs y pensent rarement, quoiqu’ils les emploient quotidiennement, mais il existe deux sortes de clics avec une souris. Le demi-clic et le simple clic. Le demi-clic intervient lorsque l’on appuie sur le bouton de la souris, tandis que le simple clic intervient lorsque l’on relache le bouton de la souris. Évidemment, si l’on effectue un simple clic, c’est après avoir effectué un demi-clic. On utilise souvent le demi-clic pour le glisser-déplacer et le clic, pour exécuter ou valider une action.

Nous pouvons tester trois possibilités :

  • L’instant où le bouton de la souris vient d’être enfoncé. C’est la fonction d’évènement mousePressed().
  • L’instant où le bouton de la souris est relâché (clic). C’est la fonction d’évènement mouseReleased().
  • Enfin, à tout instant nous pouvons vérifier si le clic est maintenu, avec la propriété mousePressed.

L’exemple qui suit recourt à toutes ces possibilités à la fois.
Dans le fonction draw(), qui s’exécute régulièrement, je vérifie si le curseur de la souris est enfoncé, avec la condition if (mousePressed). Si c’est le cas, je dessine une ellipse de 20×20 pixels aux coordonnées de la souris.
La fonction mousePressed() est exécutée lorsque le bouton de la souris est enfoncé. Ici, je l’utilise pour « repeindre » la fenêtre en blanc.
La fonction mouseReleased() est invoquée lorsque la souris a été enfoncée puis est relâchée. Ici, je lui demande de « repeindre » la fenêtre en noir.

void draw(){
  if (mousePressed){
    ellipse(mouseX, mouseY, 20,20);
  }
}

void mousePressed(){
  background(255);
}

void mouseReleased(){
  background(0);
}

Il existe par ailleurs deux fonctions relatives au déplacement de la souris, mouseMoved(), qui est invoquée chaque fois que la souris a bougé, et mouseDragged(), qui est invoquée chaque fois que la souris a bougé et que son bouton est maintenu enfoncé.
Dans l’exemple suivant, à chaque fois que la souris est déplacée et que le clic est maintenu, processing dessine une ligne entre l’ancienne position de la souris et la nouvelle.

(l’image ci-dessus n’est pas une animation Processing mais juste une image fixe qui évoque le résultat obtenu avec le programme reproduit plus bas).
Notez qu’il faut que le script contienne une fonction draw() pour que la fonction mouseDragged() soit prise en compte.

void draw(){
  // sans action, mais obligatoire
}

void mouseDragged(){
  line(pmouseX, pmouseY, mouseX, mouseY);
}

Pour finir, il existe une dernière propriété relative à la souris qui se nomme mouseButton et qui permet de vérifier quel bouton de la souris est cliqué, à savoir le droit, le gauche ou le bouton central (RIGHT, LEFT, CENTER). Par exemple : if (mouseButton== RIGHT){ instructions }, où instructions sera remplacé par les commandes à exécuter si la condition (le clic gauche) est remplie.

Problèmes d’installation de Processing 1.0

novembre 28th, 2008 Posted in Processing | 4 Comments »

J’ai profité de l’annonce de la sortie de Processing 1.0 pour lancer un cours en ligne, mais je n’avais jusqu’ici pas testé cette dernière version du programme, et pour cause, il ne fonctionnait pas sur mon ordinateur. J’ai laissé cette question en suspens, me disant que Java était peut-être incorrectement installé sur ma configuration, mais j’ai reçu un certain nombre de mails d’utilisateurs victimes du même problème, que ce soit sur Macintosh, sur PC/Windows ou sous Unix. Le symptôme est généralement une absence de réaction, on clique et rien ne se passe. Parfois il y a un message inquiétant.
Espérons qu’un correctif sera rapidement mis au point. J’ai l’impression que ça ne touche pas les gens qui utilisent des systèmes d’exploitation anglais/américains.

En attendant de comprendre la raison de ce problème, il reste possible d’installer la version précédente du logiciel (version 0157) qui fonctionne généralement très bien chez tout le monde et qui n’est du reste sortie qu’il y a dix jours.
Thibaut me souffle une autre possibilité : sur Macintosh, il parvient à ouvrir Processing 1.0 en cherchant un ancien fichier créé avec processing et en demandant à l’« ouvrir avec » (ou en faisant glisser le fichier processing sur l’icône de l’application).
J’ignore si cette manip fonctionne ailleurs que sous MacOs.

Mise à jour : Le problème semble parfaitement réglé depuis la sortie de Processing 1.01.

Processing, huitième cours

novembre 28th, 2008 Posted in Processing | 3 Comments »

Les programmeurs aguerris qui m’ont lu jusqu’ici se sont sans doute inquiétés : qu’est-ce que c’est que ce langage sans structure, dont les commandes sont lancées n’importe comment, à la façon des langages interprétés comme le bon vieux langage Logo, créé dans les années 1960 et qui servait aussi à dessiner ? Ils peuvent se rassurer : Processing est un langage tout aussi structuré que les autres. J’espère que les lignes qui vont suivre ne paraîtront pas trop abstraites à certains de leurs lecteurs. Néanmoins le sujet sera rabâché par la suite.

Il existe deux fonctions de base réellement importantes dans processing : setup(), et draw(). La fonction setup() est lancée une seule et unique fois, au démarrage de l’animation. La fonction draw() s’exécute de manière redondante selon la fréquence qu’on lui a imposé (par exemple 25 fois par seconde).
Une chose très importante à savoir, c’est qu’un programme processing qui n’a pas de setup() ni de draw() peut rencontrer des problèmes. Les fonctions créées par le programmeur ou les fonctions relatives à l’interactivité (clic, clavier,…) ne marcheront pas, par exemple.

setup()

C’est dans le setup, lancé une seule fois, que l’on initialise des variables, que l’on règle le format d’écran, sa couleur, et plus généralement tout ce qui doit être réglé au démarrage et a fortiori ce que l’on ne veut régler qu’une seule fois.
Voici un setup() typique :

void setup(){
  size(500,500);
  background(0);
  smooth();
  frameRate(24);
}

Vous connaissez déjà les commandes size (le format de la fenêtre), background (la couleur de fond) et smooth (le lissage des dessins).  Nous découvrons en revanche la fonction frameRate(), extrêmement utile puisqu’elle sert à décider de la rapidité d’exécution d’une animation. Avec frameRate(1), nous créons une animation qui affichera une image par seconde ou, plus précisément, qui exécutera la fonction draw() une fois par seconde.

draw()

draw() est donc la fonction redondante de Processing, sa « boucle temporelle ». Toute instruction que l’on écrit dans draw() sera exécutée à une fréquence précise jusqu’à ce que l’on ferme l’application ou jusqu’à ce que le programme tombe sur l’instruction noLoop(); qui inhibe l’exécution de draw();
Avec le petit programme qui suit, une ligne va être tracée à des coordonnées aléatoires de manière régulière.

void draw(){
  line(random(100),random(100),random(100),random(100)); 
}

Notez que l’exemple ci-contre a été monté sous forme de gif animé à l’aide… d’un concurrent de processing. Ce n’est donc pas une authentique animation processing mais plutôt une simulation.
Quoi qu’il en soit, il suffit donc de créer une fonction draw() pour exécuter des actions de manière régulière. C’est ce type de disposition qui fait de processing un système spécialisé dans la création visuelle. Si l’on compare avec le langage Java (qui sert de support à processing) les choses se dérouleraient bien différemment. Il faudrait commencer par déclarer l’emploi de telles et telles « librairies », puis inventer un « timer » qui de manière redondante permettrait d’exécuter certaines actions… Bref, on s’y perd vite. Ici, les besoins spécifiques à la création artistique sont intégrés et leurs commandes sont simples à manipuler.

Les fonctions

Malgré la simplicité du système, la structure des fonctions (setup() et draw() sont des fonctions) est sans doute un peu troublante à lire pour ceux qui ne connaissent pas ce genre de langage — ou pour ceux qui ne connaissent rien à la programmation. Elle est toujours la même :
type nom( arguments ){ instructions }, où type est le genre de données que la fonction renvoie. Si elle doit renvoyer un chiffre entier, le type sera int. Si elle doit renvoyer une chaîne de caractère, le type sera String. Enfin, si la fonction ne renvoie rien, le type à indiquer est void. Les gestionnaires draw() et setup() sont des fonctions qui ne renvoient pas de données, on écrit donc void devant.
Le nom de la fonction doit être une chaîne de caractères, commençant par une lettre, sans espace. Il faut impérativement que ça ne soit pas un mot réservé de processing.
Les arguments sont les éventuels paramètres que la fonction s’attend à recevoir. Pour une fonction ne recevant aucun paramètre, on se contentera de mettre une parenthèse ouvrante et une parenthèse fermante, comme draw() ou setup(). Sans les parenthèses, le programme ne comprend pas qu’il s’agit de fonction.
Processing est un langage rigoureusement typé, c’est à dire qu’il refuse de ne pas savoir de quel type (entier, flottant, chaîne, caractère, double, booleen,…) est une variable1 . Cette fonction assez simple pourra vous permettre d’y voir un peu plus clair en pratique.

float distance(float x1, float y1, float x2, float y2) {
  float cote1 = x1-x2;
  float cote2 = y1-y2;
  return sqrt(pow(cote1, 2)+pow(cote2, 2));
}

Pour l’anecdote, la fonction ci-dessus sert à calculer la distance qui sépare deux points à l’aide du théorème de Pythagore. Chaque ligne dont on connaît les coordonnées sur un écran est en fait l’hypoténuse d’un triangle-rectangle. Avec une ligne dons les points sont (x1, y1) et (x2, y2), je sais que la longueur du côté horizontal de mon triangle-rectangle est (x2-x1) – ou x2-x1, ça reviendra au même – et que son côté vertical a pour longueur (y2-y1). Nous connaissons donc nos deux côtés. Puisque nous savons que le carré de l’hypoténuse est égal à la somme des carrés des deux autres côtés, nous savons aussi que la racine carrée de la somme des carrés des deux autres côtés est égale à la longueur de l’hypoténuse. Ainsi si j’invoque ma fonction de cette manière : distance(0, 0, 100, 100), je recevrais 141.421… comme résultat, car c’est la longueur de l’hypoténuse d’un carré de 100×100. Toujours pour l’anecdote, sqrt(x) renvoie la racine carrée de x et pow(z, 2) élève z au carré.
Dans ma fonction, float est donc le type de variable que la fonction doit retourner. On peut dire que la réponse de notre fonction sera un nombre décimal (ou « à virgule flottante », d’où le « float »).
Le nom de la fonction est distance. Ce n’est pas un nom interne à Processing, c’est moi qui l’invente. J’aurais pu aussi bien nommer cette fonction obtiensDistance ou pythagore.
Les arguments qui sont envoyés entre parenthèses à ma fonction sont ici au nombre de quatre (l’abscisse du premier point, l’ordonnée du premier point, l’abscisse du second point et l’ordonnée du second point). Pour chaque argument, Processing doit savoir de quel type de variable il s’agit. Ici, tous les nombres qui sont envoyés sont des décimales, donc ils sont passés, séparés les uns des autres par des virgules et précédés chacun de leur type de donnée. Si j’invoque ma fonction comme ceci : distance(1, 2, 3, 4), la fonction placera le chiffre 1 dans sa variable flottante x1, le chiffre 2 dans sa variable flottante y1, le chiffre 3 dans x2 et le chiffre 3 dans y2.
Les deux lignes suivantes pratiquent divers calculs arithmétiques qui sont renvoyés par le mot return.

Je suppose que beaucoup auront souffert avec cette page austère et au contenu pour le moins abstrait.
La suite devrait être plus amusante.

  1. les langages strictement typés sont les plus performants car ils sont plus proches de la manière d’exécuter les programmes du système. C, C++ ou Java sont strictement typés tandis que Lingo, PHP et Javascript sont plus désinvoltes et donc moins performants. [↩]

Processing, septième cours

novembre 27th, 2008 Posted in Processing | 3 Comments »

Le fonctionnement (et l’intérêt) des ordinateurs repose sur assez peu de fonctions, finalement : effectuer des calculs numériques, accéder à des valeurs (écrire, lire, modifier), tester des conditions et enfin répêter des actions. Tout le reste, ce qu’on nomme l’algorithmie (la combinaison de ces fonctions), en découle.
Nous allons donc à présent nous pencher sur les boucles (loop en anglais), ou itérations, qui permettent donc de répéter une action.
Processing en connaît manipule deux types, les boucles conditionnelles et les boucles itératives.

Les boucles conditionnelles

La syntaxe d’une boucle conditionnelle, qui sera familière à tous les programmeurs (C, C++, Java, Actionscript,…), est la suivante : while (condition) { instructions }, où « condition » est la propriété à tester et « instructions » est l’ensemble de commandes. C’est, typiquement, avec ce genre de commande mal invoquée que l’on bloque un programme. Par exemple si j’écris while(1==1){ print(« ok »); }, l’exécution du programme n’aura aucune raison de quitter la boucle puisque la condition testée (est-ce que 1 est égal à 1 ?) ne deviendra jamais fausse. Avec Processing, ce genre de boucle infernale n’est pas fatale et impose, au pire, de quitter le programme, mais la plupart du temps, lorsque l’ordinateur « plante », c’est qu’un de ses programmes importants est tombé sur une boucle infinie de ce type.
Voici une boucle au résultat aléatoire mais, a priori, contrôlé :

while(random(100)<95){
   point(random(100),random(100));
}

Ce qui, en clair, signifie que nous alons tirer un nombre au hasard entre 0 et 100. Si ce nombre est inférieur à 95, le programme dessinera un point n’importe où dans la fenêtre d’affichage, puis refera un tirage au hasard entre 0 et 100. Il est tout à fait possible que le premier nombre tiré soit, par exemple, 96. Dans un tel cas, la condition qui nous permet de quitter la boucle sera remplie dès le départ et l’instruction (dessiner un point n’importe où) ne sera pas exécutée. Il est aussi possible que l’ordinateur, taquin, ne veuille jamais produire le moindre nombre au hasard qui excède 94.9999… ce qui aurait pour résultat de nous laisser coincés dans notre boucle. Heureusement, les probabilités, même avec le hasard très imparfait de l’ordinateur, font que nous avons une chance sur 20 de dépasser le nombre 95 et donc, de quitter la boucle. Voici le résultat de cinq lancements différents du programme :

Les boucles itératives

La syntaxe des boucles intératives est un peu barbare de prime abord et nous force à nous pencher sur les variables. Voici un exemple typique de boucle itérative :

for(int a=0; a<100; a+=4){
   line (a,0,a,100);
}

Le résultat est l’image que vous voyez à droite : une ligne a été tracée tous les quatre pixels.
On peut traduire notre boucle ainsi :
1) Départ : Créer une variable nommée a et dont la valeur de départ est 0 (zéro). Je lui ai donné le nom a car tel est mon bon plaisir, mais elle aurait aussi bien pu se nommer ornithorynque.
2) Boucle : Si la valeur de a est inférieure à 100, alors
-a) dessiner une ligne entre les points (a,0) et (a,100)
-b) incrémenter a de 4 (a+=4 signifie que a doit devenir égal à a+4)
3) Revenir au début de la boucle si sa condition (a<100) est remplie. Sinon, le programme est terminé.

Dans notre cas, a prend les valeurs successives de 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92 et 96.

La syntaxe précise est donc :
for ( départ ; condition pour rester dans la boucle ; itération ) { instructions }
Ce n’est pas très beau à lire, d’autant que c’est le seul cas où on utilise des points-virgule pour autre chose que pour terminer une commande, mais on s’y fait car la syntaxe est la même dans un grand nombre de langages de programmation.

On peut par ailleurs imbriquer des boucles dans les boucles, ce qui est particulièrement intéressant pour dessiner des images, qui sont en deux dimensions. Si je veux parcourir tous les pixels de mon image un a un et, par exemple, y dessiner un point d’une couleur tirée au hasard, je peux le faire avec des boucles imbriquées. Cette fois, au lieu d’utiliser des variables nommées a, b, c ou ornithorynque, je vais utiliser des variables nommées d’une manière qui reflète leur usage, à savoir colonne et rangee (sans accent).

for(int colonne=0; colonne <100; colonne++){
  for(int rangee=0; rangee <100; rangee++){
     stroke(random(255));
     point(colonne, rangee); 
  }
}

La première boucle s’applique à une variable nommée colonne qui va avoir toutes les valeurs possibles entre 0 et 100. Pour chacun de ces états, une seconde boucle s’appliquera à une variable nommée rangee qui aura elle aussi toutes les valeurs possibles entre 0 et 100.
Ceci fait que la commande stroke (changer la couleur du trait) et la commande point (dessiner un point) seront exécutées 100 x 100 fois, c’est à dire 10 000 fois. Dans l’exemple ci-contre, la couleur appliquée aux pixels de l’image est un niveau de gris.
L’étrange ++ signifie que l’on augmente la variable de 1. Ainsi, « a++ » est synonyme de « a=a+1 », et réciproquement on peut écrire « a– » mais aussi « a-=1 » au lieu de « a=a-1 ». La notation des opérations arithmétiques sur des variables peut être un peu déroutante de prime abord. On s’y fait rapidement :

  • a++ : augmenter a de 1
  • a+=1 : augmenter a de 1
  • a=a+1 : augmenter a de 1
  • a-– : décrémenter a de 1
  • a-=1 : décrémenter a de 1
  • a=a-1 : décrémenter a de 1
  • a*=2 (ou a=a*2) : multiplier a par 2
  • a/=5 (ou a=a/5) : diviser a par 5

Les boucles ne sont pas ce que les débutants en programmation comprennent le mieux, ni ce que j’explique le mieux. Il s’agit néanmoins d’un outil extrèmement pratique.
Supposez que vous vouliez réaliser un motif de 530×120 pixels où un petit cercle blanc est dessiné tous les 10 pixels, comme ceci :

… Avec un logiciel de dessin comme Gimp ou Photoshop, c’est tout à fait possible, par un jeu de copier-coller laborieux. Une erreur est vite faite et c’est tout de même assez long. Pour Processing, ce programme suffit :

size(530, 120);smooth();noStroke();fill(255);
background(0);
 for(int x=0;x<53;x++){
  for(int y=0;y<12;y++){
    ellipse(5+x*10,5+y*10, 4, 4);
  }
}

Mais à présent, imaginez que vous vouliez obtenir ce même motif en appliquant à chacun de vos petits cercles de 4 pixels un décalage aléatoire de plus ou moins un pixel, comme ceci :

L’impression d’irrégularité ordonnée serait difficile à obtenir manuellement, une fois encore.
Cette fois, le programme sera :

size(530, 120);smooth();noStroke();fill(255);
background(0);
 for(int x=0;x<53;x++){
  for(int y=0;y<12;y++){
    ellipse(5+x*10+random(-1,1),5+y*10+random(-1,1), 4, 4);
  }
}

L’utilité permanente des boucles fait que nous les reverrons souvent dans les articles ultérieurs. Nous verrons aussi une autre forme de boucle, la boucle temporelle, qui nous permet d’exécuter une action n fois par seconde.

Notez que pour s’extraire d’une boucle avant qu’elle ait fini de s’exécuter, on écrit ceci : break;

Processing, sixième cours

novembre 27th, 2008 Posted in Processing | 4 Comments »

Le hasard informatique

Le hasard informatique est une notion curieuse car par essence, l’ordinateur ne fait jamais rien au hasard.
À une question donnée, il apportera toujours la même réponse.
Par exemple si je demande à un ordinateur de me dire si 10 est égal à 10, il me répondra toujours oui, et si je lui demande d’aditionner 2 et 2, il me répondra invariablement 4. C’est ce que l’on entend par la phrase «.L’ordinateur ne peut pas se tromper.», phrase qui a produit des contre-sens car elle a souvent été comprise comme «.L’ordinateur sait tout.», mais c’est une autre histoire1 .

Pour que l’ordinateur change de réponse à une question, il lui faut une condition extérieure, à savoir l’interactivité, au sens large, c’est à dire l’échange de données avec une condition extérieure telle qu’un autre ordinateur ou les informations envoyées par un système de saisie quelconque. Ainsi votre ordinateur n’affiche pas toujours le curseur à la même position sur l’écran car il est sensible aux mouvements que vous donnez à un périphérique de saisie tel que la souris ou le pad.
Pour obtenir un chiffre au hasard à l’aide d’un ordinateur, on utilise généralement une méthode simple et satisfaisante dans de nombreux cas, qui est de vérifier l’état de l’horloge du système au moment de l’exécution du programme et de traiter le chiffre obtenu avec un algorithme gaussien ou autre. Tous les ordinateurs disposent d’une horloge interne qui leur permet non seulement à la machine de savoir l’heure et la date, mais surtout de synchroniser électroniquement ses différents composants. C’est le seul composant de l’ordinateur qui n’est jamais éteint, il est alimenté par une pile bouton.
Avec notre hasard basé sur l’heure, on parle de chiffres pseudo-aléatoires car en théorie, deux ordinateurs parfaitement identiques, réglés sur la même heure à la micro-seconde près et sollicités au même instant devraient fournir le même chiffre.

Pour obtenir un chiffre pseudo-aléatoire simple avec processing, on utilise la fonction random();, qui s’utilise avec un ou deux arguments.
– random(10) renverra un chiffre décimal (à virgule) compris entre 0 et 10. Par exemple 6.2434893
– random(10, 20) renverra un chiffre décimal compris entre 10 et 20. Par exemple 19.80756
La syntaxe est donc random(maximum) ou random(minimum, maximum). La valeur minimum peut être un chiffre négatif (random(-10,10) renverra un chiffre compris entre -10 et 10), en revanche elle ne peut être un chiffre supérieur à la valeur maximum : random(10,-10) renverra toujours 10.
En pratique, on peut utiliser le hasard chaque fois que l’on manipule des coordonnées ou des valeurs telles que celles des couleurs. Dans l’exemple qui suit, nous agissons sur les coordonnées de lignes :

Le programme utilisé ici commence par effectuer les réglages d’environnement d’exécution : fenêtre de 530×100 pixels, adoucissement des lignes, traits blancs, fond noir, traits de 2 pixels d’épaisseur. Ensuite, huit lignes sont tracées à l’aide de la commande line(x1, y1, x2, y2), que nous avons déjà étudiée en détails.

size(530,100);smooth();stroke(255);background(0);strokeWeight(2);
line(0,random(100),530, random(100));
line(0,random(100),530, random(100));
line(0,random(100),530, random(100));
line(0,random(100),530, random(100));
line(0,random(100),530, random(100));
line(0,random(100),530, random(100));
line(0,random(100),530, random(100));
line(0,random(100),530, random(100));

On remarque que les paramètres de line sont ceux-ci :
– l’abscisse du premier point est le chiffre 0 (zéro).
– l’abscisse du second point est le chiffre 530.
Donc nos lignes commencent invariablement à gauche de l’écran et se terminent invariablement à droite de l’écran. En revanche,
– l’ordonnée du premier point est « random(100) », c’est à dire un chiffre quelconque entre 0 et 100, par exemple 12.01681 (les chiffres décimaux sont notés à l’aide d’un point (.) et non à l’aide d’une virgule (,))
– l’ordonnée du second point est aussi « random(100) », c’est à dire un autre chiffre quelconque entre 0 et 100.

à présent, si je remplace l’ordonnée du premier point par un hasard délimité comme random(5,50) et que je remplace l’ordonnée du second point par random(50,95), j’obtiendrais un résultat tel que celui-ci :

Même si le résultat sera différent à chaque exécution du programme, nous obtenons une apparence d’ordre un peu plus grande que dans le cas précédent, car le premier point sera toujours plus haut ou égal (dans le cas rare ou nous obtiendrions le chiffre 50) au second.
Ici la commande répétée huit fois, était donc

line(0,random(50),530, random(100));

On peut adapter le hasard à de nombreux cas.
– background(random(255)); peindra la fenêtre d’affichage dans une valeur de gris comprise entre le noir (0) et le blanc (255).
– background(random(255), random(255), random(255)); peindra la fenêtre d’affichage dans une couleur quelconque parmi les 16 777 216 de couleurs (256 niveaux de rouge x 256 niveaux de vert x 256 niveaux de bleu) que sait afficher la carte graphique d’un ordinateur typique.
– stroke (255 , 255, random(255)); fera que les traits auront une couleur comprise entre le jaune (255,255,0) et le blanc (255,255,255).
– fill (random(200,255), random(100,150), 0); décidera que les remplissages de formes auront une teinte plus ou moins orangée (beaucoup de rouge, un peu de vert, pas de bleu du tout).
– ellipse (100,100, random(10), random(10)); dessinera une ellipse dont le centre sera le point (100,100) et dont le diamètre vertical comme le diamètre horizontal seront des chiffres compris entre 0 et 10.
– les points, rectangles, triangles, etc., peuvent être affichés avec des coordonnées au hasard.

L’image qui est affichée ci-dessus utilise deux notions que nous n’avons pas encore abordé :
– les boucles (ou itérations) qui permettent d’exécuter une action de manière répétitive et progressive. Dans le cas présent, il s’agit de dessiner une ellipse tous les dix pixels.
– les variables, qui permettent de stocker une valeur. Je les emploie ici pour donner à l’ellipse un diamètre égal dans sa largeur et dans sa hauteur, afin que ces ellipses soient des cercles.

Grâce aux boucles et aux variables, je peux, avec quelques lignes de code seulement, dessiner 53 x 10 cercles (soit 530 cercles, vous pouvez les compter) d’un diamètre de 1 à 10 pixels, remplis avec une couleur choisie au hasard dans une gamme orangée :

size(530, 100);background(255); noStroke(); smooth();
for(int a=0; a<53;a++){
   for(int b=0; b<10;b++){
     fill(random(200,255), random(50,150),0);
     float diametre = random(1,10);
     ellipse(a*10+5, b*10+5, diametre, diametre);
  }
 }

Les boucles feront l’objet du prochain article.

Sur le hasard, il faut encore savoir qu’il existe une alternative à la commande random(), qui est la commande noise();. Cette commande utilise le « bruit de Perlin » (d’après le nom de son inventeur, Ken Perlin), qui permet d’obtenir un hasard un peu mieux distribué que celui que produit la commande random();. Cette manière de générer du hasard informatique est très utilisée pour les calculs de textures par exemple.
L’utilisation de noise est assez différente de celle de random, car noise renvoie un chiffre compris entre 0 et 12 . De plus noise est invoqué avec un, deux ou trois paramètres et chaque fois que l’on demande la valeur de noise pour un paramètre précis, la commande renverra le même résultat. C’est à dire que si je demande à voir la valeur de noise(1) à un moment donné et que je la redemande un peu plus tard (mais sans redémarrer le programme), j’obtiendrais chaque fois le même résultat. L’essai qui suit utilise les deux formes de hasard, avec les mêmes contraintes de minimum/maximum, pour les couleurs de remplissage et pour les tailles de rectangles.
À gauche, noise(), et à droite, random().

noise(); n’est pas très compliqué à utiliser mais random(); est suffisant dans la plupart des cas, nous pouvons nous y tenir.

  1. Sur la question du hasard comme notion mathématique, et sur la question du hasard dans la nature (est-ce qu’il existe, déjà ?), je recommande le très plaisant ouvrage d’Ivar Ekeland, Au hasard, publié en poche aux éditions du Seuil. Ivar Ekeland est un mathématicien de haut-vol spécialiste du chaos, qui n’a jamais peur de captiver son public ni de faire des aller-retours entre physique, histoire et littérature. [↩]
  2. Dans de nombreux langages, la commande random renvoie un chiffre compris entre 0 et 1. Par exemple avec le langage Javascript on écrira Math.random()*100 pour obtenir un chiffre entre 0 et 100. Et Math.random()*50+50 pour obtenir un chiffre compris entre 50 et 100.   [↩]

Processing, cinquième cours

novembre 27th, 2008 Posted in Processing | 2 Comments »

On reprend, avec quelques nouvelles formes en deux dimensions. Nous avons vu la ligne, le rectangle et l’ellipse, voici à présent le point, le triangle, l’arc et le quad.

Le point

La commande point est simplissime, puisqu’elle s’invoque tout bêtement comme ceci : point(abscisse, ordonnee);, où abscisse et ordonnée sont des chiffres. Pour être plus précis, on peut ajouter un troisième axe (la cote), afin de placer le point dans l’espace et non sur un plan : point(abscisse, ordonnée, cote);. Mais nous ne parlerons pas de ça aujourd’hui.
Le point est soumis aux paramètres des traits en général, c’est à dire que l’on peut régler sa couleur avec stroke(couleur);, son épaisseur avec strokeWeight(épaisseur); et la précision visuelle de son affichage avec smooth();.
En revanche la commande noStroke(); n’a pas d’effet sur l’affichage des points.

La suite de points ci dessus a été obtenue avec ce programme :

size(530,50);
point(53,25);
strokeWeight(25);
point(159,25);
smooth();
point(265,25);
stroke(255,0,0);
strokeWeight(10);
point(371,25);
stroke(255,255,255);
point(477,25);

On peut noter la différence visuelle appréciable qui intervient après l’utilisation de la commande smooth(), sur le troisième point, au centre de l’image.

Le triangle

Le triangle, qui comme chacun sait est défini par trois points, se dessine de manière très simple avec la commande triangle(), qui est invoquée comme suit : triangle (x1, y1, x2, y2, x3, y3);, où x1 est l’abscisse du premier point, y1 l’ordonnée du premier point, et ainsi de suite. La commande triangle est sensible aux commandes fill (couleur de remplissage), stroke (couleur des traits), strokeWeight (épaisseur des traits) et smooth (qualité d’affichage).
Dans cet exemple, nous commençons par « peindre » la fenêtre en noir (background(0);) puis nous décrétons que la couleur de remplissage en cours est le rouge (fill(255,0,0);) et que les traits devront être dessinés en jaune (stroke(255,255,0);).
Enfin, nous traçons notre triangle avec trois points : (10,90), (50,10) et (90,90).

background(0);
fill(255,0,0);
stroke(255,255,0);
triangle(10,90,50,10,90,90);

L’arc

Le dessin des arcs n’est pas beaucoup plus compliqué, la syntaxe de la commande étant la suivante :
arc(x, y, largeur, hauteur, départ, arrivée); où x et y sont les coordonnées cartésiennes de l’origine de l’arc, ou largeur et hauteur sont les diamètres horizontaux et verticaux dans lesquels s’inscrit l’arc (comme pour les ellipses) et où, pour finir, départ et arrivée sont l’angle de départ et l’angle d’arrivée de l’arc. Par défaut, ces angles sont exprimés en radians (de zéro à deux fois Π) et non en degrés (de zéro à trois-cent soixante). Pour convertir des degrés en radians on utilise la commande radians (radians(180); donne Π (PI), par exemple.
Le pacman qui est dessiné ci-dessus est réalisé avec le code suivant :

fill(255,255,0);
arc(50, 50, 90, 90, radians(45), radians(315));

On remarque que les arcs sont soumis à la commande fill (remplissage). Ils sont aussi soumis aux commandes stroke, strokeweight et smooth, qui ne sont pas utilisées ici. On remarque par ailleurs que les valeurs de l’angle de départ et de l’angle d’arrivées ne sont pas des chiffres mais le résultat d’une conversion de chiffre. Pour processing, écrire radians(45) équivaut en fait à écrire 0.7853982.

Le quad

Le quad est un quadrilatère quelconque, repéré par quatre points. on le dessine à l’aide de cette commande.: quad (x1, y1, x2, y2, x3, y3, x4, y4);, où x1 et y1 sont les coordonnées d’un des quatre points, x2 et y2 les coordonnées d’un second point, x3 et y3 les coordonnées d’un troisième point et x4 et y4 les coordonnées du quatrième et dernier point. Les quads sont soumis aux commandes stroke, strokeweight et smooth. Voici quelques exemples de quads.

Ils ont été obtenus avec ce programme :

quad (10,10,90,10,90,90,10,90);
quad (10,10,90,10,10,90,90,90);
quad (10,20,90,10,80,90,20,80);
smooth();
quad (10,20,90,10,80,90,20,80);
noStroke();
fill(200,190,0);
quad (10,20,90,10,80,90,20,80);

On remarque la différence d’affichage des quads dessinés après la commande smooth(); (le quatrième et le cinquième quad sont dans ce cas). On remarque aussi que les deux premiers quads, qui utilisent les mêmes points, mais pas dans le même ordre, ce qui fait que deux traits du second quad se croisent.

Nous pouvons nous arrêter là avec les formes dessinées par processing, pour l’instant, mais il en existe d’autres : les courbes et les courbes de bézier, les « vertex » (qui sont en fait des formes à n points reliés par des lignes ou par des courbes), et bien entendu les formes en 3D.
Nous ne sommes pas non plus rentrés dans les détails concernant le rendu des lignes, que permettent les commandes strokeCap(); et strokeJoin();, qui permettent de décider si une ligne se termine par un arrondi, par un angle ou par un biseau et qui permet de définir le rendu de l’intersection de deux lignes.

Prochain épisode : l’utilisation du hasard.

Salon du livre jeunesse

novembre 27th, 2008 Posted in Brève, Lecture | 1 Comment »

Détendons l’atmosphère entre deux articles sur processing… Depuis hier mercredi jusqu’à lundi 1er décembre se tient à Montreuil le Salon du livre et de la presse jeunesse. On s’y rend facilement par la station de métro Robespierre (ligne Mairie de Montreuil). L’entrée coûte quatre euros et est gratuite pour les enfants.
Je n’y étais encore jamais allé, je n’aime pas énormément les salons. Celui-ci est très couru car il permet de faire ses courses pour noël.
Sans atteindre le niveau du salon d’Angoulême dans ce domaine, on voit de jeunes adultes écumer les allées un carton à dessin sous le bras dans le but, a priori, de trouver à faire éditer leurs travaux.

Je retiendrais :
– Une exposition pitoyable de l’école Estienne sur le stand de la Mairie de Paris, consistant en douze feuilles imprimées en A4, qui jouxtait une exposition de dessins d’enfants plutôt mieux accrochée.
– Un rayon bande dessinée pas spécialement adapté aux jeunes mais contenant des livres formidables. Outre les petits éditeurs français comme Cornélius, on pouvait regarder de superbes livres anglophones difficiles à trouver chez nous comme plusieurs livres sur Edward Gorey ou encore un livre superbe consacré à Henry Darger, ce demi-fou formidable dont l’œuvre n’a été découverte que de manière posthume. Je dis bien regarder et non acheter car tout cela est hors de prix.
– Que le secteur du livre jeunesse semble être en pleine forme si l’on se fie au nombre de publications.
– Des stands très ouverts qui forcent les éditeurs à employer de nombreuses personnes dans des tâches de surveillance. Samedi, avec la cohue, ils vont souffrir.
– Pas de multimédia, très peu de DVDs (mais plusieurs collections consacrées à l’étude du cinéma).
– Beaucoup de romans destinés aux enfants et aux adolescents
– Rien de vraiment surprenant ou de nouveau, m’a-t-il semblé.

Processing, quatrième cours

novembre 27th, 2008 Posted in Processing | 22 Comments »

Comme promis à présent, les rectangles (dont les carrés) et les ellipses (dont les cercles).
On peut difficilement faire plus simple. Pour dessiner un rectangle parallèle aux bords de l’écran, il suffit de d’indiquer son point supérieur gauche puis de décider de sa largeur et sa hauteur.

rect(20,25,50,60);

Avec ce code, processing dessine un rectangle dont le point supérieur gauche se trouve à 20 pixels du bord gauche et à 25 pixels du bord supérieur. Ce rectangle a une largeur de 50 pixels et une hauteur de 60 pixels.
La syntaxe de la commande rect est donc : rect(x, y, l, h);, où x et y sont l’abscisse et l’ordonnée du point supérieur gauche du rectangle, l sa largeur et h sa hauteur. Comme vous vous en doutez, si l’on choisit le même chiffre comme hauteur et comme largeur du rectangle, celui-ci sera un carré.
On ne peut pas faire plus simple. Comme je n’ai pas demandé de format particulier pour ma fenêtre, elle mesure 100 pixels par 100 pixels et sa couleur de fond est le gris. Puisque je n’ai pas décidé de la couleur de contour de mon rectangle, celle-ci est le noir et puisque je n’ai pas défini une couleur de remplissage pour mon rectangle, celui-ci est rempli en blanc. Si je ne veux pas de contour à mon rectangle, je dois invoquer la commande noStroke(); et si je ne veux pas lui attribuer de couleur de remplissage, je dois écrire noFill();. Évidemment, si j’ai utilisé les commandes noFill(); et noStroke(); en même temps, le résultat sera… que rien ne s’affichera. La couleur du trait de contour doit être réglée avec la commande stroke(); que nous connaissons déjà. L’épaisseur de ce trait de contour se règle avec la commande fill();, qui est parfaitement symétrique à stroke();. Mais passons à la pratique.
Le programme qui suit commence par régler la taille et la couleur de la fenêtre d’affichage (530×80 pixels, dans un gris assez clair). Puis il dessine successivement sept rectangles, en changeant les couleurs ou les options de remplissage et de contour grâce aux commandes fill, stroke, strokeWeight, noFill et noStro

size(530,80);
background(220);
rect(10,10,60,60);
fill(255,0,0);
rect(85,10,60,60);
fill(0,255,0);
stroke(0,0,255);
rect(160,10,60,60);
strokeWeight(5);
fill(255);
rect(235,10,60,60);
noStroke();
fill(255,0,0);
rect(310,10,60,60);
fill(255,255,0);
rect(385,10,60,60);
stroke(0);
noFill();
rect(460,10,60,60);

Voici le résultat que nous obtenons

Au passage, profitons en pour tester une propriété des couleurs déjà évoquée précédemment mais non-utilisée, l’opacité. Rappelez-vous, si j’écris stroke(0, 25);, cela signifiera que je veux que les traits soient noirs (0) mais à un certain degré d’opacité, à savoir 25 (sur 255, soit environ 10%). Cela fonctionne aussi pour la commande fill.

size(190,88);
background(255);
noStroke();
fill(255,0,0,20);
rect(2,2,60,60);
rect(6,6,60,60);
rect(10,10,60,60);
rect(14,14,60,60);
rect(18,18,60,60);
rect(22,22,60,60);
rect(26,26,60,60);
noFill();
stroke(0,0,255,80);
strokeWeight(2);
rect(102,2,60,60);
rect(106,6,60,60);
rect(110,10,60,60);
rect(114,14,60,60);
rect(118,18,60,60);
rect(122,22,60,60);

Dans ce cas, j’ai commencé par définir une zone d’affichage de 190 pixels par 88, sur fond blanc. Puis j’ai décrété qu’il n’y aurait pas de traits de contours à mes formes (noStroke();) et j’ai sélectionné comme couleur de remplissage du rouge (255,0,0) à une opacité de 20, comme ceci : fill(255,0,0,20);. Le niveau d’opacité (ou de transparence, c’est la même chose) peut aller de 0 (totalement invisible) à 255 (totalement opaque). Avec la valeur de 20, j’obtiens une opacité d’environ 8%. Avec 127, j’obtiendrais une opacité de 50%, etc. Des carrés sont ensuite dessinés tous les quatre pixels. L’effet de transparence/opacité fait que plus il y a d’intersections et plus la couleur est dense.
Pour la seconde série, c’est la couleur de remplissage qui est supprimée (noFill();) et la couleur de contour qui est créée à une certaine opacité (stroke(0,0,255,80);), ce qui nous donne du bleu avec une opacité de 80 sur 255, soit environ 32%. L’épaisseur des traits est de 2 pixels (strokeWeight(2);).

Les ellipses fonctionnent de manière assez similaire aux rectangles puisque leur remplissage et leur contour se décide de la même manière (stroke, noStroke, strokeWeight, fill, noFill). Comme la commande rect, la commande ellipse s’invoque avec quatre arguments : ellipse (x, y, d1, d2);, où x est l’abscisse et y l’ordonnée de l’origine (du centre) de l’ellipse et ou d1 est son diamètre horizontal et d2 son diamètre vertical.
Dans l’exemple qui suit, après avoir décidé de la taille (530 x 100) et de la couleur (blanc) de la fenêtre d’affichage, je dessine cinq ellipses dont les centres se trouvent aux positions (40,50), (120,50), (200,50), (280,50) et (360,50). Le fait que leur coordonnée verticale soit toujours la même (50) les place sur la même ligne. Les trois premières figures ont des diamètres latéraux et verticaux identiques, ce sont donc des cercles. Les deux suivantes ont des diamètres non-égaux. 
Plus loin, je supprime les traits de contour (noStroke();) puis je dessine quatre ellipses dont le point d’origine est le même (460, 50) mais dont les diamètres sont de plus en plus petits. Entre deux dessins, je change de couleur de remplissage.

size(530, 100);background(255);
ellipse(40,50,20,20);
ellipse(120,50,40,40);
ellipse(200,50,60,60);
ellipse(280,50,60,20);
ellipse(360,50,20,60);
noStroke();
fill(255,0,0);
ellipse(460,50,80,80);
fill(255,255,0);
ellipse(460,50,60,60);
fill(0,255,0);
ellipse(460,50,40,40);
fill(255);
ellipse(460,50,20,20);

Le résultat est conforme au programme.
J’aurais aussi pu décréter une épaisseur des traits de contour particulière, ce que je n’ai pas fait. 

Avec les ellipses nous retrouvons l’effet d’escalier, pas toujours heureux, qui apparaissait avec les lignes obliques dessinées à l’aide de la commande line.
Pour pallier à ce problème, exactement comme avec les lignes, on peut commencer son programme par la commande smooth(); dont l’effet est d’adoucir l’affichage de certains objets.
Si la commande smooth(); n’est pas lancée automatiquement au démarrage, c’est parce que l’on n’en a pas toujours besoin et qu’elle ralentit considérablement le travail de processing, ralentissement qui n’est cependant pas sensible sur des images aussi simples que celle-ci. 

Il n’y a pas beaucoup plus à savoir sur les ellipses et les rectangles si ce n’est qu’il existe pour chacune de ces deux formes un paramétrage facultatif permettant de modifier le rôle du point de référence de la forme. Ainsi en écrivant rectMode(CENTER);, les rectangles ne seront plus repérés par leur point supérieur gauche mais par leur centre, tandis qu’en écrivant ellipseMode(CORNER);, le point de référence de l’ellipse ne sera plus son centre mais son coin supérieur gauche.

Processing, troisième cours

novembre 26th, 2008 Posted in Processing | 3 Comments »

Continuons à explorer les fonctions de dessin de processing.
Nous avons vu la fonction line qui permet de tracer une ligne selon cette syntaxe : line (x1, y1, x2, y2); où x1 est l’abscisse (la coordonnée horizontale) du premier point de la ligne, y1 l’ordonnée (la coordonnée verticale) du premier point, x2 l’abscisse du second point et y2 l’abscisse du second point.
Une douzaine d’années d’enseignement de la programmation auprès d’étudiants en art m’a appris qu’une partie non-négligeable d’entre ces derniers décrochaient complètement à l’évocation de mots tels que abscisses et ordonnées. Il n’y a pourtant pas de raison, ces notions sont extrêmement simples, le fait que je les comprenne le prouve.
Voici un petit programme qui va dessiner cinq lignes :

size(530, 100);
line(10,10,500,10);
line(15,30,505,30);
line(20,50,510,50);
line(25,70,515,70);
line(30,90,520,90);

La première ligne sera tracée entre le point (10, 10) et le point (500, 10), la seconde entre les points (15, 30) et (505, 30) et ainsi de suite. Le résultat est le suivant :

Ce sont des traits horizontaux puisque les ordonnées (coordonnées verticales) des deux points sont chaque fois identifuqes. À présent voyons ce qui advient si nous dessinons des lignes dont les deux points ne se trouvent pas sur la même ligne.

size(530, 120);
line(10,10,500,30);
line(15,30,505,50);
line(20,50,510,70);
line(25,70,515,90);
line(30,90,520,110);

Le résultat est celui-ci :

On remarque que les traits sont dessinés avec un effet d’escalier qui n’est pas forcément très heureux.
Cela peut être évité grâce à une commande nommée smooth();
Une fois que l’on a écrit la commande smooth(); dans un programme, les traits qui sont tracés sont dessinés avec un effet d’anti-aliasing, c’est à dire avec une diffusion de gris intermédiaires de valeurs différentes

size(530, 120);
line(10,10,500,30);
line(15,30,505,50);
line(20,50,510,70);
smooth();
line(25,70,515,90);
line(30,90,520,110);

Dans ce cas précis, les trois premiers traits sont dessinés avec l’effet d’escalier, puis la commande smooth(); est invoquée. Les deux traits suivants sont alors dessinés sans l’effet d’escalier. Comme il s’agit de traits noirs sur un gris assez foncé, et que l’inclinaison des lignes est assez proche de l’horizontale, l’effet n’est pas forcément agréable à l’œil :

Pour en finir avec les lignes, deux nouvelles commandes.
– strokeWeight, qui permet de régler l’épaisseur des traits
– stroke, qui permet de régler leur couleur.

size(530, 60);   // la scène fait 530 x 60 pixels
smooth();    // les traits doivent être dessinés sans effet d'escalier
stroke(255);    // les traits s'affichent en blanc
line(50,10,50, 50);  // tracer une ligne entre (50,10) et (50,60)
strokeWeight(2); // les traits doivent avoir une épaisseur de 2 pixels
line(100,10,100, 50);  // tracer une ligne
stroke(0);  // les traits doivent être noirs
strokeWeight(1); // les traits doivent faire 1 pixel d'épaisseur
line(150,10,150, 50);  // tracer une ligne
strokeWeight(3); // les traits doivent faire trois pixels
line(200,10,200, 50);  // tracer une ligne
strokeWeight(1);  // les traits doivent faire 1 pixel d'épaisseur
stroke(255,0,0);  // les traits doivent être rouges
line(250,10,250, 50);  // tracer une ligne
strokeWeight(5);   // les traits doivent faire 5 pixels d'épaisseur
line(300,10,300, 50);  // tracer une ligne
stroke(0,255,0);  // les traits doivent être verts
strokeWeight(0.1);   // les traits doivent faire 0,1 pixel d'épaisseur
line(350,10,350, 50);  // tracer une ligne
strokeWeight(10);   // les traits doivent faire 10 pixels d'épaisseur
line(400,10,400, 50);  // tracer une ligne
stroke(0,0,255);  // les traits doivent être bleus
strokeWeight(1.5);   // les traits doivent faire 1,5 pixel d'épaisseur
line(450,10,450, 50);  // tracer une ligne
strokeWeight(5);   // les traits doivent faire 5 pixel d'épaisseur
line(500,10,500, 50);  // tracer une ligne

Le résultat sera le suivant :

La syntaxe de la commande strokeWeight, qui permet de décider de l’épaisseur du trait, est donc strokeWeight(epaisseur); où épaisseur sera remplacé par un chiffre. Par exemple strokeWeight(10); pour une épaisseur de dix pixels. Par défaut l’épaisseur des traits est de 1 pixel. Notez la majuscule sur la lettre W : strokeWeight.
La syntaxe de la commande stroke, qui permet de décider de la couleur des traits, est stroke (gris); ou stroke(gris, opacité);, ou stroke(rouge, vert, bleu); ou encore stroke(rouge, vert, bleu, opacité);
Nous laisserons l’opacité de côté pour l’instant, mais il faut savoir que chacune de ces valeurs peut avoir 256 niveaux (soit deux puissance huit, car l’ordinateur compte par puissances de deux), de 0 à 255 précisément.
Dans le code qui est reproduit plus haut, j’ai introduit une nouveauté, les commentaires. En effet tout ce qui est précédé de deux « slashs » (//) n’est pas interprêté par processing. Par exemple si j’écris

background(0); // background(255);

… Le programme exécutera la première commande (« peindre » la fenêtre en noir) mais n’exécutera pas le seconde (« peindre » la fenêtre en blanc).

Bon, nous en avons fini avec les traits. Vous pouvez à présent essayer chez vous les mêmes commandes, en modifiant les chiffres, afin de voir ce qui arrive. Le prochain article introduira d’autres objets graphiques tels que les rectangles, les ellipses et les points.