Hypnotic Squares – A Reinvention of “Random Squares” by Bill Kolomyjec

For this week’s project, I decided to reproduce the following graphics titled “Random Squares” by Bill Kolomyjec. The graphics appeared in the 1977 edition of Computer Graphics and Art and depicts a canvas with random squares with different depths that gives the impressions of hollow pyramids. Each square has a random number of squares insides it which is decided by the program.

I attempted to reproduce the canvas and here is the result. Every time the program runs, it produces a different pattern due to the randomness of the number of squares inside each square. The minimum number of square inside a square is 0 and the maximum is 20.

Version 1 – Reproduced by Arame Dieng – March 25, 2017
Version 2 – Reproduced by Arame Dieng – March 25, 2017

Method

The pattern was reproduced by building the first square and translating the square in different locations of the canvas using a for loop.

To build the first square, I created a function called drawTarget() with argument such as the starting location of the square, its size and the number of squares inside it. Using a mathematical formula, I drew the square such that it produces and angled-effect on one side of the square (if you look at the canvas carefully, inner squares seems to be dense on the upper left side of the squares).

The translation was done using another function called drawPattern() where I use a nested for-loop to translate the first square along and across the canvas with the number of inner squares randomly chosen.

void setup() {
 size(860, 620);
 background(0);
 noLoop();
 
}

void draw(){
 drawTarget(10,10,120,20); //calling function to draw first shape
 drawPattern(20); //calling function to translate shape across canvas
}


//defining function to draw shape with inner squares
void drawTarget(float xloc, float yloc, float size, float num){
 float steps = size/num;//space between each inner square
 float corner= steps/3; //creating a denser pattern on the top left        corner of each square
 rectMode(CORNER);
 for (int i=0; i<num; i++){
     rect(xloc+i*corner,yloc+i*corner,size-i*steps, size-i*steps);
 }
}

//defining function to repeat pattern across window
void drawPattern(int rand){
 float start_x=120;
 float start_y=120;
 for (int i=0; i<7; i++){
    for (int j=0; j<5; j++){
       pushMatrix();
       translate(start_x*i, start_y*j);
       drawTarget(10,10,120,random(rand)); //draw shape while randomly assigning the number of squares each shape has
       popMatrix();
     }
 }
}

To spice things up a little, I decided to go further with my representation by animating the squares and adding some color.

Pattern 1

This pattern animates the inside squares continuously thus creating an additional subliminal  layer that mimics checkered squares. This is obtained by eliminating the noLoop() function in the code above.

Pattern 2

This pattern animates both the outer and inside squares, rotating each shape and making them jitter every 2 seconds. The squares are also colored with an ombre effect from left to right.

Pattern 3

Pattern 3 is a variation of Pattern 2 with the color variation happening inside each shape rather than across shapes.

Without the jitter.

You can create different effects with the square and choose to make them rotate or not. I really had fun doing this project and creating new patterns based on the original image published in the journal. I also learned to experiment with functions and use mathematical logic to draw patterns. The most challenging part was drawing the first shape with the inner squares and figuring out how to make the translation work. But in the end, it worked out and I discovered new things from having bugs in my code.

Code for pattern 2

float angle;
float jitter;

void setup() {
 size(840, 600);
 background(255);
 drawTarget(0,0,120,15);
 background(255);
}

void draw(){
 drawPattern(15);
}


void drawTarget(float xloc, float yloc, float size, float num){
 float steps = size/num;
 float corner= steps/3;
 rectMode(CORNER);
 for (int i=0; i<num; i++){
    rect(xloc+i*corner,yloc+i*corner,size-i*steps, size-i*steps);
 }
}

void drawPattern(int rand){
 if (second() % 2 == 0) {  //creates the jitter movement
   jitter = random(-0.2, 0.2);
 }
 angle = angle + jitter;
 float c = cos(angle);

 float start_x=120;
 float start_y=120;
 float grayvalues = 255/rand; //adding color ombre 
 for (int i=0; i<rand; i++){
   for (int j=0; j<rand; j++){
      pushMatrix();
      strokeWeight(1.5);
      fill(i*grayvalues); //fill shapes
      translate(start_x*i, start_y*j); //translate then rotate
      rotate(c);
      drawTarget(0,0,120,random(rand));
      popMatrix();
   }
 }
}

Code for Pattern 3

float angle;
float jitter;
void setup() {
 size(860, 620);
 drawTarget(0,0,120,15);
 //noLoop();
}

void draw(){
 
 drawPattern(15);
 
}


void drawTarget(float xloc, float yloc, float size, float num){
 float steps = size/num;
 float corner= steps/3;
 float grayvalues = 255/num;
 rectMode(CORNER);
 for (int i=0; i<num; i++){
    fill(i*grayvalues,0,0); //fill shape before translating 
    rect(xloc+i*corner,yloc+i*corner,size-i*steps, size-i*steps);
 }
}

void drawPattern(int rand){
 if (second() % 2 == 0) { 
    jitter = random(-0.2, 0.2);
 }
 angle = angle + jitter;
 float c = cos(angle);
 float start_x=120;
 float start_y=120;
 float grayvalues = 255/rand;
 for (int i=0; i<rand; i++){
   for (int j=0; j<rand; j++){
     pushMatrix();
     noStroke();
     translate(start_x*i, start_y*j);
     rotate(c);
     drawTarget(0,0,120,random(rand));
     popMatrix();
   }
 }
}