70 lines
1.5 KiB
Plaintext

// Convert x into its expansion in base b, as an array of integers (ascending powers of b)
toBase = (b, x) => {
if (x == 0) { return [0] }
let ret = [];
while (x > 0) {
ret.push(x % b);
x = Math.floor(x / b);
}
return ret;
};
// Interpret xs as an expansion in base b (ascending powers of b)
fromBase = (b, xs) => {
let plval = 1
return xs.reduce((a, x) => {
let new_a = x * plval;
plval *= b;
return a + new_a;
}, 0)
}
// Map an expansion to a complex number (as a 2-array).
// The expansion is interpreted in base `b`.
// `n` terms of the series are used, with geometric ratio `c`
adicAngles = (expansion, b, n, c) => {
return d3.range(n).reduce((a, i) => {
let angle = fromBase(b, expansion.slice(null, i + 1)) / (b ** (i + 1));
let x = c**i * Math.cos(2 * Math.PI * angle);
let y = c**i * Math.sin(2 * Math.PI * angle);
return [a[0] + x, a[1] + y];
}, [0, 0]);
}
pointCount = 1024;
expansions = d3.range(pointCount).map((x) => toBase(base, x));
embedding = expansions.map(
(x) => adicAngles(x, embedBase, 15, geometric)
);
viewof base = Inputs.range([2, 10], {
value: 2,
step: 1,
label: "Base of expansions (b)",
});
viewof embedBase = Inputs.range([2, 10], {
value: 2,
step: 0.2,
label: "Embedding base (p)",
});
viewof geometric = Inputs.range([0.005, 0.995], {
value: 0.9,
step: 0.005,
label: "Geometric ratio (c)",
});
plot = Plot.plot({
grid: true,
inset: 10,
// aspectRatio: 1,
width: 640,
height: 480,
marks: [
Plot.dot(embedding, { r: 1 })
]
});