Introduction : Génération

En informatique, le fait de générer une entité signifie produire cette entité et la matérialiser. Cette entité peut être de diverses natures : texte, son, image, données binaires, vidéo (en 2D ou 3D), etc. La matérialisation peut être volatile, c’est-à-dire non destinée à être stockée (affichage à l’écran, production d’un son dans des haut-parleurs, etc.) ou au contraire stockée c’est-à-dire enregistrée sur un support à long terme (disque dur, impression sur papier, CD-ROM, etc.).

Source : Wikipédia

La génération d’éléments visuels tel que des motif, qu’ils soient géométrique ou organique, est l’une des bases du “creative coding” orienté visuel. À travers ce thème, qui se déroulera sur deux cours, nous explorerons les possibilité de la génération offerte par le creative coding à travers deux sous thèmes :

  1. La génération géométrique, où la génération de forme et motif basé des systèmes de grilles ou de suite mathématiques
  2. La génération organique, où la génération de forme basé sur la simulation d’événement naturelles

Pour ce thème nous explorons la génération par l’utilisation de Processing, un framework et langage de développement basé sur JAVA.

Génération Géométrique

Rappel : introduction à la programmation dans Processing

Dans cette partie nous explorerons différents paradigme de la programmation. Ces paradigmes s’applique à différents langages tels que Java, C, C++, C#, Python… mais vous pourrez en rencontrer d’autres aux travers divers autres langages de programmation. Ici nous nous intéresserons aux langages “typés”.

Un programme est exécuté par un ordinateur qui suit les ligne d’instructions écrites afin de produire un résultat. L’ordinateur lit le programme de la même manière que nous lisons un texte, ligne par ligne.
Un programme utilise les paradigmes suivants :

  1. L’utilisation de variables pour “stocker” les données. Les variables sont des «mots-clefs» auxquels nous associons des valeurs afin de les stocker dans la mémoire du programme
  2. L’utilisation de fonctions pour effectuer des actions. Les fonctions sont des verbes, il s’agit d’action que nouse demandons à notre programme de réaliser, cela peut être un calcul, un dessin, une attribution de variables…
  3. L’utilisation d’opérateurs permettant d’effectuer divers calculs
  4. L’utilisation de structures conditionnelles permettant de réaliser des comparaison et poser des questions.
  5. L’utilisation de structures itératives ou boucles permettant d’effectuer une série d’action simultanée
  6. L’utilisation d’une fonction de lancement et d’une boucle.

Les Variables :

Une variable est un « mot clé » associé à une valeur. Cela permet de stocker en mémoire des valeurs sous un nom.

Par exemple si je place deux points de coordonnées 10, 10 et 20, 20 il me sera difficile en code de changer les coordonnées de mon deuxième point car je ne sais pas comment les appeler. Or, si je dis que mon premier point est placé en coordonnée x1, y2 et le seconde x2, y2 et que je défini par la suite x1 = 10 , y1= 10 et x2 = 20, y2 = 20 il m’est alors facile de changer la valeur de x1 en 30.

Il existe plusieurs types de variables dans Processing mais nous ne commencerons ici que par les principales. Nous avons donc :

  • boolean etat = true;
    Variable de type boolean ou binaire, il s’agit d’une variable ne pouvant renvoyer que deux valeurs : Vrai/Faux. Elle permet de faire des comparaisons par exemple « Cette robe est-elle rouge? » est un question demandant un réponse booleenne. « Oui elle est rouge » « non elle ne l’est pas »
  • int x = 10; est une variable renvoyant un nombre entier
  • float x = 3.141592; est une variable renvoyant un nombre décimal
  • String nom = « moi »; est une variable renvoyant une chaîne de caractères, elle permet de stocker des mots.
  • char nom = « a »; est une variable ne pouvant stocker qu’un caractère.

Les fonctions :

Une fonction désigne en programmation un « sous-programme » permettant d’effectuer des opérations répétitives. Au lieu d’écrire le code complet autant de fois que nécessaire, on crée une fonction que l’on appellera pour l’exécuter, ce qui peut aussi alléger le code, le rendre plus lisible. La définition de fonction est la suivante :

