Math::Curves
DivergentTwo curve primitives for interpolation — a straight-line function and Bezier evaluation at a parameter for two, three or four control points.
- Version
0.0.1cpan:SAMGWISE- Depends
none beyond the core- License
- Artistic-2.0
- Its own test suite
- no test files, so trivially green
- Checked
- 2026-09-15 against Raku++ 3.28.0 and Rakudo 2026.08
Install it #
$ rakupp install Math::Curveszef install Math::Curves writes the same store; either installer leaves the module usable by both engines.
What it is for #
Animation, easing and any kind of smooth interpolation all come down to evaluating a curve at a parameter between 0 and 1. Bezier curves are the standard choice because they are cheap, and because their control points are an intuitive handle.
This distribution is the evaluation, for the two-, three- and four-point cases and for an arbitrary list.
Evaluating a curve #
use Math::Curves;
say 'linear (two control points), from 0 to 10:';
for 0/1, 1/4, 1/2, 3/4, 1/1 -> $t {
say sprintf(' t=%-5s -> %s', $t.raku, bézier($t, 0, 10).raku);
}
say '';
say 'quadratic (three), with the middle point pulled to 10:';
for 0/1, 1/4, 1/2, 3/4, 1/1 -> $t {
say sprintf(' t=%-5s -> %s', $t.raku, bézier($t, 0, 10, 0).raku);
}
say '';
say 'cubic (four), the usual easing shape:';
for 0/1, 1/4, 1/2, 3/4, 1/1 -> $t {
say sprintf(' t=%-5s -> %s', $t.raku, bézier($t, 0, 0, 10, 10).raku);
}linear (two control points), from 0 to 10:
t=0.0 -> 0.0
t=0.25 -> 2.5
t=0.5 -> 5.0
t=0.75 -> 7.5
t=1.0 -> 10.0
quadratic (three), with the middle point pulled to 10:
t=0.0 -> 0.0
t=0.25 -> 3.75
t=0.5 -> 5.0
t=0.75 -> 3.75
t=1.0 -> 0.0
cubic (four), the usual easing shape:
t=0.0 -> 0.0
t=0.25 -> 1.5625
t=0.5 -> 5.0
t=0.75 -> 8.4375
t=1.0 -> 10.0The cubic row is the classic ease-in-out: slow at both ends, fast through the middle.
The list form and the parameter range #
use Math::Curves;
say 'a list of control points : ', bézier(1/2, (0, 10, 0)).raku;
say '';
say 't must be in 0..1 — the subset enforces it:';
for 0/1, 1/1, 3/2, -1/2 -> $t {
my $r = try bézier($t, 0, 10);
say sprintf(' t=%-6s -> %s', $t.raku, $r.defined ?? $r.Str !! 'refused');
}a list of control points : 5.0
t must be in 0..1 — the subset enforces it:
t=0.0 -> 0
t=1.0 -> 10
t=1.5 -> refused
t=-0.5 -> refusedNote the export is spelled with an acute accent — bézier, not bezier — and there is no ASCII alias, so the accent must be typed everywhere.
The one thing to know #
line($x, $gradient) returns $x + ($x * $gradient), not $x * $gradient.
use Math::Curves;
for (2, 1/2), (10, 1/1), (4, 0/1), (5, 2/1) -> ($x, $g) {
say sprintf('line(%2d, %-5s) = %-8s x * g would be %s',
$x, $g.raku, line($x, $g).raku, ($x * $g).raku);
}
say '';
say 'so a "gradient" of 0 is the identity rather than a flat line,';
say 'and the function never passes through the origin except at x = 0.';line( 2, 0.5 ) = 3.0 x * g would be 1.0
line(10, 1.0 ) = 20.0 x * g would be 10.0
line( 4, 0.0 ) = 4.0 x * g would be 0.0
line( 5, 2.0 ) = 15.0 x * g would be 10.0
so a "gradient" of 0 is the identity rather than a flat line,
and the function never passes through the origin except at x = 0.The second parameter is a fractional increment applied to x, not a slope. Anyone reading it as y = mx gets an answer wrong by exactly x — which is a large error and a plausible-looking one.
Where the two engines differ #
On what happens when t is not a Rat, and it is a compile-time error against a runtime one.
bézier's t is declared Transition, a subset of Rat. So bézier(0, 0, 10) and bézier(1, 0, 10) — the two endpoints, written the obvious way with integer literals — do not dispatch. Rakudo reports it at compile time and refuses the whole file; Raku++ compiles and fails at runtime when that line is reached.
A program with such a call in a rarely taken branch therefore runs until it gets there on one engine and will not compile at all on the other.
Write 0/1 and 1/1, as every example on this page does. Num arguments fail too — 0.5e0 does not match Rat — and line's gradient is Rat as well, so line(2, 0.5e0) fails where line(2, 0.5) succeeds.
The distribution declares no test files and no auth in its metadata.