// 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([1.1, 10], {
  value: 2,
  step: 0.1,
  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 })
  ]
});