On appelle fonction une partie de code recevant une ou plusieurs informations à partir desquelles elle retourne une ou plusieurs informations. Les informations fournies à la fonction sont appelées arguments ou paramètres de la fonction. Les informations renvoyées par la fonction sont appelées résultat

Nous pouvons comparer la fonction à une «action à faire» par notre programme nous permettant ainsi de répéter cette action. Une fonction s’écrit de la manière suivante :

type nomDeLaFonction(paramètre){
     action à effectuer;
}

Nous distinguerons deux type de fonction :

Fonction retournant un résultat. Il s’agit d’une fonction «répondant» au programme en renvoyant un résultat.

int addition(int x1, int x2){
     return x1 + x2; 
}

L’exemple ci-dessus montre l’écriture d’une fonction renvoyant le résultat de x1+x2 permettant ainsi d’effectuer une action avec résultat Nous l’utiliserons de la manière suivante :

int resultat = addition(1, 2);

Ici résultat sera alors égale à 3

La procédure, où la fonction exécutant un action. Il s’agit d’une fonction ne renvoyant aucun résultat mais effectuant un action comme dessiner un objet sur la scène.

void dessinerUnePoint(int x, int y){
     Dessine un point aux coordonnées x, y
}

Nous noterons l’utilisation du mot void au début de la fonction permettant de définir que la fonction ne renverra aucun résultat.

Les opérateurs :

Ils permettent d’effectuer divers calculs ou comparaisons. Nous sommes ici dans des notions de bases des mathématiques.

Nous avons différents types d’opérateurs :

Les opérateurs arithmétiques

  • +, –, *, / qui permettent d’addition, soustraire, multiplier ou diviser des valeurs.
  • % le modulo qui permet de connaître la valeur d’un reste d’une division (valeur résiduelle) par exemple 17%3 = 2 car 2 est le reste de la division de 17/3

Les opérateurs d’assignation :

  • = permet d’attribuer une valeur à un variable
  • +=, -=, *=, /= permettent d’incrémenter, soustraire, multiplier ou diviser des valeurs par exemple x = x+1 est la même chose que x +=1;

Les opérateur d’accumulation :

  • +=, -=, *= /=, %= Les opérateurs d’accumulation sont des opérateurs qui ajoutent une valeur à la variable.
    Par exemple, ma variable var1 vaut 10. Je veux lui ajouter 5. Je peux écrire var1 = var1 + 5 ou var1 += 5. Cette expression est très souvent utilisée dans les boucles.

Les opérateurs relationnels

  • >, <, <=, =>, == , != permettent de comparer deux valeurs afin de savoir si celles-ci sont supérieur, inférieur, supérieur ou égale, inférieur ou égale, égale ou différentes. Ces opérateur ne renvoi que des valeurs booléennes, c’est à dire vrai ou faux. Par exemple 1 == 2 renverra la valeur « false » car 1 n’est pas égale à 2;

Les opérateurs logiques

&&, || permettent d’effectuer des opérations booléenne de type ET et OU.

Les structures conditionnelles

Les structures conditionnelles permettent de comparer des valeur de d’attribuer des conditions.

Par exemple j’aimerai pouvoir marcher que si mes lacets sont fait sinon je tombe pourrait s’écrire :

boolean lacetsFait = true; //ici mes lacets sont fait, si lacetFait = false alors il ne sont pas fait

boolean tombe; //ici la variable booléenne n'est pas encore définie car je ne sais pas encore si je vais tomber ou pas

if(lacetFait == true)
{
    tombe = false;
}
else{
    tombe = true;
}

Il existe différent type de structures conditionnelles tel que :

  1. Si. Structure conditionnelle simple permettant de vérifier une condition:
    Si x est égale à 3 alors j’effectue une action

    if(x == 3){
      //action
    }
  2. Si, sinon. Structure conditionnelle permettant de vérifier une condition ou non :
    Si x est égale à 3 alors j’effectue une action Sinon j’effectue une autre action

    if(x == 3){
      //action 1
    }else{
      //action 2
    }
  3. Si, sinon si. Structure conditionnelle permettant de vérifier plusieurs condition ou non :
    Si x est égale à 3 alors j’effectue une action Sinon si x est égale à 6 j’effectue une autre action, Sinon, j’effectue une tiers action.

    if(x == 3){
    //action 1
    }else if(x == 6){
    //action 2
    }else{
    //action 3
    }
  4. Switch/case. Structure conditionnelle permettant d’effectuer des actions selons des cas prédéfinis
    Dans le cas où x est égales à une valeur entière.
    Si x est égales à 3, j’effectue l’action 1,
    Si x est égales à 6, j’effectue l’action 2,
    Si x est égales à 9, j’effectue l’action 3,

    swicth(x){
       case 3 : //action 1
       break;
       case 6 : //action 2
       break;
       case 3 : //action 3
       break;
    }

Les structures itératives :

En mathématique, un itération est l’action de répéter un processus. La structure itérative permet d’effectuer une suite d’opération. Très utilisé pour effectuer plusieurs actions simultanées.

Par exemple, si je désire dessiner des lignes verticales de 100 pixels de haut et ce tous les 10 pixels de large je pourrais très bien écrire :

line(0, 0, 0, 100);
line(10, 0, 10, 100);
line(20, 0, 20, 100);
line(30, 0, 30, 100);
line(40, 0, 40, 100);
…

Et ce pour autant de largeur que je veux pour mon dessins. C’est assez simple pour un dessin de 100 pixel de large mais que ce passe-t-il pour 1920 pixels de large.
Je ne vais pas écrire 1920/10, soit 192 fois la même ligne? C’est là où la structure itérative entre en action. Elle va me permette de dire que pour une variable i égale 0 (mon départ); i toujours inférieur à 1920 (la limite de mon dessin) et i s’incrémentant de 10 pixels (cad pour i=0 puis 10, puis 20…) alors je dessine mes lignes. Ce qui donne :

for(int i = 0; i<1920; i+=10)
{
  line(i, 0, i, 100);
}

Ici nous pouvons traduire l’itération par la phrase suivante :

Pour un nombre entier i; i étant toujours inférieur à 1920; et i s’incrémentant de 10

for(int i = 0; i<1920; i+=10){}

La structure itérative s’écrit donc de la manière suivante :

for(type variable = valeurDeDépart; variable limité à; variable  s’incrémetant de){}

Une seconde forme de structure itérative existe et fonctionne sur un paradigme légèrement différent utilisant la notion de «Pendant que». Cette structure permet d’effectuer une itération tant qu’une certaines condition n’a pas été atteinte. Elle s’écrit de la manière suivante :

while(condition){
//action
}

Dans l’exemple suivant nous effectuerons une action tant que i est inférieur à 10; à chaque fin d’action nous incrémentons i de 1 afin de passer à l’itération suivante.

int i=0;
while(i < 10){
//action
i++;
}

 Fonction de lancement et de boucle du programme

La plupart des programmes se repose sur l’utilisation de deux fonctions principales :

  1. Fonction d’initialisation. Elle permet de lancer le programme. C’est ici que nous définirons la taille du programme, son mode de dessins ou que nous initialisons nos variables.
  2. Fonction de boucle. Fonction se répétant plusieurs fois par seconde. Il s’agit de la répétition général permettant de lire le programme frame par frame.

Dans processing ces fonctions s’écrivent de la manière suivante :

void setup()
{
    size(710, 200);
}

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

Les grille cartésienne

La grille est l’un des éléments principaux du design graphique, on la retrouve dans de nombreux domaines tel que :

  1. La mise en page
  2. Les frises
  3. Les pavage (ou pattern)
  4. Compositions d’images

En design graphique la grille est un structure (souvent en 2 dimensions) réalisé par partir d’un série d’intersection entre des éléments (généralement des ligne horizontale et vertical). Pour en savoir plus sur la grille de mise en page je vous invite à vous rendre sur le site de l’atelier Nun :

