raw math

Drawing an upright star polygon

Robert Eisele

Drawing a regular star with \(n\) edges that stands upright on the ground should be easy with a rotation by \(\Delta\alpha=\frac{1}{n}\) around the center of the star. For each of the \(2n\) 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 \(n\) 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:

\[ \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 \(n\) and can be described by:

\[ \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)\) of denominoators:

\(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)\) (from A145979) for all \((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 \(\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, -1\) emerges, which obviously is \(2-m\) for \(m\in \{0,1,2,3\}\). From this follows that the angle \(\alpha_i\) for each edge \(i\) is

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

The final implementation of a star with \(n\) 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
}