Fourier Curves

The core idea

Every curve in this project is built from rotating complex numbers. A single rotating complex exponential traces a circle:

exp(im · f · t)  for t ∈ [0, 2π]

where f is an integer that controls how many times the point goes around the circle per period. Adding several of these together with different magnitudes and frequencies produces a more complex path — the same idea behind a Fourier series.

μg — the general curve

μg(t; cs, fs)  =  Σᵢ  cs[i] · exp(im · fs[i] · t)

Parameters:

ParameterTypeDescription
tRealCurve parameter, typically range(0, 2π, n)
csVector{Complex}Coefficients — one per frequency term
fsVector{Real}Frequencies — integers, but any real is accepted

The return value is a complex number whose real part is x and imaginary part is y on the canvas.

What each parameter controls

cs — coefficients

Each coefficient cs[i] is a complex number with a magnitude and a phase:

  • Magnitude |cs[i]| controls how large a contribution that frequency makes. Larger magnitude → that term pulls the curve further from the origin.
  • Phase angle(cs[i]) rotates that term's starting position. In practice most examples use real positive values, but complex coefficients shift where each circular component starts, changing the overall curve shape without changing its "size".

fs — frequencies

Each frequency fs[i] controls how many loops that component makes per period:

  • fs[i] = 1 — one loop (a circle)
  • fs[i] = 2 — two loops (the component winds around twice per cycle)
  • fs[i] = -1 — one loop in the opposite direction
  • Large |fs[i]| — tight, high-frequency wiggles added to the curve

Combining a low frequency (the overall shape) with higher frequencies (fine detail) is how intricate curves are built. The classic example from Farris:

cs = [1.0, 0.5, im/3]
fs = [1, 6, -14]

This produces a curve with a large circular component (f=1), a medium six-fold component (f=6), and a fine 14-fold component in reverse (f=-14).

Quick experiments

Change the shape by swapping frequencies:

# Simple figure-eight-like shape
μg(t, cs=[1.0, 0.5], fs=[1, -1])

# More petals by adding a higher frequency
μg(t, cs=[1.0, 0.3, 0.15], fs=[1, 5, 10])

fkm — the selective Fourier sum

fkm(t, k, m;  M=5, as=ones(2M+1))

fkm is a restricted version of μg that only uses frequencies n where n mod m == k. This is the construction Farris uses in Chapter 4 to enforce specific wallpaper symmetry groups.

What the parameters do

ParameterDefaultDescription
kResidue class. Which remainder to keep: selects frequencies where n % m == k
mModulus. The "period" of the selection rule
M5Half-bandwidth. Frequencies run from −M to +M; 2M+1 total possible terms
asones(2M+1)Weights. One coefficient per frequency index from −M to +M

How k and m create symmetry

The selection rule n % m == k keeps only frequencies that are congruent to k modulo m. This enforces m-fold rotational symmetry in the resulting artwork. The curve itself may not look symmetric, but when you draw m rotational copies (as drawZθfunc4b does), the copies will tile perfectly.

Some useful combinations:

mkEffect
313-fold symmetry (frequencies 1, 4, 7, −2, −5, …)
525-fold symmetry
616-fold symmetry
414-fold symmetry

Setting k=0 selects frequencies 0, ±m, ±2m, … which tends to produce flowers with petals on the axes.

M — the bandwidth

M controls how many terms are available. With M=5 there are 11 possible frequencies (−5 to +5); with M=37 there are 75. A larger M allows finer detail in the curve at the cost of computation time. For artwork purposes, M between 10 and 50 gives good results.

as — per-frequency weights

as is a vector of length 2M+1. The index n+M+1 maps frequency n to its weight. Frequencies that don't satisfy the residue rule are ignored regardless of their weight.

  • All ones (default): equal weight to all selected frequencies — produces a relatively "busy" curve.
  • Cosine taper (as[i] = cos(π*(i-M-1)/(2M))): gives less weight to extreme frequencies, producing smoother curves.
  • Random (as = randn(2M+1)): each call gives a different curve shape with the same symmetry order.

Example

using DigitalArt

M  = 20
t  = range(0, 2π, 1000)
# 5-fold rotational symmetry, residue class 2
vals = fkm.(t, 2, 5; M=M, as=ones(2M+1))

Connecting curves to the canvas

Both μg and fkm return complex numbers. To draw them:

xs = real.(vals)
ys = imag.(vals)
lines!(ax, xs, ys)

The canvas coordinates run roughly in the range set by the largest coefficient. If the curve looks too small, scale the coefficients:

cs_scaled = 2.0 .* cs   # double the size