La grille de mise en page a été théorisée par le graphiste suisse Joseph Muller Brockmann dans les année 1960, notamment dans son ouvrage Grid Systems in Graphic Design. Elle permet de découper le format dans sa largeur (et plus tard dans sa hauteur) en plusieurs parties égales, séparées par des espaces verticaux. L’usage des colonnes ainsi créées permet de travailler avec des « zones », proportionnelles entre elles, ce que l’œil du lecteur perçoit immédiatement.

Source : Nun Design

Dans le cas d’un motif ou d’un frise, la grille permet de définir la structure en 1, 2 ou 3 dimensions de répétition d’une forme (1 dimension pour la frise et 2 pour le motif). On retrouve l’utilisation de ces motifs dans de nombreux travaux graphiques tel que :

Réalisation d’une grille cartésienne

En géométrie un espace cartésien est un espace géométrique permettant de définir la position d’un point dans un espace munie d’un repère cartésien définie par droite x, y et z (horizontal, vertical, et en profondeur)

Afin de réaliser notre motif nous allons utiliser ce système de grille afin de définir les coordonnées de notre motif à répéter sur les axe x et y.

Pour cette exercice nous utiliserons un motif simple, le rectangle.

Cette forme est définie par les variables suivantes :

  1. Coordonnées x,y placées en son centre
  2. Taille définie par une largeur et une hauteur

La frise

Dans un premier temps nous allons réaliser une frise. Une frise est un répétition, sur un axe, d’un motif. Dans notre cas nous réaliserons notre frise sur l’axe X.

La frise étant composé d’une répétition de motif nous pouvons la réaliser en utilisant un structure itérative. En effet ces structure nous permettent de réaliser une répétition d’action (ici le dessin d’un rectangle). Si nous regardons notre frise de prêt nous pouvons la décomposer de la sorte

Définir le nombre de répétition des motifs :

Pour un nombre i étant égale à 0;
Ce nombre i étant toujours inférieur à 5;
Et ce nombre s’incrémentant de 1; 


Pour chacun de ce nombre :
→ Nous définissons une position x étant égale à la position précédent + un certain écart (ici la largeur d’un rectangle)
→ Nous dessinons ce rectangle


