Quase espirais…

Na última sessão, mais do que um estudante quiseram abordar o desenho do retrato generativo com algoritmo diferente: provocar uma espécie de “raiado” que vai do centro para fora da imagem.

Como o Processing desenha “por cima” o que desenha em último, este raiado tem que ser produzido de fora para dentro. E, como nós estamos a percorrer a imagem pixel-a-pixel e linha-a-linha por ordem as primeiras tentativas de percorrer a imagem geram um artefacto estranho quando se cruza “o meio” da imagem. Fica metade bem, e metade mal.

Assim, quase imediatamente, surgiu a ideia de fazer um algoritmo de espiral. Mas, o problema é como fazer isto com um sistema de regras simples (sem usar matrizes de dados / vetores bidimensionais)?

A solução que surge imediatamente no stackoverflow parece-me muito visual e adequada. Mas, o logo de imediato sugere o conceito de uma matriz de vetores bidimensionais:

https://stackoverflow.com/questions/398299/looping-in-a-spiral

A ideia está lá, de forma crua num par de soluções (de python e c++). Agora que as vejo depois de fazer a minha, apercebo-me de quão primitiva é a minha pilha condicional! 🙂

Mas pronto. Arregaçadas as mangas, e passado um pouco, consegui converter a decisão de percorrer uma imagem ou matriz de dados em espiral, de forma a obter uma rotação completa e evitar artefactos de simetria.

Ainda há aspetos a corrigir. Por exemplo, percorrer a imagem sem ser de forma simétrica a partir de qualquer ponto—na realidade era isso que queria, mas a dificuldade de fazer isto sem sem em active mode foi esmagadora da experiência. Por isso, fica aqui esta solução que já resolve (?) e no próximo módulo podemos atacar de novo o problema com matrizes como deve ser 😉

// Square spiral algorithm from Bruno B. (from T2) and… ??? from T1
// FBAUP/LSI/P1 Portrait idea/sketch base code
// PAmado, 2021-03-12

// declare variables
int ts;               // tile size
int nh, nv;           // number of horz. and vert. tiles

int iph, ipv;         // initial positions
int counth, countv;   // position counters

float col;              // gradient color value 

size(1000, 500);
background(255);
ts = 50;              // size of tiles

nh = width/ts;        // number of tiles on screen
nv = height/ts;

iph = 1;              // initial tile position
ipv = 1;

counth = nh - iph;   // number of tiles left in the row/column after the chosen position
countv = nv - ipv;

col = 255;           // initial color value to draw a trail of tiles

textSize(ts*0.3);    // debug tile numbers…
noStroke();

// set the tile board
for (int k = 0; k < nv; k++) {
  for (int i = 0; i < nh; i++) {
    
    stroke(0);
    line(i*ts+ts, k*ts, i*ts, k*ts+ts);
    
    noStroke();
    fill(200);
    rect(i*ts + ts*0.1, k*ts + ts*0.1, ts *0.8, ts *0.8);
    
    
  }
}


noStroke();

// determine the total tiles available on the board
int total = (nv-ipv*2) * (nh-iph*2);

// draw a tile (set x and y of the tile in the initial position) <-- I didn't really have to do this… but it helps me think ;)
int x = iph;
int y = ipv;

// you will be placing the tile somewhere… 
// take the initial position out of the counters of the remaining positions!…
counth--;
countv--;

// set an initial direction 1: right, 2: down, 3: left, 4: up…
int dir = 1;

int number = 1; // display a text counter for visual debug

// move it to a specific direction in a loop 
// start in the initial position and loop for the rest of the available positions in the board
for (int i = 0; i < total; i++) {

  // draw the tile
  noStroke();
  fill(col, 0, 0);
  rect(x*ts + ts*0.2, y*ts + ts*0.2, ts*0.6, ts*0.6);

  fill(255);
  text(number, x*ts + ts*0.3, y*ts + ts*0.7);

  // update the position
  // if… go right
  if (dir == 1) {
    x++;
    println("going right");

    // check if at the end of horizontal space right
    if (x > counth-1) {
      dir = 2;
      counth--;
      println("changing dir down");
    }
  } else if (dir == 2) {
    y++;
    println("going down");

    // check if at the end of vertical space down
    if (y > countv-1) {
      dir = 3;
      countv--;
      println("changing dir left");
    }
  } else if (dir == 3) {
    x--;
    println("going left");

    // check if at the end of horizontal space left
    if (x < nh-counth-1) {
      dir = 4;
      //counth--; // <-- I haven't checked for alternate starting directions other than right… you might need to do an aditional verification/boolean to make this bullet proof for eery starting direction…
      println("changing dir up");
    }
  } else if (dir == 4) {
    y--;
    println("going up");

    // check if at the end of vertical space up

    if (y < nv-countv) {
      dir = 1;
      // counth--;
      println("changing dir right");
    }
  }

  // update the color
  col -= 255/float(total) ;
  
  // update the text number counter
  number++;
  
  println(number);
}

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *