Tema 7

Rotació i transformacions

Descobreix com moure, girar i escalar les teves formes per crear mandales, patrons radials i composicions dinàmiques amb translate(), rotate() i scale().

Per què necessitem transformar?

Fins ara hem dibuixat formes directament en una posició del llenç. Però imagina que vols dibuixar un molí de vent amb aspes al voltant d'un centre, o una flor amb pètals en cercle. Calcular les coordenades de cada element pot ser complicat.

Les transformacions geomètriques ens permeten canviar temporalment el sistema de referència del dibuix: desplaçar l'origen, girar els eixos o canviar l'escala. Així, poden dibuixar cada element com si estigués a la posició original, i que automàticament aparegui al lloc correcte.

Idea clau: Les transformacions no mouen les formes, sinó el sistema de coordenades on les dibuixem.

translate(x, y): desplaçar l'origen

translate(dx, dy) mou l'origen de coordenades (0,0) a la posició (dx, dy) del llenç. A partir d'aleshores, tot el que dibuixem es referirà a aquest nou origen.

Per exemple, si fem translate(150, 100) i després dibuixem un cercle a (0,0), aquest apareixerà al centre (150, 100) del llenç original.

translate(150, 100);        // movem origen al centre
fill(255,0,0,100);
ellipse(0, 0, 80, 80);      // cercle centrat al nou origen
fill(0,0,255,150);
rect(-20, -10, 40, 20);     // rectangle al voltant de l'origen
line(-60, 0, 60, 0);        // eix X
line(0, -50, 0, 50);        // eix Y

Sense translate(), hauríem de sumar 150 a totes les X i 100 a totes les Y. Amb la transformació, dibuixem al voltant del (0,0) local i és molt més còmode.

rotate(angle): girar el món

rotate(angle) gira el sistema de coordenades un cert angle (en radians) al voltant de l'origen actual. Per passar de graus a radians, podem fer radians(graus).

Important: la rotació sempre es fa respecte a l'origen (0,0) actual. Per girar un objecte al voltant del seu propi centre, primer cal fer translate() per situar l'origen al centre desitjat.

translate(150, 100);            // centre del llenç
for (let i = 0; i < 8; i++) {
  rotate(radians(45));          // gira 45° cada cop
  fill(255, 150, 0, 150);
  rect(30, -5, 30, 10);        // rectangle desplaçat a la dreta
}

Cada rotate() s'acumula als anteriors. Per aïllar transformacions, més endavant veurem push() i pop().

scale(factor): escalar el dibuix

scale(s) multiplica la mida de tot el que dibuixem a partir d'aleshores. Si el factor és 2, tot serà el doble de gran; si és 0.5, la meitat. També podem escalar de manera diferent en X i Y: scale(sx, sy).

translate(20, 80);
for (let i = 0; i < 4; i++) {
  scale(0.8);                   // cada cop un 80% de la mida anterior
  fill(255, 100, 100, 100);
  rect(0, -20, 50, 40);        // rectangle a la posició actual
  translate(55, 0);             // desplaçament per al següent
}

Truc: scale() també afecta el gruix del traç i altres propietats. Si vols evitar-ho, pots ajustar strokeWeight() després d'escalar.

L'ordre de les transformacions importa!

Quan combines translate(), rotate() i scale(), l'ordre és crucial perquè les transformacions s'apliquen en seqüència. No és el mateix traslladar i després girar, que girar i després traslladar.

translate → rotate

L'objecte gira al voltant de la seva pròpia posició.

rotate → translate

L'objecte orbita al voltant d'un punt llunyà.

Recorda: Les transformacions s'apliquen en ordre invers al que les escrivim. Primer rotate() gira el món, i després translate() es fa sobre el món ja girat.

push() i pop() en profunditat

Com que les transformacions s'acumulen, si volem dibuixar diversos objectes independents, necessitem aïllar les transformacions de cadascun. push() guarda l'estat actual (posició, rotació, escala, estil...) i pop() el recupera.

// Objecte 1: vermell, girat 20°
push(); translate(70, 100); rotate(radians(20));
fill(255,100,100); rect(-20,-15,40,30); pop();

// Objecte 2: blau, girat -35°
push(); translate(210, 100); rotate(radians(-35));
fill(100,100,255); rect(-20,-15,40,30); pop();

// Objecte 3: verd, sense transformacions
fill(0,255,100); ellipse(140,150,30,30);

Creació de mandales pas a pas