Dans processing nous traduisons cela par la structure suivante :
for (int i=0; i<5; i++) {
    float newX = x + i * largeur;
    rec

Par la suite nous pouvons ajouter diverse variations à notre frise tel qu’une marge séparant les formes, une variation de couleur, de tailles…

** Algorithm tips : le modulo **

Nous pouvons facilement réaliser une frise à plusieurs motif tel que défini par le modèle suivant :

Si nous pouvons définir cette frise par les instruction suivantes :

Définir le nombre de répétition des motifs :

Pour un nombre i étant égale à 0;
Ce nombre i étant toujours inférieur à 6;
Et ce nombre s’incrémentant de 1; 


Pour chacun de ce nombre :
→ Nous définissons une position x étant égale à la position précédent + un certain écart (ici la largeur d’un rectangle)
→ Une fois sur deux nous dessinons un rectangle ou une ellipse

Le problème principale étant de résoudre le problème “Une fois sur deux”; pour ce faire nous utiliserons le modulo (%). Le modulo (%), en programmation, permettant d’obtenir le reste d’une division.
Par exemple si la division de 5 par 2 donne le résultat 2, nous aurons un reste de 1. Ainsi le modulo de 5 par 2 nous renverra le résultat 1

5/2 = 2 avec un reste de 1
5%2 = 1 soit le reste de la division de 5 par 2

Lorsque nous effectuons un modulo sur un suite de nombre E divisée par une certain nombre X nous obtenons un résultat intéressant. En effet le modulo nous renverra une suite de résultat se répétant en fonction du dénominateur (diviseur). Ainsi nous obtenons les résultats suivant :

→ Soit une suite de nombre allant de 0 à 5 en incrémentant de 1
→ Soit un dénominateur X

Si X = 2
  0%2 = 0
  1%1 = 1
  2%2 = 0
  3%2 = 1
  4%2 = 0
  …

Si X = 3
  0%3 = 0
  1%3 = 1
  2%3 = 2
  3%3 = 0
  4%3 = 1
  5%3 = 2
  ...

Si X = 4
  0%4 = 0
  1%4 = 1
  2%4 = 2
  3%4 = 3
  4%4 = 0
  5%4 = 1
  6%4 = 2
  7%4 = 3
  ...

Nous pouvons donc facilement définir notre changement de forme une fois sur deux par l’utilisation d’un modulo de 2 (%2) et d’un condition. En effet il nous suffit de savoir si le modulo de l’itération en cours (défini par i) renvoie un nombre pair (0) ou impaire (0). Dans le premier cas nous dessinerons un rectangle, sinon nous dessinerons une ellipse.

for (int i=1; i<5; i++) {
    float newX = x + i * largeur;
    if (i%2 == 0) {
      ellipseMode(CORNER);
      ellipse(newX, y, largeur, hauteur);
    } else {
      rect(newX, y, largeur, hauteur);
    }
  }

Le Pavage

Nous allons maintenant réaliser un pavage. Un pavage est une répétition d’un motif sur plus d’un axe. Il s’agit d’une évolution de la frise. Ici nous réaliserons un pavage sur deux dimensions

Lorsque nous observons le pavage nous remarquons qu’il s’agit d’une répétition de la frise que nous avons précédemment réalisé. En d’autre terme nous pourrions dire :

Un pavage est la répétition d’une frise qui est elle même la répétition d’un motif (inception!!!!).

Si un pavage est la répétition d’un répétition nous pouvons donc le définir de la manière suivante :

Définir le nombre de répétition des frise :

Pour un nombre i étant égale à 0;
Ce nombre i étant toujours inférieur à 5;
Et ce nombre s’incrémentant de 1; 

Définir le nombre de répétition des motifs :

Pour un nombre j étant égale à 0;
Ce nombre j étant toujours inférieur à 5;
Et ce nombre s’incrémentant de 1; 


Pour chacun de ce nombre :
→ Nous définissons une position x étant égale à la position précédent + un certain écart (ici la largeur d’un rectangle)
→ À chaque nouvelle frise nous définissons une position y étant égale à la position précédent + un certain écart (ici la hauteur d’un rectangle)
→ Nous dessinons ce rectangle

Dans processing nous traduisons cela par la structure suivante :
for (int i=0; i<3; i++) {
    for (int j=0; j<5; j++) {
      float newX = x + j * largeur;
      float newY = y + i * hauteur;
      rect(newX, newY, largeur, hauteur);
    }
  }

Comme pour la frise, nous pouvons ajouter diverse variations à notre frise tel qu’une marge séparant les formes, une variation de couleur, de tailles…

La grille Polaire

Nous l’avons vu la grille cartésienne est un élément permettant de réaliser des répétition de motif sur les axes XY que ce soit des frises ou des pavages. Cependant il ne s’agit pas du seul système de coordonnées possible. Parmi les différents systèmes de coordonnées il en est un que nous retrouvons régulièrement dans les arts graphique, le VFX ou les jeux vidéo : le système de coordonnées polaires

Réalisation d’une grille polaire

En géométrie un espace polaire est un espace géométrique à deux dimensions dans lequel les coordonnées d’un point sont définie par une valeur d’angle et une distance (rayon).

Ce système de coordonnées et particulière pratique dans la création de systèmes circulaires tels que les pendules, spirales ou autre. Pour réaliser un système polaire il est nécessaire de connaître l’équation nous permettant de positionner un point sur un cercle à partir d’un angle et d’une distance.

** Algorithm tips : le rapport trigonométrique **

La trigonométrie traite des relations entre distances et angles dans les triangles et notamment dans le triangle rectangle. C’est ce dernier qui va nous intéresser plus particulièrement.

Faisons un rapide bon dans le passé concernant ce triangle. Un triangle rectangle se caractérise par un angle droit (90°) et la somme de ses angles est égale à 180°. L’angle droit est donc son angle le plus grand. Enfin le côté opposé à cet angle s’appel l’hypoténuse et se caractérise par le fait qu’il est le côté le plus grand de ce triangle.

Si on s’intéresse à l’angle BAC et aux fonctions trigonométriques alors nous remarquons que :

  1. sin(BAC) = a/c
  2. cos(BAC) = b/c
  3. tan(BAC) = a/b

Nous avons ici les fonctions auxquelles nous allons prêter attention. Allons maintenant plus loin en traçant un cercle dont l’origine sera A et de rayon AB (notre hypothénuse). Partons du principe que notre hypoténuse AB a une valeur de 1. Nous obtenons alors un cercle trigonométrique.

Si on observe ce cercle nous remarquons que les coordonnées du point B peuvent être définies de la sorte :

  1. x = cos(t)
  2. y = sin(t)

Or nous savons ici que notre hypothénuse à un valeur de 1. Si nous voulons être correcte dans nos cordonnées, nous obtenons :

  1. x = cos(t) * 1
  2. y = sin(t) * 1

Nous venons de voir la formule permettant de calculer les coordonnées d’un point sur un cercle. Nous avons ici l’une des formules que nous utiliserons le plus dans nos programmes par la suite.

  1. x = cos(angle)*rayon
  2. y = sin(angle)*rayon

Nous venons de voir à quoi les fonctions trigonométriques Sinus et Cosinus pouvaient nous être utile, attardons nous maintenant sur la dernière, la Tangente. La tangente est le rapport du sinus au cosinus, par définition :

  1. tan(angle) = sin(angle)/cos(angle)

On appelle tangente de l’angle aigu , le nombre noté tan(angle) défini par BC/AC. Nous savons aussi que la tangente d’un angle est égale au côté opposé / côté adjacent ou dans notre cas à b/a. Pour obtenir notre angle il nous faudra alors obtenir l’inverse de cette tangente. Ainsi l’angle BAC sera égale à :

  1. angle = atan2(a, b);

La frise polaire

Une fois que nous connaissons l’équation permettant de placer un point sur un cercle nous pouvons facilement réaliser la frise suivante :

Nous l’avons vu précédemment, la frise étant composé d’une répétition de motif nous pouvons la réaliser en utilisant un structure itérative. Nous pouvons définir la frise de la manière suivante

Définir l’origine XY du motif
Définir la distance/rayon depuis l’origine
Définir le nombre de répétition des motifs

Pour un nombre i étant égale à 0;
Ce nombre i étant toujours inférieur à 8;
Et ce nombre s’incrémentant de 1; 

Pour chacun de ces nombres :
→ Nous définissons un angle pour chacun des motif où ce dernier est égales à 360/nombre d'itération * l'itération actuelle
→ Nous définissons les coordonnées XY du point à l’aide de l’équation : 
x = cos(angle)*rayon
y = sin(angle)*rayon
→ Nous dessinons une ellipse

Dans processing nous traduisons cela par la structure suivante :
for (int i=0; i<8; i++) {
    float angle = radians(360/8 * i);
    float newX = x + cos(angle) * rayon;
    float newY = y + sin(angle) * rayon;
    ellipse(newX, newY, largeur, hauteur);
  }

** Algorithm tips : Rotation d’un élément et matrices **

Lorsque nous dessinons sur nos écrans, nous travaillons sur une grille, une matrice. Dans le cas d’une réalisation de maquette pour un site web, nous travaillons, par exemple, sur des .psd de 1280*1024 soit une grille de pixels de 1280*1024, c’est notre matrice. Nous plaçons ensuite nos éléments sur cette grille. Il en est de même avec nos programmes où notre grille commence au point d’origine 0, 0 pour finir au point width, height. Nous allons voir comment manipuler cette matrice.

Par défaut le point d’origine (0, 0) de notre matrice se trouve au coin supérieur gauche de notre programme mais il peut être facilement déplaçable.

Déplacer une matrice signifie que l’on décale son point d’origine à un autre endroit. Cela nous donne un autre point de vue et change notre système de géométrie.

Il peut être pratique de déplacer son point d’origine au centre du programme, notamment lorsque nous souhaitons réaliser un programme en symétrie. Ainsi dans le cas d’un rectangle de position 10, 10 dans une symétrie axiale, dont le point d’origine sera le centre de notre programme, le second rectangle aura une position de -10, 10 soit l’inverse de la position x du premier rectangle.

Afin d’effectuer un déplacement de matrice dans processing, nous utilisons la méthode suivante :

translate(x, y);

Cela aura pour effet de déplacer la matrice de x pixels en latéral et y pixels en vertical. Le point d’origine 0,0 sera alors en x, y. Il est important de savoir que cette méthode est cumulative, c’est à dire que si nous effectuons, tout au long de notre code, les méthodes suivante :

translate(10, 10);
//code
translate(10, 10);
//code
translate(10, 10)
//code

Cela aura pour effet de déplacer une première fois notre matrice en 10,10 puis en 20, 20 puis en 30, 30. Nous devrons donc effectuer un déplacement inverse si nous souhaitons positionner la matrice à son premier point d’origine.

Afin d’éviter de nombreuses transformations retour durant notre code, il est possible d’isoler notre déplacement de matrice à l’aide des méthodes suivante :

pushMatrix();
translate(10, 10);
//code
popMatrix();

pushMatrix() permet à un instant T d’enregistrer les coordonnées du point d’origine afin de pouvoir les restituer à l’aide de la commande popMatrix()

À l’exécution de ce code, la matrice se déplacera en position x, y lors de la méthode translate(), puis reviendra à son point d’origine lors de la méthode popMatrix(). Cela nous permet donc de changer notre géométrie à un instant T et de dessiner l’ensemble de nos formes voulues dans ce nouveau système de géométrie encadrée par les méthodes pushMatrix(); popMatrix();

La rotation d’un élément est un cas particulier. Pour bien comprendre son fonctionnement revenons au point de vue microscopique de notre espace de travail, le pixel.

Nous souhaitons dessiner un rectangle de position 10, 10 et de taille 10, 10.Puis nous souhaitons effectuer un rotation de 45° de ce même rectangle. Le pixel est un élément dessiné, 0 ou 1, plein ou vide, il ne peut être rempli de manière partielle. Lorsque nous effectuons ce genre de manipulation dans photoshop, notre logiciel dessine notre diagonale sous forme de pixels pleins ou vides.

Cette transformation utilisée par photoshop n’est pas la plus simple à réaliser et processing utilise un autre méthode.

Au lieu de redessiner les pixels de notre rectangle, nous allons effectuer une rotation de notre espace de coordonnées à l’aide la méthode suivante :

rotate(angle);

(Nous noterons que processing définit ses angles en radians). Cette méthode permet donc faire faire une rotation à notre matrice et ce depuis son point d’origine.

Pour obtenir notre rectangle à une véritable position 10, 10 et ayant effectué une rotation à 45° nous devons donc déplacer la matrice un premier temps, puis effectuer la rotation.

Nous utilisons alors la méthode suivante :

pushMatrix()
translate(10, 10);
rotate(degrees(45));
//dessins
popMatrix();

 Le pavage polaire

Nous allons maintenant réaliser un pavage polaire.

Le pavage étant un répétition de répétition nous utiliserons une double structures itérative :

Définir l’origine XY du motif
Définir le nombre de répétition de frise

Pour un nombre i étant égale à 0;
Ce nombre i étant toujours inférieur à 2;
Et ce nombre s’incrémentant de 1; 

Définir le nombre de répétition des motifs

Pour chacun de ces nombres :
→ Nous définissons un rayon égale à la multiplication de l’itération par une certain nombre N

Pour un nombre i étant égale à 0;
Ce nombre i étant toujours inférieur à 8;
Et ce nombre s’incrémentant de 1; 

Pour chacun de ces nombres :
→ Nous définissons un angle pour chacun des motif où ce dernier est égales à 360/nombre d'itération * l'itération actuelle
→ Nous définissons les coordonnées XY du point à l’aide de l’équation : 
x = cos(angle)*rayon
y = sin(angle)*rayon
→ Nous dessinons ce rectangle

Dans processing nous traduisons cela par la structure suivante :
for (int i=0; i<2; i++) {
    float rayon = rayonRef + rayonRef * i;
    for (int j=0; j<8; j++) {
      float angle = radians(360/8 * j);
      float newX = x + cos(angle) * rayon;
      float newY = y + sin(angle) * rayon;
      pushMatrix();
      translate(newX, newY);
      rotate(angle);
      rect(0, 0, largeur, hauteur);
      popMatrix();
    }
  }

** Algorithm tips : Rotation d’un élément et matrices **

Nous pouvons facilement ajouter une variation graphique à notre motif pour l’utilisation d’une valeur pseudo-aléatoire. En programmation on appel ces valeurs pseudo-aléatoire car elle sont définie par une équation et sont donc prévisible, cependant elles offre une large possibilité de variations. L’un de ces aléatoires est l’aléatoire brownien.

Le bruit brownien est un aléatoire où les valeurs produites sont réparties de manière totalement aléatoire. Chaque valeur pourra être grandement espacée les une des autres ou totalement proche voir identique. Une répartition brownien peut être imaginé par ce schema :

Dans processing le bruit brownien est produit par la fonction :

Float aleatoire = random(valeur minimum, valeur maximum)

 Rappel des algorithmes et méthodes

  1. Nous utilisons d’une structure itérative for() afin de réaliser une frise (répétition sur un axe)
  2. Nous pouvons utiliser un modulo (reste d’une division) pour définir un certain nombre de répétition égale au dénominateur de l’opération.
  3. Nous utilisons une double structure itérative for(for()) afin de réaliser un pavage (répétition sur deux axes)
  4. La position d’un point sur un cercle est définie par
    1. X = cos(angle) * rayon
    2. Y = sin(angle) * rayon
  5. Dans Processing nous pouvons définir un point d’ancrage à notre élément via la méthode :

    pushMatrix()
    translate(position x, position y);
    rotate(degrees(angle));
    //dessins à la position 0, 0
    popMatrix();
  6. Dans processing nous pouvons définir une valeur aléatoire via la fonction suivante : 
    random(valeur minimum, valeur maximum)

Pour aller plus loin

Réaliser les exercices suivant :

  1. Réaliser un pavage à 3, 4, ou 5 formes
  2. Définir un élément du motif en fonction d’une répétition (1 sur 2, 1 sur 3…) par l’utilisation d’un modulo
  3. Ajouter une marge à vos motifs
  4. Réaliser un motif à partir d’autres formes tel que des lignes, des triangle, des ellipse…)
  5. Réaliser un motif avec une rotation de ce dernier
  6. Réaliser un pavage à l’aide d’aléatoire

