Skip to content

Instantly share code, notes, and snippets.

@ericdlaspe
Last active November 22, 2021 03:51
Show Gist options
  • Save ericdlaspe/6d9a93e4ff814f22b25ddd459b70c668 to your computer and use it in GitHub Desktop.
Save ericdlaspe/6d9a93e4ff814f22b25ddd459b70c668 to your computer and use it in GitHub Desktop.
Arc experiment gone wrong produced an interesting tumbleweed
function twoPointArc(x1, y1, x2, y2, radius, weight, direction) {
p5.push()
// p5.angleMode(p5.RADIANS)
let x = x1
let y = y1
// ab is the midpoint between the two input points
const ab = p5.createVector((x1 + x2) / 2, (y1 + y2) / 2)
// circle(ab.x, ab.y, 9)
const b = p5.dist(x1, y1, x2, y2) / 2
const a = Math.sqrt(Math.abs(radius ** 2 - b ** 2))
const p1 = p5.createVector(x1, y1)
const p2 = p5.createVector(x2, y2)
let heading = p1.sub(p2).heading()
if (direction < 0) {
heading += p5.PI / 2
} else {
heading -= p5.PI / 2
}
// ac is the center of the arc
const ac = p5.createVector(ab.x + p5.cos(heading + p5.PI) * a,
ab.y + p5.sin(heading + p5.PI) * a)
const angle = p5.asin(b / radius)
// Arc length
const L = radius * angle
const brushWeight = weight / 2
// The i step scales based on the length of the line segment being drawn,
// keeping the line smooth without excess drawing
const step = weight / (L * 10)
console.log(step)
// const step = 0.1 / b / (weight * 3)
for (let i = 0; i < 1; i += step) {
// Theta is the angle of the current circle to draw
const theta = p5.map(i, 0, 1, angle, -angle)
x = ac.x + p5.cos(heading + theta) * radius
y = ac.y + p5.sin(heading + theta) * radius
p5.circle(x, y, brushWeight)
}
p5.pop()
}
p5.push()
// Position coordinates in the center of the canvas
p5.translate(WIDTH/2, HEIGHT/2)
let arcWeight = 5
let arcColor = 40
const nPoints = 22
const outerRadius = 200
const innerRadius = 20
// Don't pass p5 functions to fn. I don't know why, but they don't work.
function distribute(nPoints, start, end, fn, fnXMin, fnXMax) {
const outputs = Array(nPoints)
const fnYMin = fn(fnXMin)
const fnYMax = fn(fnXMax)
for (let i = 0; i < nPoints; i++) {
const x = p5.map(i, 0, nPoints, fnXMin, fnXMax, true)
const y = fn(x)
outputs[i] = p5.map(y, fnYMin, fnYMax, start, end)
}
return outputs
}
p5.background('black')
let rotationStep = p5.PI / 5
// let rotation = p5.PI / 7
let rotation = p5.random(1, rotationStep)
for (let j = 0; j < p5.TWO_PI; j += rotation) {
let sign = (p5.random() > 0.5) ? 1 : -1
const radii = distribute(nPoints, innerRadius, outerRadius, Math.sin, 0, Math.PI / 2)
radii.push(outerRadius)
radii.push(outerRadius)
let startPoint = p5.createVector(radii[0], 0)
let endPoint = p5.createVector(radii[1], 0)
p5.fill(arcColor)
p5.noStroke()
twoPointArc(startPoint.x, startPoint.y, endPoint.x, endPoint.y,
100000, arcWeight, 1)
console.assert(radii.length > 2, 'Not enough points for arc loop')
for (let i = 2; i < radii.length; i++) {
startPoint.x = endPoint.x
startPoint.y = endPoint.y
const theta = sign * p5.map(p5.random(), 0, 1, innerRadius, outerRadius, true)
const r = radii[i]
endPoint.x = r * Math.cos(theta)
endPoint.y = r * Math.sin(theta)
// Find the direction the arc should face
const direction = Math.sign(startPoint.y - endPoint.y)
// Draw the arc
twoPointArc(startPoint.x, startPoint.y, endPoint.x, endPoint.y,
outerRadius, arcWeight, direction)
sign = -sign
}
// Adjust params for next iteration
// rotation = p5.random(1, rotationStep)
rotation = p5.random(1, rotationStep)
p5.rotate(rotation)
}
p5.pop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment