rolerman-Intersections
Interactive app:
Animated GIF:
Code:
const numLines = 12 const lineLength = 350 const w = 720 const h = 480 let lines = [] let intersections = [] // ----- line generation functions ------ const generateLine = () => { let angle = Math.random() * Math.PI let x0 = Math.random() * (w - lineLength * Math.cos(angle)) let y0 = Math.random() * (h - lineLength * Math.sin(angle)) return { x0, y0, x1: x0 + Math.cos(angle) * lineLength, y1: y0 + Math.sin(angle) * lineLength, } } const regenerateLines = () => { lines = [] for (let i = 0; i < numLines; i++) { lines.push(generateLine()) } } // ----- intersection calculation functions ------ const getSlope = (L) => (L.y1 - L.y0) / (L.x1 - L.x0) const getYInt = (L, slope) => L.y0 - slope * L.x0 const ptInLineBounds = (pt, L) => { let minX = Math.min(L.x0, L.x1) let minY = Math.min(L.y0, L.y1) let maxX = Math.max(L.x0, L.x1) let maxY = Math.max(L.y0, L.y1) return (pt.x > minX && pt.x < maxX && pt.y > minY && pt.y < maxY) } const calculateIntersection = (line0, line1) => { // get lines in y = mx + b form const m0 = getSlope(line0) const b0 = getYInt(line0, m0) const m1 = getSlope(line1) const b1 = getYInt(line1, m1) // get x intersect value: m0 * x + b0 = m1 * x + b1 const x = (b1 - b0) / (m0 - m1) const y = m0 * x + b0 const pt = {x, y} // make sure it actually falls on both lines if (ptInLineBounds(pt, line0) && ptInLineBounds(pt, line1)) { return(pt) } return null } const calculateAllIntersections = () => { intersections = [] for (let i = 0; i < numLines; i++) { for (let j = 0; j < numLines; j++) { if (lines[i] !== lines[j]) { intersection = calculateIntersection(lines[i], lines[j]) if (intersection) intersections.push(intersection) } } } } // ----- window functions ------ // for pulsing rainbow colors const colors = ["#E50013", "#E33100", "#E17600", "#DFBA00", "#BDDD00", "#78DB00", "#34D900", "#00D70D", "#00D54F", "#00D38F", "#00D1CE", "#0092CF", "#0051CD", "#0012CB", "#2B00C9", "#6800C7", "#A300C5", "#C300A7", "#C1006A", "#BF002E"] let currentColorIndex = 0 const updateColor = () => { fill(colors[currentColorIndex]) currentColorIndex++ if (currentColorIndex >= colors.length) { currentColorIndex = 0 } } // for pulsing dots const maxDotSize = 14 const minDotSize = 10 let dotSize = 12 let shrink = false const updateDotSize = () => { if (shrink) dotSize = dotSize - 1 else dotSize++ if (dotSize < minDotSize) shrink = false if (dotSize > maxDotSize) shrink = true } function mouseClicked() { regenerateLines() calculateAllIntersections() } function setup() { createCanvas(w, h) regenerateLines() calculateAllIntersections() strokeWeight(3) window.setInterval(() => { updateColor(); updateDotSize(); }, 50) } // ----- draw functions ------ const drawLine = (L) => { stroke(255) line(L.x0, L.y0, L.x1, L.y1) } const drawIntersection = (I) => { noStroke() ellipse(I.x, I.y, dotSize) } const drawAllLines = () => { lines.forEach(drawLine) } const drawAllIntersections = () => { intersections.forEach(drawIntersection) } function draw() { background(0) drawAllLines() drawAllIntersections() } |
Here’s mine with 100 lines: