weirdie-Interruptions

Observations

  1. The artwork is square
  2. The artwork consists of many short black lines on a white backgrounds
  3. All of the lines have the same length
  4. The lines do not go off of the page
  5. There is a white border around the artwork
  6. There are random, small sections which do not have any lines
  7. The lines have an average direction, whether that be vertical or horizontal
  8. Very few lines do not touch another line
  9. There are sections of repeating patterns of lines
  10. The lines have roughly the same amount of space between them
  11. The lines which touch do so barely - they either just hit the edge of another line or cross over only slightly
  12. The lines appear to be in columns
  13. Lines intersect at most 3 other lines, most likely 2, and sometimes no other lines.

I started by placing the lines into a grid, but faced the problem of many overlapping "X's", so I wrote a function that found and removed them. This created the problem of too much space between lines, and it took bringing the image into Photoshop and plotting points to realize it was the midpoints that were on the grid, and not either endpoint.

This realization made the lines "fit together" properly, which is what I was finding most difficult to replicate. The noise function was used to generate values based on each line's coordinates, deleting those which were over a certain threshold to make gaps.

I now appreciate that generative art is not nearly as random as it initially appears, and that there are several layers of rules and calculations behind it. After many versions, I believe my replication is close, though hers may have nicer, more balanced empty sections.

sapeck-Intersections

/* Sapeck    9/6/2017
"sapeck-Intersections"
60-212                        Carnegie Mellon University
Copyright (C) 2018-present  Sapeck
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation.
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.
*/
 
var NUM_LINES = 12
 
function setup() {
  createCanvas(720, 480)
  boolDoRefresh = true
}
 
function draw() {
  if (boolDoRefresh) {
    background(255);
 
		let lines = []
		let intersects = []
		for (let i=0;i<NUM_LINES;i++) {
			let thisLine = {
				x1: floor(random(0, width)),
				y1: floor(random(0, height)),
				y2: floor(random(0, height))
			}
			thisLine.x2 = floor(random(thisLine.x1+1, width))
			thisLine.m = (thisLine.y2 - thisLine.y1) / (thisLine.x2 - thisLine.x1)
			lines.push(thisLine)
		}
		for (let i=0;i<lines.length;i++) {
			for (let j=i+1;j<lines.length;j++) {
				if (i !== j) {
					let thisLine = lines[i]
					let testLine = lines[j]
 
					// My brute-force-test-x method that didn't entirely work
					// for (let thisX=thisLine.x1;thisX<=thisLine.x2;thisX+=0.1) {
					// 	let thisY = floor((thisLine.m * (thisX-thisLine.x1)) + thisLine.y1)
					// 	let testY = floor((testLine.m * (thisX-testLine.x1)) + testLine.y1)
					// 	if (thisY==testY) intersects.push({x: thisX, y: thisY})
					// }
 
					// Paul Bourke's method (see function defintion below for full citation)
					let x1 = thisLine.x1, x2 = thisLine.x2, x3 = testLine.x1, x4 = testLine.x2
					let y1 = thisLine.y1, y2 = thisLine.y2, y3 = testLine.y1, y4 = testLine.y2
					let intersection = intersect(x1, y1, x2, y2, x3, y3, x4, y4)
					if (intersection !== false) intersects.push({x: intersection.x, y: intersection.y})
				}
			}
		}
		for (let i=0;i<lines.length;i++) {
			let thisLine = lines[i]
			stroke(color(0,0,255))
			line(thisLine.x1, thisLine.y1, thisLine.x2, thisLine.y2)
		}
		for (let i=0;i<intersects.length;i++) {
			let intersection = intersects[i]
			noStroke();
			fill(color(255,0,0,50))
			ellipse(intersection.x,intersection.y,20,20)
		}
 
    boolDoRefresh = false
  }
}
 
function mousePressed() {
  boolDoRefresh = true
}
 
// line intercept math by Paul Bourke http://paulbourke.net/geometry/pointlineplane/
// Determine the intersection point of two line segments
// Return FALSE if the lines don't intersect
function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
 
  // Check if none of the lines are of length 0
	if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
		return false
	}
 
	denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
 
  // Lines are parallel
	if (denominator === 0) {
		return false
	}
 
	let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
	let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator
 
  // is the intersection along the segments
	if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
		return false
	}
 
  // Return a object with the x and y coordinates of the intersection
	let x = x1 + ua * (x2 - x1)
	let y = y1 + ua * (y2 - y1)
 
	return {x, y}
}

