# An animation Media art of the generative design of rectangles

## The original idea of this media art.

When I played with ntsutae (@ntsutae) san's work 'Symmetry 2'.

👉 この記事は日本語でも読めます。

I found it creates interesting shapes if I tuned the size of rectangles.

And I tried to make it interesting media art, I used 'blendMode(DIFFERENCE)' and tuned the edge size of the rectangle.

## Making my own work.

The original ntsutae san's work used logical operation to determine the shape. But it does not necessarily need the logical operation to make a shape randomly. So I changed the formula of shape calculation to the formula I can easily understand.

float theta = HALF_PI * floor(8 * sin(shapeBase + shapeDiv * i));

I proceeded to tune the size and the width of the edge of rectangles and made the whole shape locate to the center of the canvas.

## Make it move with simple morphing technique.

I called it 'Simple morphing technique', but it is just a linear interpolation.

I used to calculate the interpolation by myself like 'Johnny on the Monorail'.

float xF = _to.get(f).x * _rate + _from.get(f).x * (1.0 - _rate);

And I found the 'lerp()' function at last! Ahh! what a divine blessing!

float x = lerp(shapeFrom.get(i).x, shapeTo.get(i).x, easeRatio);

Finally, I made this media art as a loop animation.

During the way, I made some failed creative work. It's a 'strokeWeight(random())'.

## The example code of the 'Processing'.

Please feel free to use this example code under the terms of the GPL. To see other works based on my code is my pleasure. And my honor.

This code does not display any images on the screen but generates image files in frames directory. You can make an animation with these files.

``````
/**
* It's a media art that displays the morphing generative design of rectangles.
* original idea : https://openprocessing.org/sketch/1125777
*
* @author @deconbatch
* @version 0.1
* Processing 3.5.3
* 2021.05.23
*/

void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
rectMode(CENTER);
smooth();
}

void draw() {

int   frmRate  = 30;
int   frmMorph = frmRate * 1;       // morphing duration frames
int   cycles   = 8;                 // animation cycle no
int   frmMax   = frmMorph * cycles; // whole frames
float rSize    = 25.0;

// generate shapes
ArrayList<ArrayList<PVector>> shapes = new ArrayList<ArrayList<PVector>>();
float weights[] = new float[cycles];
for (int i = 0; i < cycles; i++) {
weights[i] = rSize * floor(random(6));
}

// variables for animation
ArrayList<PVector> shapeFrom = new ArrayList<PVector>();
ArrayList<PVector> shapeTo   = new ArrayList<PVector>();
float weightFrom = 0.0;
float weightTo   = 0.0;
int   cycleCnt   = 0;

for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
float frmRatio  = map(frmCnt, 0, frmMax, 0.0, 1.0);
float easeRatio = InFourthPow(map(frmCnt % frmMorph, 0, frmMorph - 1, 0.0, 1.0));

// shape for morphing animation. loops cyclic.
if (frmCnt % frmMorph == 0) {
cycleCnt   = frmCnt / frmMorph;
shapeFrom  = shapes.get(cycleCnt);
shapeTo    = shapes.get((cycleCnt + 1) % cycles);
weightFrom = weights[cycleCnt];
weightTo   = weights[(cycleCnt + 1) % cycles];
}

// draw
blendMode(BLEND);
background(0.0, 0.0, 100.0, 100.0);

blendMode(DIFFERENCE);
fill(0.0, 0.0, 100.0, 100.0);
stroke(0.0, 0.0, 100.0, 100.0);
strokeWeight(lerp(weightFrom, weightTo, easeRatio));
for (int i = 0; i < shapeFrom.size(); i++) {
float x = lerp(shapeFrom.get(i).x, shapeTo.get(i).x, easeRatio);
float y = lerp(shapeFrom.get(i).y, shapeTo.get(i).y, easeRatio);
rect(x, y, rSize, rSize);
}

blendMode(BLEND);
casing();

// for stop motion
if (frmCnt % frmMorph == 0) {
for (int i = 0; i < frmRate; i++) {
saveFrame("frames/" + String.format("%04d", cycleCnt) + ".00." + String.format("%04d", i) + ".png");
}
}

// for moving motion
saveFrame("frames/" + String.format("%04d", cycleCnt) + ".01." + String.format("%04d", frmCnt) + ".png");
}

exit();
}

/**
* getShape : generates the shape
*/
ArrayList<PVector> getShape(float _size) {

int   pvNum     = 15;
float shapeBase = random(TWO_PI);
float shapeDiv  = random(HALF_PI);

float x = 0.0;
float y = 0.0;
ArrayList<PVector> pvs = new ArrayList<PVector>();
for (int i = 0; i < pvNum; i++) {
float theta = HALF_PI * floor(8 * sin(shapeBase + shapeDiv * i));
x += _size * cos(theta);
y += _size * sin(theta);
}

// centering the shape
float xMin = width;
float xMax = 0;
float yMin = height;
float yMax = 0;
for (PVector pv : pvs) {
xMin = min(xMin, pv.x);
xMax = max(xMax, pv.x);
yMin = min(yMin, pv.y);
yMax = max(yMax, pv.y);
}
float xDiv = (width - xMin - xMax) * 0.5;
float yDiv = (height - yMin - yMax) * 0.5;
for (PVector pv : pvs) {
}

return pvs;
}

/**
* InFourthPow : easing function.
*/
private float InFourthPow(float _t) {
return 1.0 - pow(1.0 - _t, 4);
}

/**
* casing : draws fancy casing
*/
void casing() {
float w = min(width, height) * 0.05;
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(w + 4.0);
stroke(0.0, 0.0, 0.0, 100.0);
rect(width * 0.5, height * 0.5, width, height);
strokeWeight(w);
stroke(0.0, 0.0, 100.0, 100.0);
rect(width * 0.5, height * 0.5, width, height);
}

/*

This program is free software: you can redistribute it and/or modify
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/
```
```
No Comment