xxxxxxxxxx
283
const initialTargetScl = 1,
scaleThresh = 30;
let pi,
pie,
odds,
addsub,
scl = initialTargetScl,
targetScl = initialTargetScl,
scaleChanged = false,
paused,
iPerFrame = 1,
history,
historyDisplayCount,
historyDisplayCountChanged,
showHistoryI = false,
pieLineY,
lerpPieLineY,
showHelp = false,
showQV = true;
function iterate() {
pi += (addsub ? 1 : -1) / odds;
addsub = !addsub;
odds += 2;
pie = abs(pi * 4);
history.push({
value: pie,
dist: dist(0, pie, 0, PI),
});
}
function restart() {
pi = 0;
pie = 0;
odds = 1;
addsub = false;
scl = initialTargetScl;
targetScl = initialTargetScl;
history = [];
historyDisplayCount = 1;
historyDisplayCountChanged = false;
pieLineY = 0;
lerpPieLineY = 0;
}
function setup() {
createCanvas(window.innerWidth, window.innerHeight);
restart();
}
function draw() {
background(100, 100, 120);
if (!paused) {
for (let i = 0; i < iPerFrame; i++) {
iterate();
}
}
scl = lerp(scl, targetScl, 0.1);
if (!scaleChanged) {
targetScl = history.length * 0.2;
targetScl = targetScl < 1 ? 1 : targetScl;
}
if (!historyDisplayCountChanged && history.length <= 256) {
historyDisplayCount = history.length;
}
stroke(150, 150, 255);
strokeWeight(1);
let prevPieX = width;
let prevPieY = height / 2;
let below = false;
if (showQV) {
beginShape();
}
let count = 0;
for (
let i = 0;
i < history.length;
i += floor(history.length / historyDisplayCount)
) {
const hist = history[i];
const pieX = map(i, 0, history.length - 1, width, 0);
const pieY = map(
hist.dist,
0,
1,
height / 2,
(height / 2) * (1 + (below ? scl : -scl))
);
if (showHistoryI && !below && count % 20 == 0) {
textSize(12);
text(`${i}`, pieX + -10, pieY + (below ? 20 : -10));
}
if (showQV && !below) {
vertex(pieX, pieY);
}
if (!showQV) {
line(prevPieX, prevPieY, pieX, pieY);
prevPieX = pieX;
prevPieY = pieY;
}
// only show the pie line above pi
if (!below) {
pieLineY = pieY;
}
below = !below;
count++;
}
if (showQV) {
noFill();
strokeWeight(2);
stroke(150, 255, 150);
endShape();
}
lerpPieLineY = lerp(lerpPieLineY, pieLineY, 0.5);
if (dist(0, lerpPieLineY, 0, height / 2) > 20) {
// d line
stroke(255, 255, 0);
strokeWeight(3);
const dxOff = 20,
halfDy = lerpPieLineY + (height / 2 - lerpPieLineY) / 2;
line(0, lerpPieLineY, dxOff, halfDy);
line(dxOff, halfDy, 0, height / 2);
// d text
noStroke();
fill(255, 255, 0);
textSize(16);
text(abs(pie - PI), dxOff + 5, halfDy + 5);
}
stroke(255, 100, 100);
strokeWeight(2);
// pi line
line(0, height / 2, width, height / 2);
// pie line
line(0, lerpPieLineY, width, lerpPieLineY);
noStroke();
textSize(24);
fill(0);
// pi text
text("𝜋 = " + PI, 10, height / 2 + 25);
// pie text
text("🥧 = " + pie, 10, lerpPieLineY - 10);
noStroke();
if (paused) {
fill(255, 0, 0);
text("paused", width / 2 - 50, 80);
}
// controls
textSize(16);
fill(0);
const helpOffsetInterval = 20;
let helpOffset = height - 10;
text("h to toggle help", 10, helpOffset);
if (showHelp) {
text(
`v toggles displaying quadratic equation and points`,
10,
(helpOffset -= helpOffsetInterval)
);
text(
`, and . change the number of previous pie values displayed by a factor of 2 (count = ${historyDisplayCount})`,
10,
(helpOffset -= helpOffsetInterval)
);
text(
"n sets the number of previous pie values displayed to auto",
10,
(helpOffset -= helpOffsetInterval)
);
text(
`i to display the index of each previous pie value (i = ${history.length})`,
10,
(helpOffset -= helpOffsetInterval)
);
text(
`right and left arrows change the iterations per frame by a factor of 2 (i / frame = ${iPerFrame})`,
10,
(helpOffset -= helpOffsetInterval)
);
text(`s to resume auto scale`, 10, (helpOffset -= helpOffsetInterval));
text(
`up and down arrows change the scale by a factor of 2 (scl = ${targetScl.toFixed(
10
)})`,
10,
(helpOffset -= helpOffsetInterval)
);
text("space to pause", 10, (helpOffset -= helpOffsetInterval));
text("r to reset", 10, (helpOffset -= helpOffsetInterval));
}
fill(150, 255, 150);
// title
textSize(24);
text("finding 𝜋 with the Madhava–Leibniz series", 5, 25);
// equation
textSize(16);
text("𝜋/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 ...", 7, 50);
}
function keyPressed() {
if (keyCode === UP_ARROW) {
targetScl *= 2;
scaleChanged = true;
} else if (keyCode === DOWN_ARROW) {
targetScl *= 0.5;
targetScl = targetScl < 1 ? 1 : targetScl;
scaleChanged = true;
} else if (keyCode === RIGHT_ARROW) {
iPerFrame *= 2;
} else if (keyCode === LEFT_ARROW) {
iPerFrame *= 0.5;
iPerFrame = round(iPerFrame < 1 ? 1 : iPerFrame);
} else if (keyCode === 190) {
// .
historyDisplayCount *= 0.5;
historyDisplayCount = historyDisplayCount < 1 ? 1 : historyDisplayCount;
historyDisplayCountChanged = true;
} else if (keyCode === 188) {
// ,
historyDisplayCount *= 2;
historyDisplayCount =
historyDisplayCount < history.length
? historyDisplayCount
: history.length;
historyDisplayCountChanged = true;
} else if (keyCode === 78) {
// n
historyDisplayCountChanged = false;
historyDisplayCount = 256;
} else if (keyCode === 73) {
// i
showHistoryI = !showHistoryI;
} else if (keyCode === 32) {
// SPACE
paused = !paused;
} else if (keyCode === 82) {
// r
restart();
} else if (keyCode === 83) {
// s
scaleChanged = false;
} else if (keyCode === 72) {
// h
showHelp = !showHelp;
} else if (keyCode === 86) {
// v
showQV = !showQV;
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}