sapeck-IterationExercise

/* Sapeck    9/6/2017
"sapeck-IterationExercise"
60-212                        Carnegie Mellon University
Copyright (C) 2018-present  Sapeck
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation.
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.
*/
 
// Based on starter Code for "Embedded Iteration + Randomness"
var boolDoRefresh;
 
function setup() {
  createCanvas(400, 400)
  boolDoRefresh = true
}
 
function draw() {
  if (boolDoRefresh) {
    background(255);
 
		var rows = width/50
		var cols = width/50
 
		for (var i=0;i<rows;i++) {
			for (var j=0;j<cols;j++) {
				if (random(50) < 5) {
					fill(color(255,0,0))
					ellipse((i*50) + (45/2) + 2.5, (j*50) + (45/2) + 2.5, 45, 45)
				} else {
					fill(color(0,255,0))
					rect(i*50 + 2.5, j*50 + 2.5, 45, 45)
				}
			}
		}
 
    boolDoRefresh = false
  }
}
 
function mousePressed() {
  boolDoRefresh = true
}

The Critical Engineering Manifesto Response – dinkolas

The third point in "The Critical Engineering Manifesto" by Julian Oliver et al. (2011) particularly stood out to me:

"The Critical Engineer deconstructs and incites suspicion of rich user experiences."

A few years ago I learned that in every large social media platform the users, not the site, are the product. The consumers who pay for the users' attention are advertisers. Thus, a "rich user experience" can sometimes just be a means of attracting the most user attention, or gathering the most product to sell. This could be viewed as a win-win: the user gets to choose the best site, and the best site is rewarded with advertising money. However, when the site is designed for addiction (which is the case with most social media platforms), this interaction is soured, and the site which manages to squeeze the most time out of the most people comes out on top. That is why I find this principal of the manifesto to be particularly important; the best solution to avoid having your time exploited is to be suspicious when you are repeatedly attracted to a single user experience, and to become conscious of ulterior motives the designers of such a system may have.

yuvian-Reading

The Critical Engineer recognises that each work of engineering engineers its user, proportional to that user's dependency upon it.

A critical engineer's work is understood to have an effect on its user corresponding to degree in which the user relies on it. Thus, the more a user depends on the work, the more they will be influenced by its content.

This is an interesting thought regarding the relationship between a product and its user/audience. I can see this belief reflected in popular culture regarding the prevalence of smartphones in our current society. It is often joked that as our phones become "smarter" we become less so. Nowadays, it is easy to see the influence technology has on our lives. Recently, research has shown the detrimental effects of blue light on our Circadian clock, our postures suffer due to long hours in front of a computer screen, and average time spent outdoors is quickly decreasing. In the same way our technology is continuously engineered and altered throughout the years, so have our lifestyles. Because of this, the fifth tenet of the "Critical Engineering Manifesto" rings true.

nannon-IterationExercise

var boolDoRefresh;
 
function setup() {
  createCanvas(400, 400);
	background(240,240,255);
  boolDoRefresh = true;
}
 
function rando(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min)) + min; 
}
 
console.log(rando(0,100))
 
 
 
function draw() {
  if (boolDoRefresh) {
    //margins = 16px
		//box size= 32
		//spacer=16
		setup()
		var margin =16
		var spacer=16
		var boxsize=32
		for (i=0; i<8; i++) {
			for (j=0;j<8;j++) {
				var randomint=rando(0,100)
				var randopercent = rando(5,12)
				var x=margin+j*(spacer+boxsize)
				var y=margin+i*(spacer+boxsize)
				if (randomint<randopercent) {
					ellipse(x+16, y+16, 28,28)
				}
 
				else {
					rect(x, y, boxsize, boxsize)
				}
			}
		}
 
    boolDoRefresh = false;
  }
}
 
function mousePressed() {
  boolDoRefresh = true;
}

nannon-Intersections

 
var boolDoRefresh;
var linelist=[]
var numSlider
 
function setup() {
  createCanvas(720,480);
  boolDoRefresh = true;
}
 
function rando(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive 
}
 
// function findintersection(line1, line2) {
//     return math.intersect(line1[0], line1[1], line2[0], line2[1])
// }
 
function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
  if ((x1 === x2 &amp;&amp; y1 === y2) || (x3 === x4 &amp;&amp; y3 === y4)) {
    return false
  }
  denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
  if (denominator === 0) {
    return false
  }
  let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
  let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator
  if (ua &lt; 0 || ua &gt; 1 || ub &lt; 0 || ub &gt; 1) {
    return false
  }
  let x = x1 + ua * (x2 - x1)
  let y = y1 + ua * (y2 - y1)
 
  return [x, y]
}
 
function draw() {
  if (boolDoRefresh) {
    var numLines= 15
    background("#FFE6E6");
    linelist=[]
    for (i=0;i&lt;numLines;i++){ var startx= rando(0, width) var starty= rando(0, height) var endx = rando(0, width) var endy = rando(0, height) stroke("#FF0000"); strokeWeight(2); line(startx, starty, endx,endy) linelist.push([[startx,starty],[endx,endy]]) if (linelist.length &gt;1) { 
          for (j=0;j&lt;i; j++) {
            var inter = intersect(linelist[i][0][0], linelist[i][0][1], linelist[i][1][0], linelist[i][1][1], linelist[j][0][0], linelist[j][0][1], linelist[j][1][0], linelist[j][1][1],)
            if (inter) {
              strokeWeight(2)
              fill('rgba(255,0,0, 0.25)')
              ellipse(inter[0], inter[1], 20,20)
            }
          }
      }
    }
    boolDoRefresh = false;
  }
}
 
function mousePressed() {
  boolDoRefresh = true;
}
 
//random function from: 
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
 
//intersect function from:
//http://paulbourke.net/geometry/pointlineplane/javascript.txt

yuvian-Intersections

intersections

twelve intersections

seventy intersections


var lines = [];
var numOfLines = 12;
var intersectXArray =[];
var intersectYArray = [];

var yAxis = 1;
var c1, c2, c3;

function setup() {
	createCanvas(720, 480);
	
	background(0);

  c1 = color(0);
  c2 = color(16, 45, 117);
	c3 = color(244, 89, 66);
	
	// gradient background 1
	setGradient(0, 0, windowWidth, windowHeight / 2, c1, c2, yAxis);
	
	// gradient background 2
	setGradient(0, windowHeight/2, windowWidth, windowHeight, c2, c3, yAxis);
	
  for (var i = 0; i < numOfLines; i++) {
    lines.push(new Line());
  }

}

function draw() {
  for (var i = 0; i < lines.length; i++) {
    lines[i].display();
  }
  
  for (var i = 0; i < lines.length; i++) {
    for (var j = 0; j < lines.length; j++) {
      intersectXArray.push(intersect(lines[i].x1, lines[i].y1, lines[i].x2, lines[i].y2, lines[j].x1, lines[j].y1, lines[j].x2, lines[j].y2).x);
      intersectYArray.push(intersect(lines[i].x1, lines[i].y1, lines[i].x2, lines[i].y2, lines[j].x1, lines[j].y1, lines[j].x2, lines[j].y2).y);
    } 
  }  
	  
	// display twinkling stars as intersection points
  for (var i = 0; i < intersectXArray.length; i++) {
		star = new Star(intersectXArray[i], intersectYArray[i]);
		star.display();
		star.twinkle();
  }
}

function mousePressed() {
  lines = [];
  intersectXArray = [];
  intersectYArray = [];
  setup();
}

function Line() {
  this.x1 = random(0, width);
  this.y1 = random(0, height);
  this.x2 = random(0, width);
  this.y2 = random(0, height);

  this.display = function() {
    stroke(249, 252, 232, 20);
    strokeWeight(1);
    line(this.x1, this.y1, this.x2, this.y2);
  }
}

function Star(x,y) {
	this.x = x;
	this.y = y
	this.r = random(8);
	
	this.display = function() {
		stroke(22, 71, 119);
		fill(255);
		this.rc = constrain(this.r, 0, 9);
    ellipse(this.x, this.y, this.rc, this.rc);
  };

	this.twinkle = function() {
		if (this.r < 3) {
			this.r += random(-.5,1.5);
		} else if (this.r >= 3 && this.r < 6) {
			this.r += random(-1,1);
		} else if (this.r >=6 && this.r <=9) {
			this.r += random(-1.5,0.5);
		}
		
	}
}

