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: