Aller au contenu

Les transformations

translate(), rotate(), push() et pop() servent à déplacer et faire tourner ce que l’on dessine. Elles déroutent souvent au début, parce qu’elles ne font pas ce qu’on imagine. Tout devient simple avec une seule image en tête :

Les schémas reprennent le style de la page Les coordonnées. Dans les animations, la grille grise représente la feuille, avec ses axes X et Y et son origine (0, 0), le point bleu. Le cadre, lui, c’est le canevas : il ne bouge jamais. Le bandeau sous chaque animation affiche l’instruction en cours.

circle(400, 150, 20);

Le point (0, 0), l’origine, est dans le coin en haut à gauche du canevas.

x augmente vers la droite. y augmente vers le bas : c’est l’inverse des maths du secondaire !

Le point (400, 150) est donc à 400 pixels du bord gauche et à 150 pixels du haut. Voir aussi la page Les coordonnées.

translate(200, 150);
rect(0, 0, 150, 90);

translate(x, y) fait glisser l’origine de la feuille.

On dessine ensuite en (0, 0)… qui se trouve maintenant en (200, 150) sur l’écran.

Le canevas ne bouge pas : c’est la grille grise, notre feuille, qui a glissé.

L’intérêt ? Le code de la forme ne change jamais, aussi compliquée soit-elle : elle est toujours dessinée autour de (0, 0). On ne change que la position de la feuille. Ici, la feuille suit la souris :

function setup() {
createCanvas(800, 400);
}
function draw() {
background(240);
translate(mouseX, mouseY); // la feuille suit la souris
fill(255, 150, 50);
// la forme, dessinée autour de (0, 0)
beginShape();
vertex(0, 0);
vertex(90, 20);
vertex(60, 40);
vertex(90, 40);
vertex(60, 60);
vertex(90, 60);
vertex(60, 80);
vertex(70, 90);
vertex(60, 100);
vertex(50, 90);
vertex(40, 100);
vertex(0, 70);
vertex(10, 40);
endShape(CLOSE);
}
translate(50, 250);
rect(0, 0, 80, 80);
translate(150, 0);
rect(0, 0, 80, 80);
translate(150, 0);
rect(0, 0, 80, 80);

Chaque translate() part de la position actuelle de la feuille, pas du coin du canevas : le troisième carré est en x = 50 + 150 + 150 = 350.

Attention donc : un translate(0, 0) après un translate(50, 50) ne ramène pas la feuille à zéro. Il ne fait… rien du tout.

rotate(30);
rect(300, 100, 150, 90);

rotate(angle) fait tourner toute la feuille… autour de son origine, c’est-à-dire le coin en haut à gauche.

Le rectangle ne tourne donc pas sur lui-même : il décrit un grand arc de cercle.

C’est le piège classique. On voit plus bas comment l’éviter.

function setup() {
createCanvas(600, 600);
angleMode(DEGREES);
}

Par défaut, p5.js compte les angles en radians (un tour complet = TWO_PI, environ 6,28). Pour travailler en degrés, ajoutez angleMode(DEGREES) dans setup() : un tour complet vaut alors 360. Tous les exemples de cette page utilisent les degrés.

Un angle positif tourne dans le sens des aiguilles d’une montre, parce que y va vers le bas.

Pour faire tourner une forme sur elle-même, on combine les deux :

  1. Aller : translate(x, y)

    Placer l’origine de la feuille au centre de la forme.

  2. Tourner : rotate(angle)

    Faire tourner la feuille autour de ce centre.

  3. Dessiner : rect(0, 0, w, h)

    Dessiner la forme en (0, 0). Avec rectMode(CENTER), le rectangle est centré sur ce point.

À répéter comme une comptine : je vais au centre, je tourne, je dessine.

function setup() {
createCanvas(600, 600);
angleMode(DEGREES);
rectMode(CENTER);
}
function draw() {
background(255);
translate(300, 300); // 1. aller
rotate(frameCount); // 2. tourner
rect(0, 0, 200, 100); // 3. dessiner
}