Annexes :

  1. Processing références : https://processing.org/reference/
  2. Ixd.education : introduction à processing : http://ixd.education/2013/10/digital-lab-introduction-a-processing-2-03/
  3. Définition des routines : https://fr.wikipedia.org/wiki/Routine_(informatique)
  4. Introduction générale à la programmation : https://fr.wikiversity.org/wiki/Introduction_g%C3%A9n%C3%A9rale_%C3%A0_la_programmation
  5. Principles of Design : https://docs.google.com/presentation/d/1QkXHGhG5xLnuziBpV72MuESpBEX7Y3478iDi0-viR5k/edit#slide=id.g19ef2af6f9_0_6
  6. Grille de mise en page : principe et utilisation : http://www.nundesign.fr/transmettre/espace-pedagogique/fondamentaux/grille-de-mise-en-page-principe-et-utilisation
  7. La division : https://fr.wikipedia.org/wiki/Division
  8. Grilles et répétitions de motifs : http://ixd.education/2013/10/digital-lab-grilles-et-repetitions-de-motifs-structures-iteratives-conditionnelles/
  9. Transformations 2D : http://ixd.education/2014/02/digital-lab-transformations-2d/
  10. Retour sur les bases de la trigonométrie : http://ixd.education/2013/03/digital-lab-retour-sur-les-bases-de-trigonometrie/
  11. Système de coordonnées polaires : https://fr.wikipedia.org/wiki/Coordonn%C3%A9es_polaires
  12. L’aléatoire brownien et Perlin : http://ixd.education/2013/03/digital-lab-aleatoire-bruit-brownien-et-bruit-perlin/