66 lines
2.1 KiB
JavaScript
66 lines
2.1 KiB
JavaScript
function babylonianSpiral(stepCount) {
|
|
const tau = 2 * Math.PI;
|
|
const squares = Array(stepCount + 1).fill(0).map((_, i) => i * i);
|
|
const points = [[0, 0], [0, 1]];
|
|
let norm = 1;
|
|
|
|
for (let step = 0; step < stepCount - 2; ++step) {
|
|
const previousPoint = points[points.length - 1];
|
|
const theta = Math.atan2(previousPoint[1], previousPoint[0]);
|
|
let candidates = [];
|
|
|
|
while (candidates.length === 0) {
|
|
norm += 1;
|
|
for (let i = 0; i < stepCount; ++i) {
|
|
const a = squares[i];
|
|
if (a > norm / 2) break;
|
|
for (let j = Math.floor(Math.sqrt(norm)) + 1; j >= 0; --j) {
|
|
const b = squares[j];
|
|
if (a + b < norm) break;
|
|
if (a + b === norm) {
|
|
const nextPoints = [
|
|
[i, j], [-i, j], [i, -j], [-i, -j],
|
|
[j, i], [-j, i], [j, -i], [-j, -i]
|
|
];
|
|
candidates.push(...nextPoints);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let minimum = null;
|
|
let minimumValue = tau;
|
|
for (const candidate of candidates) {
|
|
const value = (theta - Math.atan2(candidate[1], candidate[0]) + tau) % tau;
|
|
if (value < minimumValue) {
|
|
minimumValue = value;
|
|
minimum = candidate;
|
|
}
|
|
}
|
|
points.push(minimum);
|
|
}
|
|
|
|
// Accumulate points
|
|
for (let i = 0; i < points.length - 1; ++i) {
|
|
points[i + 1] = [
|
|
points[i][0] + points[i + 1][0],
|
|
points[i][1] + points[i + 1][1]
|
|
];
|
|
}
|
|
|
|
return points;
|
|
}
|
|
|
|
function main() {
|
|
const points = babylonianSpiral(40);
|
|
console.log("The first 40 points of the Babylonian spiral are:");
|
|
for (let i = 0, column = 0; i < 40; ++i) {
|
|
const pointStr = `(${points[i][0]}, ${points[i][1]})`;
|
|
process.stdout.write(pointStr.padStart(10));
|
|
if (++column % 10 === 0) {
|
|
console.log();
|
|
}
|
|
}
|
|
}
|
|
|
|
main();
|