Disegnare onde su reticoli con Processing

processing_logo

Introduzione

Circa una settimana fa, mentre navigavo su Google+ mi capita di vedere una GIF animata che rappresentava una serie di palline nere che orbitavano intorno a dei punti di un reticolo. Queste palline avevano gli angoli sfalsati tra di loro e ruotando tutte insieme davano al complesso l’immagine di un onda che scorre attraverso una superficie.

Questa immagine mi ha colpito così tanto che stamattina ho deciso di realizzarla scrivendo il codice con Processing.

Purtroppo ho perso i riferimenti di quella immagine. Quindi non so assolutamente di cosa parlava o chi ne era l’autore. Comunque, chiunque dovesse avere qualche informazione al riguardo, potrebbe cortesemente aggiungere un commento alla fine dell’articolo?  

Ecco all’incirca come era l’immagine… (in realtà questa è mia e l’ho generata con Processing)

WaveOnLatticeHead

Implementiamo il codice con Processing

Scrivere il codice di una animazione come questa è un lavoro che può essere complesso con altri tipi di linguaggi, ma con Processing può rivelarsi davvero facile. Infatti Processing è un linguaggio (in realtà si basa su Java) creato appositamente per la realizzazione di applicazioni grafiche e soprattutto di animazione.

Per chiunque non conoscesse Processing consiglio di andarsi a leggere l’articolo Una breve introduzione a Processing.

processing_wave_on_lattice

Una volta aperto l’IDE di Processing create un nuovo sketch e scrivete il codice sottostante.

//Waves_on_Lattice animation written by F.Nelli (26-Mar-2014)

int w = 700;
int h = 400;
int r = 10; // r>4
int n_h,n_w;
int k = 0;

void setup(){
  size(w,h);
  background(255);
  n_h = h/(2*r);
  n_w = w/(2*r);
}

void draw(){
  background(255);
  for (int i=0; i < n_w; i++)
    for(int j=0; j < n_h; j++) {
      int cx = (2*i+1)*r;
      int cy = (2*j+1)*r;
      ellipse(cx,cy,2*r-4,2*r-4);
      fill(0);
      int dx = (int)((r-2)*sin(radians((i+j+k)*12)));
      int dy = (int)((r-2)*cos(radians((i+j+k)*12)));
      ellipse(cx+dx,cy+dy,4,4);
      fill(255);
    }
    k++;
}

Incredibile vero? Questo è un codice non supera le 30 righe!! Questo perchè Processing ci permette di concentrare l’attenzione solo su quello che vogliamo disegnare. La gestione grafica, la chiamata agli oggetti, le classi, gli stream, ecc, sono gestiti implicitamente. Chi programma su Processing deve pensare solo ad implementare le figure geometriche e l’algoritmo che le utilizza.

Eseguiamo il codice ed ecco il risultato:

Wave On Lattice

Diamo un’occhiata veloce al codice.

int w = 700;
int h = 400;
int r = 10; // r>4
int n_h,n_w;
int k = 0;

In queste righe definiamo i parametri w e h, che sono rispettivamente la larghezza e l’altezza della finestra (area di disegno). Con r definiamo la distanza tra i punti del reticolo (i centri delle circonferenze), mentre n_h e n_w sono delle variabili che serviranno a contenere di quanti punti sarà composto il reticolo orizzontalmente e verticalmente. Infine k che è la variabile contatore per l’animazione.

void setup(){
  size(w,h);
  background(255);
  n_h = h/(2*r);
  n_w = w/(2*r);
}

All’interno della funzione setup( ) definiamo tutto il codice inerente all’inizializzazione dell’applicazione. Con size( ) disegnamo la finestra e con background( ) ne definiamo il colore di sfondo (bianco). Ci calcoliamo poi quanti punti avrà il reticolo per ricoprire l’area di disegno sia orizzontalmente che verticalmente.

void draw(){
  background(255);
  for (int i=0; i < n_w; i++)
    for(int j=0; j < n_h; j++) {
      int cx = (2*i+1)*r;
      int cy = (2*j+1)*r;
      ellipse(cx,cy,2*r-4,2*r-4);
      fill(0);
      int dx = (int)((r-2)*sin(radians((i+j+k)*12)));
      int dy = (int)((r-2)*cos(radians((i+j+k)*12)));
      ellipse(cx+dx,cy+dy,4,4);
      fill(255);
    }
    k++;
}

Infine all’interno della funzione draw( ) definiamo tutto il codice che dovrà eseguito per realizzare l’animazione. Per chi non lo sapesse, la funzione draw( ) viene eseguita iterativamente come fosse all’interno di un circolo “while“infinito. Abbiamo già detto che k è il contatore che partirà dal valore 0 (definito in setup()) e andrà via via crescendo di unità in unità (k++). Un reticolo come quello che vogliamo realizzare, non è altro che una circonferenza con un pallino al suo interno ripetuta sia orizzontalmente che verticalmente. Per implementare quindi il reticolo utilizziamo un doppio ciclo for() annidato. All’interno di questo doppio ciclo, ci calcoliamo le coordinate del centro di ciascuna circonferenza, cioè cx e cy. Poi disegnamo la circonferenza stessa con la funzione ellipse(). Ci calcoliamo poi le coordinate del pallino nero che orbita intorno al centro. Lo possiamo fare calcolandoci l’orbita intorno a tale centro, tenendo conto però dello sfasamento di ciascuno punto (con i e j) e del movimento da effettuare frame per frame per ottenere l’animazione (con k). Infine li disegnamo anch’essi con la funzione ellipse().

Giocando con le equazioni delle orbite dei pallini è possibile ottenere tantissimi effetti. Provate per esempio questa combinazione che darà un “effetto a bandiera” all’animazione.

int dx = (int)((r-2)*sin(i*radians(10+j+k)));
int dy = (int)((r-2)*cos(i*radians(10+j+k)));

Lascia un commento