frameCount compte les images depuis le début du sketch. Il augmente de 1 à chaque image : l’angle grandit tout seul et le rectangle tourne.

Mêmes instructions, ordre différent, résultat différent. Dans les deux animations, l’angle a va et vient entre 0 et 50 :

translate(300, 150);
rotate(a);
rect(0, 0, 100, 60);
rotate(a);
translate(300, 150);
rect(0, 0, 100, 60);

À gauche, on va d’abord au bon endroit, puis on tourne : la forme tourne sur place. À droite, on tourne d’abord la feuille entière autour du coin, puis on avance le long de l’axe x qui a tourné : la forme tourne autour du coin.

translate(300, 300);
rotate(45);
fill(255, 120, 141);
rect(0, 0, 150, 150);
fill(29, 161, 242);
rect(100, 100, 80, 80);

Une transformation reste active jusqu’à la fin de draw().

Le carré bleu est déplacé et tourné lui aussi, au lieu d’apparaître en (100, 100).

push()

Je prends une photo de la feuille : sa position, sa rotation, et aussi les réglages de style comme fill() ou stroke().

pop()

Je remets la feuille exactement comme sur la photo. Tout ce qui a été fait entre les deux est oublié.

Toujours par paire, comme des parenthèses : chaque push() a son pop().

push();
translate(300, 200);
rotate(45);
fill(255, 120, 141);
rect(0, 0, 120, 120);
pop();
fill(29, 161, 242);
rect(150, 450, 120, 120);

Entre push() et pop(), les axes en pointillés montrent la photo prise par push(). Au moment du pop(), la feuille y retourne : le carré bleu est dessiné au bon endroit.

Le décalage des lignes entre push() et pop() n’est pas obligatoire, mais il aide à voir ce qui est « entre parenthèses ».

Avec rectMode(CENTER) et angleMode(DEGREES) dans setup().

function draw() {
background(255);
translate(300, 300);
rotate(second() * 6);
line(0, 0, 0, -250);
}

Un tour = 360°. En 60 secondes : 360 / 60 = 6° par seconde.

On dessine l’aiguille vers le haut, de (0, 0) à (0, -250) : c’est midi. La rotation fait le reste.

Chaque aiguille a sa propre rotation : on range le push(), le rotate() et le pop() dans une fonction, et on l’appelle trois fois.

function draw() {
background(255);
translate(300, 300);
aiguille(second() * 6, 250);
aiguille(minute() * 6, 200);
aiguille(hour() * 30, 130);
}
function aiguille(angle, longueur) {
push();
rotate(angle);
line(0, 0, 0, -longueur);
pop();
}

Les heures : 12 heures pour un tour, soit 360 / 12 = 30° par heure.

Pour aller plus loin, voir l’exercice Créez une horloge.

Les push() et pop() peuvent s’emboîter. La Terre tourne autour du Soleil ; la Lune tourne autour de la Terre, dans le repère de la Terre.

function draw() {
background(255);
translate(300, 300);
circle(0, 0, 80); // Soleil
push();
rotate(frameCount);
translate(200, 0);
circle(0, 0, 30); // Terre
push();
rotate(frameCount * 4);
translate(45, 0);
circle(0, 0, 10); // Lune
pop();
pop();
}

Les petites flèches autour de la Terre montrent son repère : c’est dans cette feuille-là que la Lune est dessinée.

FonctionCe qu’elle faitÀ retenir
translate(x, y)Déplace l’origine de la feuilleLes déplacements s’additionnent
rotate(angle)Tourne la feuille autour de l’origineSens horaire
push()Prend une photo de la feuilleToujours suivi d’un pop()
pop()Remet la feuille comme sur la photoOublie tout depuis le push()
rectMode(CENTER)Dessine le rectangle depuis son centrePour tourner sur place
angleMode(DEGREES)Compte les angles en degrésÀ mettre dans setup()
draw()Remet la feuille à zéro à chaque imageRien ne s’accumule d’une image à l’autre

La référence de rotate() sur p5js.org