Dividing a grid into sections using noise

Hello,

I keep coming back to an idea which I don’t know how to implement correctly or approach effectively.
I want to use noise to organically/dynamically subdivide a grid into smaller sections, whilst always remaining the same width in total (also: is this an example of a deterministic algorithm?).
The best way I have seen this visualised is this Instagram post by user fxpx.

The one idea which I’ve come up with which I’ve managed to get working is making a row of rectangles (or ‘cells’ if you will) where every rectangle’s width is calculated based on noise, and the position of each is calculated as the sum of the previous cell’s widths. The last cell’s width would be calculated by subtracting the total sum from the width of the grid. Here’s a simple example:

int row = 5;

float[] w;
float h = 50;
float x, y;

float t, incr;

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

  incr = .01;

  w = new float[row];
  for (int i = 0; i < row; i++) {
    w[i] = random(10, (width/10));
  }
}

void draw() {
  background(0);
  
  noFill();
  stroke(-1);
  newWidths();
}

void newWidths() {
  float sum = 0;
  y = 0;
  for (int i = 0; i < row; i++) {
    x = sum;
    if (i != row-1) {
      float wi = noise(t+i);
      w[i] = map(wi, -1, 1, 10, width/3);
    } else {
      w[i] = width-sum;
    }
    rect(x, y, w[i], h);
    sum += w[i];
  }

  t += incr;
}

The unfortunate thing is that it’s quite obvious that the last cell is simply a remainder of all the other elements in the grid, whereas fxpx’s example looks and feels a lot more organic from both axes. I’m interested to learn how to approach setting up a grid, or any data structure for that matter, in the way that he has implemented beautifully, where the noise seems to ‘loop’ perfectly from one end to the other.

Any help would be much appreciated! Any other advice on my code structure is welcome too.
Thanks in advance!

Hi Namrad,

not have that much time currently but here is a way you can do. In the example you added by insta link not only the width is affected but also the height of the cells, but as you seems only to want to concentrate on the width I’ve kept my example also simple to demostrate a way you can build on …
If you have Q’s about I’ll try to answer on next free timeslot. :grin:

Hope that helps…

Cheers
— mnse

// class representing a cell
class Cell {
  PVector p;
  PVector s;
  float v;

  public Cell() {
    p = new PVector();
    s = new PVector();
    v = 0;
  }

  void updateValue(float pv) {
    v = pv;
  }

  void updateBoxes(Cell l, Cell t, float sx) {
    s.x=v*sx;
    s.y=scl;
    p.x = l != null ? l.p.x+l.s.x : 0;
    p.y = t != null ? t.p.y+t.s.y : 0;
  }

  public void render() {
    stroke(0);
    fill(map(v, 0, 1, 0, 255));
    rect(p.x, p.y, s.x, s.y);
  }
}

// main scetch

float scl = 15.;
int rows;
int cols;
Cell[][] grid;

float zVal   = 0;
float zShift = 0.03;

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

  rows = floor(height/scl);
  cols = floor(width/scl);
  grid= new Cell[rows][cols];

  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      grid[y][x] = new Cell();
    }
  }
}

void draw() {
  background(0);

  // update values
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      grid[y][x].updateValue(noise(x*0.05, y*0.05, zVal));
    }
  }
  zVal+=zShift;

  // determine ScalingFactor for each row
  float[] xfact = new float[cols];
  for (int y = 0; y < rows; y++) {
    float vmaxc = 0;
    for (int x = 0; x < cols; x++) {
      vmaxc += grid[y][x].v;
    }
    xfact[y] = width/vmaxc;
  }

  // update boxes and render
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      Cell l = x>0 ? grid[y][x-1] : null;
      Cell t = y>0 ? grid[y-1][x] : null;
      grid[y][x].updateBoxes(l, t, xfact[y]);
      grid[y][x].render();
    }
  }
}

Hi again,

found a few minutes to go on and re-build the example from the insta link with also the heights included.

// class representing a cell
class Cell {
  PVector p;
  PVector s;
  float v;

  public Cell() {
    p = new PVector();
    s = new PVector();
    v = 0;
  }

  void updateValue(float pv) {
    v = pv;
  }

  void updateBoxes(Cell l, Cell t, float sx, float syh) {
    s.x=v*sx;
    s.y=syh;
    p.x = l != null ? l.p.x+l.s.x : 0;
    p.y = t != null ? t.p.y+t.s.y : 0;
  }

  public void render() {
    stroke(0);
    fill(map(v, 0, 1, 0, 255));
    rect(p.x, p.y, s.x, s.y);
  }
}

// main sketch
float scl = 15.;
int rows;
int cols;
Cell[][] grid;

float zVal   = 0;
float zShift = 0.03;

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

  rows = floor(height/scl);
  cols = floor(width/scl);
  grid= new Cell[rows][cols];

  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      grid[y][x] = new Cell();
    }
  }
}

void draw() {
  background(0);

  // update values
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      grid[y][x].updateValue(noise(x*0.05, y*0.05, zVal));
    }
  }
  zVal+=zShift;

  // determine ScalingFactor for each row height and col width
  float[] xfact = new float[rows];
  float[] yfacth = new float[rows];
  float yfact = 0;
  float vmax = 0;
  for (int y = 0; y < rows; y++) {
    vmax = 0;
    float vmaxh = 0;
    for (int x = 0; x < cols; x++) {
      vmax += grid[y][x].v;
      if (vmaxh < grid[y][x].v) {
        vmaxh = grid[y][x].v;
      }
    }
    xfact[y] = width/vmax;
    yfacth[y] = vmaxh;
  }
  vmax=0;
  for (int y = 0; y < rows; y++) {
    vmax += yfacth[y];
  }
  yfact = height/vmax;

  // update boxes and render
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      Cell l = x>0 ? grid[y][x-1] : null;
      Cell t = y>0 ? grid[y-1][x] : null;
      grid[y][x].updateBoxes(l, t, xfact[y], yfacth[y] * yfact);
      grid[y][x].render();
    }
  }
}

Have fun!
— mnse

PS: short vid as demo
output