Un mandala és un disseny radial simètric. Amb un bucle i rotate(), podem repetir un motiu al voltant d'un centre per crear mandales hipnòtics.

translate(width/2, height/2);
let numPecs = 12;
for (let i = 0; i < numPecs; i++) {
  push(); rotate(radians(i * 360 / numPecs));
  fill(255, 200, 0, 200); noStroke();
  ellipse(40, 0, 25, 15);
  fill(255, 100, 0, 150);
  triangle(50, -8, 70, 0, 50, 8);
  pop();
}
fill(255, 255, 200); ellipse(0, 0, 30, 30);

Fórmula màgica del mandala: translate(centre); for(...){ push(); rotate(angle); dibuixaMotiu(); pop(); }

Exemples creatius pas a pas

Molí de vent animat

Utilitzem rotate() amb un angle que canvia al draw() per crear aspes que giren.

let angle = 0;
function draw() {
  background(135,206,235);
  translate(120, 120);
  fill(180,130,80); rect(-5, 0, 10, 40);
  push(); rotate(angle);
  for (let i=0; i<3; i++) {
    rotate(radians(120));
    fill(220,220,240); triangle(0,0, -15,-40, 15,-40);
  }
  pop(); angle += 0.02;
}

Flor concèntrica amb escala

Combinem scale() i rotate() per crear capes de pètals de mides decreixents.

translate(width/2, height/2);
for (let capa=0; capa<4; capa++) {
  push(); scale(1 - capa*0.2);
  for (let i=0; i<8; i++) {
    rotate(radians(45));
    fill(255, 100+40*capa, 150-30*capa, 150);
    ellipse(25, 0, 18, 8);
  }
  pop();
}
fill(255,255,0); ellipse(0,0,15,15);

Consells per treballar amb transformacions

  • Dibuixa sempre al voltant del (0,0) local dins de cada push()/pop(). Així el teu motiu serà fàcil de centrar i girar.
  • Utilitza radians(graus) per no haver de pensar en radians.
  • L'ordre recomanat dins d'un push()/pop(): primer translate(), després rotate() i/o scale(), i finalment dibuixa.
  • Per animar, utilitza una variable global per a l'angle i incrementa-la a cada draw().
  • Combina amb bucles per multiplicar l'efecte.

Exercicis per practicar

  1. Dibuixa un rellotge analògic: 12 marques horàries al voltant d'un cercle, utilitzant un bucle i rotate().
  2. Crea un "sol radiant" amb 16 raigs (línies) que surtin del centre, alternant longituds llargues i curtes.
  3. Dissenya una roda de carro: un cercle exterior, un de central, i radis (línies) cada 30 graus.
  4. Fes una espiral de quadrats: un quadrat que es repeteix 20 cops, cada cop girat 15° i escalat al 95%.
  5. Repte: Crea un calidoscopi digital: dibuixa un motiu al centre, i utilitza scale(-1,1) o múltiples rotate() per reflectir-lo en diferents eixos i omplir tot el llenç.

Reflexió artística

Les transformacions geomètriques són el cor de moltes formes d'art: des dels mandales budistes fins als vitralls gòtics, passant per l'op-art de Victor Vasarely. Amb rotate() i scale(), un sol motiu pot convertir-se en una composició hipnòtica. La bellesa de la simetria radial és que l'ull humà la troba natural i satisfactòria: la veiem a les flors, als estels de mar, a les rodes. Però també pots trencar la simetria introduint petites variacions, com fèiem amb random() al Tema 5, per crear obres que siguin alhora ordenades i sorprenents. Pensa en les transformacions com una dansa: tu decideixes els passos (translate, rotate, scale) i el motiu és el ballarí que els executa.

Mini-projecte del Tema 7

Crea un "Mandala generatiu personal" amb les següents directrius:

  • Utilitza translate() per centrar el mandala al llenç.
  • Defineix un motiu propi (combinació de formes, línies, colors) dins d'un bloc push()/pop() amb rotate().
  • Repeteix el motiu almenys 8 vegades al voltant del centre (360° / 8 = 45° entre cada un).
  • Incorpora almenys dues capes amb diferents escales (per exemple, una capa externa gran i una interna petita).
  • Utilitza colors amb transparència per crear superposicions interessants.
  • Opcional: anima el mandala fent que l'angle de rotació variï amb el temps (frameCount) o amb el ratolí.

Comparteix el teu mandala i explica el significat del motiu que has triat i com l'has construït.