Generates a random field of lines, each of which grows in a straight line until it encounters any other line, at which point it stops.
Phase one of a generative art project inspired by Jared Tarbell's Substrate project.
license: mit | |
scrolling: no | |
border: no |
Generates a random field of lines, each of which grows in a straight line until it encounters any other line, at which point it stops.
Phase one of a generative art project inspired by Jared Tarbell's Substrate project.
<!doctype html> | |
<html lang=""> | |
<head> | |
<meta charset="utf-8"> | |
<title>Intersections</title> | |
<meta name="description" content=""> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<script src="https://unpkg.com/d3/build/d3.min.js"></script> | |
<style> | |
body{ background: #ffffff } | |
/*canvas{ background: #212121 }*/ | |
canvas{ background: #ffffff } | |
</style> | |
</head> | |
<body> | |
<canvas></canvas> | |
<script type='text/javascript'> | |
let width = 500, | |
height = 300, | |
DPR = window.devicePixelRatio || 1, | |
scaledWidth = width * DPR, | |
scaledHeight = height * DPR, | |
canvas = d3.select("canvas") | |
.attr('width', scaledWidth) | |
.attr('height', scaledHeight) | |
.style('width', `${width}px`) | |
.style('height', `${height}px`), | |
ctx = canvas.node().getContext('2d'), | |
timesUp = 10000, | |
tickLength = 0.04, | |
lines = [], | |
intersects = []; | |
ctx.scale(DPR, DPR); | |
ctx.strokeStyle = '#000000'; | |
ctx.lineWidth = 0.5; | |
const sameSign = (a, b) => (a * b) > 0; | |
function intersect(a,b,c,d,p,q,r,s) { | |
let det, gamma, lambda; | |
det = (c - a) * (s - q) - (r - p) * (d - b); | |
if (det === 0) { | |
return false; | |
} else { | |
lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det; | |
gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det; | |
return (0 < lambda && lambda < 1) && (0 < gamma && gamma < 1); | |
} | |
} | |
function addLine(id){ | |
let line = { | |
id: id, | |
intersects: [], | |
start: [Math.random()*width, Math.random()*height], | |
end: [0, 0], | |
// slope: d3.format('.2f')(Math.random()) * Math.PI * 2 | |
// slope: [0,Math.PI/2,Math.PI,Math.PI*3/2][Math.floor((Math.random()*4))] | |
slope: [0,Math.PI*0.333,Math.PI*0.666,Math.PI,Math.PI*1.333, Math.PI*1.666][Math.floor((Math.random()*6))] | |
}; | |
lines.push(line); | |
} | |
d3.range(0,180).map((i) => addLine(i)); | |
function draw(t){ | |
let nLines = lines.length; | |
let linesLeft = lines.filter(f => f.intersects.length == 0); | |
linesLeft.forEach(l => { | |
let to = l.end = [l.start[0]+Math.cos(l.slope)*t*tickLength, | |
l.start[1]+Math.sin(l.slope)*t*tickLength]; | |
for(let index=0; index < lines.length; index++){ | |
let d = lines[index]; | |
if(intersect(...d.start, ...d.end, ...l.start, ...l.end) == 1 && intersects.indexOf([l.id,d.id].sort((a,b) => a-b).join('_')) < 0){ | |
l.intersects.push(1); | |
intersects.push([l.id,d.id].sort((a,b) => a-b).join('_')); | |
break; | |
} | |
} | |
if(to[0] >= 0 && to[0] <= width && to[1] >= 0 && to[1] <= height && l.intersects.length == 0){ | |
/* ctx.fillRect(l.start[0]-2, l.start[1]-2, 4, 4) ;*/ | |
ctx.moveTo(...l.start); | |
ctx.lineTo(...to); | |
ctx.stroke(); | |
}else{ | |
/* console.log(`Line ${l.id} hit edge, ${lines.length} left`); */ | |
nLines -= 1; | |
} | |
}) | |
if(nLines == 0){ | |
console.log('CEASE') | |
timer.stop(); | |
} | |
} | |
let timer = d3.interval(function(elapsed) { | |
draw(elapsed); | |
/* if (elapsed > timesUp) timer.stop(); */ | |
}, 25); | |
</script> | |
</body> | |
</html> |