# Optical illusion: are these lines parallel or not?

Hello, I joined recently the forum.

I’ve decided to share some of my sketches which, I believe, some may find interesting.

From time to time, I like wandering the Internet to look for ideas on maths and arts. I came across this optical illusion in a Tumblr blog and I decided to make a sketch out of it. This is a gif with the result; you can find the code below to run the animation endlessly.

main sketch
``````/*
Intent to reproduce the following optical illusion:
https://szimmetria-airtemmizs.tumblr.com/post/170377417893/illusion-the-horizontal-lines-between-the

The animation loops forever with a period set
via the variable 'duration_secs'.

The image can be divided into rows of squares,
some of which move, while other don't.

The visual part (render, colours, etc.) is managed
by the class 'Row'; on the other hand, the dynamic
of the mobile rows are carried out by the class 'DynSyst'.
*/
Row[] rows;
int q_rows;
int q_squares; // squares per row
float edge; // edge of the squares
float duration_secs; // duration of the animation, in secs
DynSyst sd;

void setup() {
size(640, 480);
//fullScreen();
frameRate(34);

//background(80);
rectMode(CENTER); // important
stroke(120);
strokeWeight(2);

duration_secs = 6; // 6 seconds
edge = 80;
q_rows = int(height / edge) + 1;
q_squares = int(width / edge) + 5;

float cx_ini = -2 * edge; // abscissa of all rows' position

sd = new DynSyst(cx_ini, 3.f * edge / 4, duration_secs);
rows = new Row[q_rows];
for (int i = 0; i < rows.length; i++) {
rows[i] = new Row(cx_ini, i * edge, edge, q_squares);
rows[i].is_mobile = i % 2 == 0 ? false : true;
rows[i].draw();
}
}

void draw() {
sd.iterate();
for (int i = 0; i < rows.length; i++) {
rows[i].update(sd.x);
rows[i].draw();
}
}
``````
class for the motion bits
``````/*
Class representing a (discrete) simple harmonic motion (SHM).
A simple harmonic motion is a sort of periodic motion,
which is described by a sinusoidal function.

This class will be using this one:
x(t) = A * sin(w * t + a)

Where:
-A is the amplitude of the motion.
-w is the angular velocity, calculated as w = 2 * PI / T.
-T is the motion's period, in seconds.
-a is the initial phase, which we'll take as 0.

By <em>discrete</em>, it is meant that the time variable
changes in a discrete manner, instead of continuously.
In each iteration the time variable's value is incremented
by a fixed value.

This fixed value is related to the sketch's frameRate
and guarantees that, if the dynamical system's 'iterate()'
method is called once per frame, the animation has period T.
*/
class DynSyst {
final float DELTA_T = 1.f / frameRate; // time increment per iteration
private float cx; // center or equilibrium point of the SHM
float x; // position at time t
float amplitude;
float period;
float ang_vel;
float t;

DynSyst(float cx, float amplitude, float period_secs) {
this.cx = x = cx;
this.amplitude = amplitude;
period = period_secs;
ang_vel = 2 * PI / period;
t = 0.f;
}

/*Increments dynamical system's time variable
and returns the position at this new time.*/
float iterate() {
t += DELTA_T;
if (t >= period) {
t = 0.f;
}
x = cx + amplitude * sin(ang_vel * t);

return x;
}
}
``````
class for the visual bits
``````/*
Class representing a row of squares with alternating colours.
The row's position is the center of its first (left-most) square.
*/
class Row {
private float cx_ini; // row's initial abscissa
float cx, cy; // row's current position
float edge;
int q_squares; // quantity of squares
color c1 = #ffffff, c2 = #000000; // colours to alternate between
boolean is_mobile;

/**/
Row(float cx, float cy, float edge, int q_squares) {
this.cx = cx_ini = cx;
this.cy = cy;
this.edge = edge <= 0.f ? 0.f : edge;
this.q_squares = q_squares <= 0 ? 0 : q_squares;
is_mobile = false;
}

void update(float cx) {
if (is_mobile) {
this.cx = cx;
}
}

/*Draws this row alternating the colour of the squares.
Assumes rectMode(CENTER) has been set.*/
void draw() {
color c;

c = c1;
for (int i = 0; i < q_squares; i++) {
draw_square(cx + i * edge, cy, edge, c);
c = c == c1 ? c2 : c1;
}
}

/*Draws a square given its center, edge and colour.
Assumes rectMode(CENTER) has been set.*/
private void draw_square(float cx, float cy, float edge, color c) {
fill(c);
rect(cx, cy, edge, edge);
}
}
``````

Feel free to make any comments, suggestions or even post back your tinkers.

8 Likes