1

Im trying to make each square in my grid randomly rotated, so each one has a diffrent angle, but instead i rotate all of my squares. I dont understandt why, as both the rotate and the rect is drawn once at a time inside of the for loop?


int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));


void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {

      pushMatrix();
      rotate(radians(rando));
      rect(x, y, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}
Soma Juice
  • 369
  • 1
  • 11

1 Answers1

2

You're on the right track using pushMatrix()/popMatrix() to isolate coordinates for each square.

The gotcha is with rect() as it "hides" a translation.

This lines:

rotate(radians(rando));
rect(x, y, rectSize, rectSize, 10);

roughly works as:

rotate(radians(rando));
translate(x, y);
rect(0, 0, rectSize, rectSize, 10);

and (as you can see in the 2D Transformations tutorials) the order of operations is important.

In your case, you want to translate first, then rotate (from that translated position):

translate(x, y);
rotate(radians(rando));
rect(0, 0, rectSize, rectSize, 10);

In conclusion, your code would look like this:


int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));


void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {

      pushMatrix();
      translate(x, y);
      rotate(radians(rando));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

Update If you want to rotate each square with a different random value you need to calculate one for each square.

You could so something like this:


int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));


void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      rando = random(55);
      pushMatrix();
      translate(x, y);
      rotate(radians(rando));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

Pretty easy, right ? Re-calculate the value! There's a catch here too :) If you do this, random is re-calculated not just once per square, but also per frame so you'll end up with very jittery squares.

That is you need to re-draw the same squares again and again (even though the content doesn't change). If you simply want a static image, you can skip draw() and just use setup():

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;

void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
  
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {

      pushMatrix();
      translate(x, y);
      rotate(radians(random(55)));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }
}

Even "immediate mode", with no setup() will result in the same image:

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;

size(900, 900);


noStroke();
fill(40);
rectMode(CENTER);

background(255);
for (int x=marginX; x<width; x+=xStep) {
  for (int y=marginY; y<height; y+=yStep) {

    pushMatrix();
    translate(x, y);
    rotate(radians(random(55)));
    rect(0, 0, rectSize, rectSize, 10);
    popMatrix();
  }
}

Let's assume you do want draw() because you might want to use a keyboard shortcut or a mouse click to re-randomise values.

To get around the limitation you'd need to calculate the random values for each square once, then simply retrieve these values when rendering.

That means you'd need a structure to store each random value per square to which you write values once in setup() and read repeatedly in draw(): an array can easily solve you problem.

Since you're using nested for loops you could use a 2D array. Just remember that x,y counter in your loop are absolute pixel coordinates and you'd need separate indices for array access. That's easy enough to: simply divide x,y by the pixel increment and it will the 'step' counter:

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
// store random values for each square
float[][]randos;

void setup() {
  size(900, 900);
  
  // initialise random array
  randos = new float[width / xStep][height / yStep];
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      // calculate array indices
      int xIndex = x / xStep;
      int yIndex = y / yStep;
      // write random values
      randos[yIndex][xIndex] = random(55);
    }
  }

  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      // calculate array indices
      int xIndex = x / xStep;
      int yIndex = y / yStep;
      pushMatrix();
      translate(x, y);
      // read random values
      rotate(radians(randos[xIndex][yIndex]));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

The array can also be 1D, just need to count differently:

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
// store random values for each square
float[] randos;

void setup() {
  size(900, 900);
  
  // initialise random array
  int numSquares = (width / xStep) * (height / yStep);
  randos = new float[numSquares];
  int index = 0;
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      randos[index++] = random(55);
    }
  }

  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  int index = 0;
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      pushMatrix();
      translate(x, y);
      rotate(radians(randos[index++]));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

(As a next step you can encapsulate the part in setup which initialises the array with random values into a function: this would allow you reset/recalculate new random values whenever you call this function again (e.g. on mouse click/key press/etc.)

George Profenza
  • 50,687
  • 19
  • 144
  • 218
  • thanks for the answer was quite usefull,but i did not express myself clear i see now, what i meant was that each square individually was rotatated with a random angle – Soma Juice Mar 26 '22 at 20:16