raw math

Drawing an upright star polygon

Robert Eisele

Drawing a regular star with nn edges that stands upright on the ground should be easy with a rotation by Δα=1n\Delta\alpha=\frac{1}{n} around the center of the star. For each of the 2n2n edges we toggle between the inner and the outer radius like so:

for (let i = 0; i <= 2 * n; i++) {
  let alpha = i / n * Math.PI;
  let radius = 1 === i % 2 ? innerRadius : outerRadius;

  let x = Math.cos(alpha) * radius;
  let y = Math.sin(alpha) * radius;
  // ... draw line to x, y
}

Here is a visualization of the algorithm where you can change the number of edges nn of the star with the slider below. As you can see the stars do not stand upright all the time as it would when you check the corrected version:

Corrected

The question is, how can we derive the correction. The first edge is marked with a circle and the needed correction should be the minimal rotation to make the star stand on the bottom edges. When we analyze the first angles, we see the following pattern:

correction={0 if n=216π if n=314π if n=4110π if n=50 if n=6114π if n=7... if n=8 \text{correction}= \begin{cases} 0 &\text{ if } n=2\\ -\frac{1}{6}\pi &\text{ if } n=3\\ \frac{1}{4}\pi &\text{ if } n=4\\ \frac{1}{10}\pi &\text{ if } n=5\\ 0 &\text{ if } n=6\\ -\frac{1}{14}\pi & \text{ if } n=7\\ ... & \text{ if } n=8\\ \end{cases}

It turns out that the pattern that starts to appear is repeating every four nn and can be described by:

correction={1nπ if (nmod4)=012nπ if (nmod4)=10 if (nmod4)=212nπ if (nmod4)=3 \text{correction}= \begin{cases} \frac{1}{n}\pi &\text{ if } (n\bmod 4)=0\\ \frac{1}{2n}\pi &\text{ if } (n\bmod 4)=1\\ 0 &\text{ if } (n\bmod 4)=2\\ -\frac{1}{2n}\pi &\text{ if } (n\bmod 4)=3 \end{cases}

When taking the denominator of zero being zero, we get the series a(n)a(n) of denominoators:

0,6,4,10,0,14,8,18,0,22,12,26,0,30,16,34,0,38,...0, -6, 4, 10, 0, -14, 8, 18, 0, -22, 12, 26, 0, -30, 16, 34, 0, -38, ...

This is pretty interesting, as a(n)=A145979(n)|a(n)|= A145979(n) (from A145979) for all (nmod4)2(n\bmod 4) \neq 2 - which shows a relation to n-gons. If we implement this correction, we could add the fraction of π\pi to the actual angle by naivly implementing:

switch (edges % 4) {
  case 0:
    alpha += Math.PI / edges;
    break;
  case 1:
    alpha += Math.PI / (2 * edges);
    break;
  case 3:
    alpha -= Math.PI / (2 * edges);
    break;
}

However, we could factor out πn\frac{\pi}{n} and since we work with a fraction of π\pi, we can extend the fraction by two to get the following:

for (let i = 0; i <= 2 * n; i++) {
  let alpha2Nominator = 2 * i;
  let radius = 1 === i % 2 ? innerRadius : outerRadius;

    switch (edges % 4) {
      case 0:
        alpha2Nominator += 2;
        break;
      case 1:
        alpha2Nominator += 1;
        break;
      case 3:
        alpha2Nominator -= 1;
        break;
    }

  let x = Math.cos(alpha2Nominator * Math.PI / (2*edges)) * radius;
  let y = Math.sin(alpha2Nominator * Math.PI / (2*edges)) * radius;
  // ... draw line to x, y
}

Now the new pattern 2,1,0,12, 1, 0, -1 emerges, which obviously is 2m2-m for m{0,1,2,3}m\in \{0,1,2,3\}. From this follows that the angle αi\alpha_i for each edge ii is

αi=2i+2(nmod4)2nπ\begin{array}{rl} \alpha_i &= \frac{2i+2-(n\bmod 4)}{2n}\pi \end{array}

The final implementation of a star with nn edges is therefore:

for (let i = 0; i <= 2 * n; i++) {
  let alpha = (2 * i + 2 - n % 4) / (2 * n) * Math.PI;
  let radius = 1 === i % 2 ? innerRadius : outerRadius;

  let x = Math.cos(alpha) * radius;
  let y = Math.sin(alpha) * radius;
  // ... draw line to x, y
}