// creates gradients
function setGradient(x, y, w, h, c1, c2, axis) {
	noFill();
	if (axis == yAxis) {  // Top to bottom gradient
   	for (var i = y; i <= y+h; i++) {
    	var inter = map(i, y, y+h, 0, 1);
    	var c = lerpColor(c1, c2, inter);
    	stroke(c);
    	line(x, i, x+w, i);
   	}
 	} 
}

//from Paul Bourke http://paulbourke.net/geometry/pointlineplane/javascript.txt
function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {

  // Check if none of the lines are of length 0
  if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
    return false
  }

  denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))

  // Lines are parallel
  if (denominator === 0) {
    return false;
  }

  let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
  let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;

  // is the intersection along the segments
  if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
    return false
  }

  // Return a object with the x and y coordinates of the intersection
  let x = x1 + ua * (x2 - x1)
  let y = y1 + ua * (y2 - y1)

  return {x, y}
}

harsh-Interruptions

Observations:

  1. The lines have seemingly random angles with the square of the paper
  2. While the pattern seems random, the lines are evenly distributed on the paper
  3. Some lines intersect others
  4. There are some irregularly large white-spaces in the artwork where lines have been removed
  5. There is a white border around the edge of the artwork
  6. The lines tend to break into this border, preventing it from being a square
  7. The border's on the top, left and right are larger than the ones at the bottom
  8. There exists a signature at the bottom right corner
  9. Generally, most lines tend to bias verticality
  10. The lines seem to be part of a general grid system

I thought of this as a grid distortion process - where most lines in a column system get rotated by some kind of distribution. After the distortion, there is a sequential "culling" of lines, which is not random but happens in chunks or groups, so it can be thought of as culling blocks of grids instead of individual lines.

Initially, I used the P5.JS random function to generate the values that would rotate each line segment, but I quickly realized that Molnar's piece had some kind of specific mathematical distribution. After messing around with Perlin Noise, I used Gaussian Distribution to generate the rotation (seeing as most lines tend t0 be more vertical). I think the calibration of the distribution still needs some work - and so does the calibration of the culling of the "patches" in the grid.

This was quite an interesting process, learning to re-create a visual effect through code - the process involved a lot of educated guessing, which while tough, was an interesting experience because of its iterative nature.

breep-Interruptions

Observations:

  1. The background is white, all the lines are black
  2. Lines are arranged in a square lattice
  3. The lines are rotated around their centre point on the lattice
  4. The lattice is 56 x 56
  5. Some lines are missing
  6. If a line is missing, the probability that one of its neighbours is missing is high (Missing in groups)
  7. There are many more lines present than missing
  8. The length of each line is twice the distance between the centre points of each line on the lattice
  9. All the lines are the same length
  10. There is a margin around the piece
  11. The angles of rotation of the lines are within a rough normal distribution (the vast majority have only a small amount of rotation, and the more extreme the rotation the less of them there are)

I started out my figuring out how to formulate the lattice, starting with circles with their centre at the lattice points. This was done with a nested for loop. Once this was created, I set about replacing every circle with a vertical line with the appropriate pixel measurements/separations. At this point I had 56 vertical long lines. I then set about figuring out how to randomly rotate each of the lines. I initially just did this purely randomly, using random(). However, displeased by this I looked at possibilities for getting the rotations more normally distributed, and found randomGaussian(). Using this I was able to more normally distribute the angles. This was definitely a saving grace, and I massive appreciated it's existence, and it also alerted me to the extent of built in functions within p5.js.

I then set about working on the spaces, and felt that I would need two cases of probability of a space. My first probability was the base overall probability of their being a blank space, which I set to be relatively low. I then set about creating an array to store whether a line was there or not, with 0 representing the presence of a line and 1 being a blank space. Then with this, as the lines were created I checked whether a line's neighbour was blank (its left, above and left top angled neighbours). If this was the case the probability that it would be blank became higher. I then tinkered with both probabilities until I got a result that I felt resembled the original Interruptions.  Getting this element of the neighbours working was the most difficult element of the app for me, with the formatting of the neighbour checking proving challenging.