Skip to the plate
FORMA PUBLIC DOMAIN GENERATIVE ATLAS / ED. 0.28
Plate 02, Rhodonea: a still of the polar / sinusoid plate as the atlas renders it, in the curves accent.

PL. 02  ·  CURVES / POLAR / SINUSOID

Rhodonea

Guido Grandi, c. 1723

OPEN THE LIVE PLATE ▸

DEFINITION

r(θ) = cos(k·θ),  k = n/d

NOTES

A sinusoid in polar coordinates. Grandi named these rose curves for the obvious reason. When k is an integer the bloom has k petals if k is odd and 2k if it is even — a parity quirk that comes from whether the negative half of the cosine retraces the positive half or lands opposite it.

PROVENANCE

Origin
Guido Grandi, Italian mathematician, c. 1723
Standing
Public domain — 18th-century mathematics
Constants
n/d rational gives a closed curve; large d gives dense rosettes

HOUDINI · VEX

The same published mathematics as a Detail Wrangle body. Paste it into a Wrangle with Run Over set to Detail; every constant is the published value plus a tweak channel, so Create Spare Parameters gives a slider that starts where the paper does.

// FORMA — PL. 02 · RHODONEA — Guido Grandi, c. 1723
//   r(θ) = cos(k·θ),  k = n/d
// Paste into a Detail Wrangle (Run Over: Detail), no inputs needed.
// Written from the published mathematics, not adapted from any code.
// Constants arrive at their published values. Press the node's Create
// Spare Parameters button and every tweak becomes a slider — starting
// at 0, the published figure, and moving in the constant's own units.
// https://forma-gen.com/#plate=rose

float p_n = 5 + chf('n_tweak');       // n — numerator · live 1 .. 13
float p_d = 4 + chf('d_tweak');       // d — denominator · live 1 .. 13

// The plate's own colour: FORMA's CURVES accent as a cosine ramp,
// brightest near t = 0 and t = 1, near-black around t = 0.5.
vector forma_ramp(float t){
  return set(
    0.11 + 0.1196 * cos(6.28318530718 * (t + 0)),
    0.46 + 0.5 * cos(6.28318530718 * (t + 0.05)),
    0.2453 + 0.2667 * cos(6.28318530718 * (t + 0.1)));
}

// r = cos(k·θ) with k = n/d closes after d full turns of θ, tracing every
// petal exactly once — the same span the plate walks.
int forma_n = 4000;

int   nn = int(p_n), dd = int(p_d);
float k = float(nn) / float(dd);
float turns = 6.28318530718 * float(dd);
int prim = addprim(0, "polyline");
for (int i = 0; i <= forma_n; i++){
    float th = float(i) / float(forma_n) * turns;
    float r  = cos(k * th);
    // canvas y runs down; negated so the curve sits as the plate shows it
    int pt = addpoint(0, set(r * cos(th), -r * sin(th), 0.0));
    // colour sweeps the bright lobe of the ramp along the curve
    float u = float(i) / float(forma_n);
    setpointattrib(0, "Cd", pt, forma_ramp(0.8 + 0.3 * u));
    addvertex(0, prim, pt);
}

AFTER EFFECTS · EXPRESSION

The same published mathematics as a Shape Layer path expression. Paste it onto a Path property; every constant is the published value plus a Slider Control named _tweak, so a bare paste already draws the figure and each slider moves one constant in its own units. Trim Paths is the comet.

// FORMA — PL. 02 · RHODONEA — Guido Grandi, c. 1723
//   r(θ) = cos(k·θ),  k = n/d
// After Effects port — paste onto a Shape Layer's Path property
// (Contents › Shape › Path). Written from the published mathematics, not
// adapted from any code. Constants arrive at their published values; add a
// Slider Control (Effect › Expression Controls) named <k>_tweak and that
// constant moves in its own units, starting at 0 — the published figure.
// The plate's comet and its reveal are Trim Paths; the stroke colour is
// FORMA's CURVES accent, #3DFF88. Animation runs on time.
// https://forma-gen.com/#plate=rose

// A missing slider reads 0, so a bare paste already draws the figure.
function forma_tweak(n){ try { return effect(n)("Slider"); } catch (e){ return 0; } }
var p_n = 5 + forma_tweak("n_tweak");     // n — numerator · live 1 .. 13
var p_d = 4 + forma_tweak("d_tweak");     // d — denominator · live 1 .. 13

// The frame: the plate's W × H canvas is this comp, with the origin at the
// layer's anchor; canvas y already runs down, as After Effects' does.
var forma_W = thisComp.width, forma_H = thisComp.height, forma_t = time;
var forma_phase = 0.46361143887043;   // this plate's own fixed phase, as the page has it
function forma_pt(x, y){ return [x - forma_W / 2, y - forma_H / 2]; }

// r = R·cos(kθ) with k = n/d, traced over d full turns so a rational k closes.
// The page's comet circles once every ~24 s (Trim Paths, End 0 → 100%).
var R = Math.min(forma_W, forma_H) * 0.45, k = p_n / p_d;
var turns = Math.PI * 2 * p_d, N = 4000;
var pts = [];
for (var i = 0; i <= N; i++){
  var th = i / N * turns, r = R * Math.cos(k * th);
  pts.push(forma_pt(forma_W / 2 + r * Math.cos(th), forma_H / 2 + r * Math.sin(th)));
}
createPath(pts, [], [], true);