Last active
November 22, 2021 03:51
-
-
Save ericdlaspe/6d9a93e4ff814f22b25ddd459b70c668 to your computer and use it in GitHub Desktop.
Arc experiment gone wrong produced an interesting tumbleweed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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