bezier-eval.dhover×251all
#!/usr/bin/env dub
/+ dub.sdl:
    name "manim_bezier_eval"
    targetPath "build"
+/
/**
 * Quadratic (3-point) vs cubic (4-point) Bézier curves: de Casteljau
 * evaluation, exact quadratic→cubic degree elevation, and the one-way
 * conversion cost that a single quadratic pays approximating a cubic.
 *
 * The *object & scene model* axis of the analysis spine, exercised in code.
 * The two Manim geometry camps disagree on the Bézier basis: ManimGL and
 * community's OpenGL classes store curves as **quadratic** triples
 * `(anchor, handle, anchor)`; community's Cairo classes store **cubic**
 * quads `(anchor, handle, handle, anchor)`. The choice is load-bearing for a
 * reimplementation because the conversion between the two bases is *not*
 * symmetric:
 *
 *   1. A quadratic Bézier `Q(P0,P1,P2)` elevates to a cubic `C(C0..C3)`
 *      *exactly* — `C0=P0`, `C1=P0+2/3(P1-P0)`, `C2=P2+2/3(P1-P2)`, `C3=P2` —
 *      so the two curves are pointwise identical. This probe elevates a
 *      quadratic and prints the max sample deviation (0 within fp epsilon):
 *      quadratics are a strict subset of cubics.
 *   2. The reverse is lossy: a general cubic has an inflection a single
 *      quadratic cannot follow. This probe fits the "best" single quadratic
 *      (sharing the cubic's endpoints, handle at the cubic control average)
 *      and prints the residual max deviation — the per-curve error the
 *      quadratic-canonical engines eat, and the reason a cubic-canonical
 *      store only makes the *GPU* backend lower curves (§ cubic-canonical).
 *
 * This is the concrete evidence behind the `manim-community/scene-graph.md`
 * and `manimgl.md` geometry sections, and behind the proposal's decision to
 * standardise on a cubic interchange basis.
 *
 * Companion to docs/research/manim/manim-community/scene-graph.md
 *   § "Bézier basis: cubic vs quadratic" and docs/research/manim/manimgl.md
 *   § "Quadratic curves in a structured array".
 * Run with: dub run --single bezier-eval.d
 *
 * Portability: pure computation, no external dependencies or host
 * capabilities — compiles and runs identically everywhere.
 */
module 
(module) manim_bezier_eval

Quadratic (3-point) vs cubic (4-point) Bézier curves: de Casteljau evaluation, exact quadratic→cubic degree elevation, and the one-way conversion cost that a single quadratic pays approximating a cubic.

The object & scene model axis of the analysis spine, exercised in code. The two Manim geometry camps disagree on the Bézier basis: ManimGL and community's OpenGL classes store curves as quadratic triples (anchor, handle, anchor); community's Cairo classes store cubic quads (anchor, handle, handle, anchor). The choice is load-bearing for a reimplementation because the conversion between the two bases is not symmetric:

  1. A quadratic Bézier Q(P0,P1,P2) elevates to a cubic C(C0..C3) exactlyC0=P0, C1=P0+2/3(P1-P0), C2=P2+2/3(P1-P2), C3=P2 — so the two curves are pointwise identical. This probe elevates a quadratic and prints the max sample deviation (0 within fp epsilon): quadratics are a strict subset of cubics.

  2. The reverse is lossy: a general cubic has an inflection a single quadratic cannot follow. This probe fits the "best" single quadratic (sharing the cubic's endpoints, handle at the cubic control average) and prints the residual max deviation — the per-curve error the quadratic-canonical engines eat, and the reason a cubic-canonical store only makes the GPU backend lower curves (§ cubic-canonical).

This is the concrete evidence behind the manim-community/scene-graph.md and manimgl.md geometry sections, and behind the proposal's decision to standardise on a cubic interchange basis.

Companion to docs/research/manim/manim-community/scene-graph.md § "Bézier basis: cubic vs quadratic" and docs/research/manim/manimgl.md § "Quadratic curves in a structured array". Run with: dub run --single bezier-eval.d

Portability

pure computation, no external dependencies or host capabilities — compiles and runs identically everywhere.

manim_bezier_eval
;
import
(package) std
std
.
(module) std.math

Contains the elementary mathematical functions (powers, roots, and trigonometric functions), and low-level floating-point operations. Mathematical special functions are available in std.mathspecial.

Category Members
Constants E PI PI_2 PI4 M1_PI M2_PI M2_SQRTPI LN10 LN2 LOG2 LOG2E LOG2T LOG10E SQRT2 SQRT1_2
Algebraic abs fabs sqrt cbrt hypot poly nextPow2 truncPow2
Trigonometry sin cos tan asin acos atan atan2 sinh cosh tanh asinh acosh atanh
Rounding ceil floor round lround trunc rint lrint nearbyint rndtol quantize
Exponentiation & Logarithms pow powmod exp exp2 expm1 ldexp frexp log log2 log10 logb ilogb log1p scalbn
Remainder fmod modf remainder remquo
Floating-point operations approxEqual feqrel fdim fmax fmin fma isClose nextDown nextUp nextafter NaN getNaNPayload cmp
Introspection isFinite isIdentical isInfinity isNaN isNormal isSubnormal signbit sgn copysign isPowerOf2
Hardware Control IeeeFlags ieeeFlags resetIeeeFlags FloatingPointControl

The functionality closely follows the IEEE754-2008 standard for floating-point arithmetic, including the use of camelCase names rather than C99-style lower case names. All of these functions behave correctly when presented with an infinity or NaN.

The following IEEE 'real' formats are currently supported:

  • 64 bit Big-endian 'double' (eg PowerPC)

  • 128 bit Big-endian 'quadruple' (eg SPARC)

  • 64 bit Little-endian 'double' (eg x86-SSE2)

  • 80 bit Little-endian, with implied bit 'real80' (eg x87, Itanium)

  • 128 bit Little-endian 'quadruple' (not implemented on any known processor!)

  • Non-IEEE 128 bit Big-endian 'doubledouble' (eg PowerPC) has partial support

Unlike C, there is no global 'errno' variable. Consequently, almost all of these functions are pure nothrow.

Source

std/math/package.d

@copyrightCopyright The D Language Foundation 2000 - 2011. D implementations of tan, atan, atan2, exp, expm1, exp2, log, log10, log1p, log2, floor, ceil and lrint functions are based on the CEPHES math library, which is Copyright (C) 2001 Stephen L. Moshier <steve@moshier.net> and are incorporated herein by permission of the author. The author reserves the right to distribute this material elsewhere under different copying permissions. These modifications are distributed here under the following terms:@licenseBoost License 1.0.@authorsWalter Bright, Don Clugston, Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger
math
:
(alias) manim_bezier_eval.fabs = real std.math.algebraic.fabs(real x) pure nothrow @nogc @safe

Returns |x|

x fabs(x)
0.0 +0.0
+
fabs
,
(alias) manim_bezier_eval.sqrt = float std.math.algebraic.sqrt(float x) pure nothrow @nogc @safe

Compute square root of x.

x sqrt(x) invalid?
-0.0 -0.0 no
<0.0 yes
+ + no
sqrt
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) manim_bezier_eval.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
,
(alias template) manim_bezier_eval.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
alias
(alias) manim_bezier_eval.P = double[2]
P
= double[2];
(alias) manim_bezier_eval.P = double[2]
P
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) a
a
, in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) b
b
, double
(parameter) double t
t
) @safe pure nothrow @nogc
=> [
(parameter) const(double[2]) a
a
[0] + (
(parameter) const(double[2]) b
b
[0] -
(parameter) const(double[2]) a
a
[0]) *
(parameter) double t
t
,
(parameter) const(double[2]) a
a
[1] + (
(parameter) const(double[2]) b
b
[1] -
(parameter) const(double[2]) a
a
[1]) *
(parameter) double t
t
];
/// de Casteljau for a quadratic (3 control points).
(alias) manim_bezier_eval.P = double[2]
P
double[2] manim_bezier_eval.quad(in double[2] p0, in double[2] p1, in double[2] p2, double t) pure nothrow @nogc @safe

de Casteljau for a quadratic (3 control points).

quad
(in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) p0
p0
, in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) p1
p1
, in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) p2
p2
, double
(parameter) double t
t
) @safe pure nothrow @nogc
{ const
(local variable) const(double[2]) a
a
=
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(parameter) const(double[2]) p0
p0
,
(parameter) const(double[2]) p1
p1
,
(parameter) double t
t
);
const
(local variable) const(double[2]) b
b
=
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(parameter) const(double[2]) p1
p1
,
(parameter) const(double[2]) p2
p2
,
(parameter) double t
t
);
return
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(local variable) const(double[2]) a
a
,
(local variable) const(double[2]) b
b
,
(parameter) double t
t
);
} /// de Casteljau for a cubic (4 control points).
(alias) manim_bezier_eval.P = double[2]
P
double[2] manim_bezier_eval.cubic(in double[2] p0, in double[2] p1, in double[2] p2, in double[2] p3, double t) pure nothrow @nogc @safe

de Casteljau for a cubic (4 control points).

cubic
(in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) p0
p0
, in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) p1
p1
, in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) p2
p2
, in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) p3
p3
, double
(parameter) double t
t
) @safe pure nothrow @nogc
{ const
(local variable) const(double[2]) a
a
=
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(parameter) const(double[2]) p0
p0
,
(parameter) const(double[2]) p1
p1
,
(parameter) double t
t
);
const
(local variable) const(double[2]) b
b
=
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(parameter) const(double[2]) p1
p1
,
(parameter) const(double[2]) p2
p2
,
(parameter) double t
t
);
const
(local variable) const(double[2]) c
c
=
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(parameter) const(double[2]) p2
p2
,
(parameter) const(double[2]) p3
p3
,
(parameter) double t
t
);
const
(local variable) const(double[2]) d
d
=
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(local variable) const(double[2]) a
a
,
(local variable) const(double[2]) b
b
,
(parameter) double t
t
);
const
(local variable) const(double[2]) e
e
=
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(local variable) const(double[2]) b
b
,
(local variable) const(double[2]) c
c
,
(parameter) double t
t
);
return
double[2] manim_bezier_eval.lerp(in double[2] a, in double[2] b, double t) pure nothrow @nogc @safe
lerp
(
(local variable) const(double[2]) d
d
,
(local variable) const(double[2]) e
e
,
(parameter) double t
t
);
} double
double manim_bezier_eval.dist(in double[2] a, in double[2] b) pure nothrow @nogc @safe
dist
(in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) a
a
, in
(alias) manim_bezier_eval.P = double[2]
P
(parameter) const(double[2]) b
b
) @safe pure nothrow @nogc
=>
double std.math.algebraic.sqrt(double x) pure nothrow @nogc @safe

Compute square root of x.

x sqrt(x) invalid?
-0.0 -0.0 no
<0.0 yes
+ + no
sqrt
((
(parameter) const(double[2]) a
a
[0] -
(parameter) const(double[2]) b
b
[0]) ^^ 2 + (
(parameter) const(double[2]) a
a
[1] -
(parameter) const(double[2]) b
b
[1]) ^^ 2);
/// Polyline arc-length estimate over `n` samples. double
double manim_bezier_eval.arcLength(scope double[2] delegate(double) @safe f, ulong n = 256LU) @safe

Polyline arc-length estimate over n samples.

arcLength
(scope
(alias) manim_bezier_eval.P = double[2]
P
delegate(double) @safe
(parameter) double[2] delegate(double) @safe f
f
,
(alias) object.size_t = ulong
size_t
(parameter) ulong n
n
= 256) @safe
{ double
(local variable) double len
len
= 0;
(alias) manim_bezier_eval.P = double[2]
P
(local variable) double[2] prev
prev
=
(parameter) double[2] delegate(double) @safe f
f
(0);
foreach (
(local variable) ulong i
i
; 1 ..
(parameter) ulong n
n
+ 1)
{ const
(local variable) const(double[2]) cur
cur
=
(parameter) double[2] delegate(double) @safe f
f
(cast(double)
(local variable) ulong i
i
/
(parameter) ulong n
n
);
(local variable) double len
len
+=
double manim_bezier_eval.dist(in double[2] a, in double[2] b) pure nothrow @nogc @safe
dist
(
(local variable) double[2] prev
prev
,
(local variable) const(double[2]) cur
cur
);
(local variable) double[2] prev
prev
=
(local variable) const(double[2]) cur
cur
;
} return
(local variable) double len
len
;
} int
int D main() @safe
main
() @safe
{ // A quadratic and its EXACT cubic elevation. const
(alias) manim_bezier_eval.P = double[2]
P
(local variable) const(double[2]) q0
q0
= [0.0, 0.0],
(local variable) const(double[2]) q1
q1
= [1.0, 2.0],
(local variable) const(double[2]) q2
q2
= [3.0, 0.0];
const
(alias) manim_bezier_eval.P = double[2]
P
(local variable) const(double[2]) c0
c0
=
(local variable) const(double[2]) q0
q0
;
const
(alias) manim_bezier_eval.P = double[2]
P
(local variable) const(double[2]) c1
c1
= [
(local variable) const(double[2]) q0
q0
[0] + 2.0 / 3 * (
(local variable) const(double[2]) q1
q1
[0] -
(local variable) const(double[2]) q0
q0
[0]),
(local variable) const(double[2]) q0
q0
[1] + 2.0 / 3 * (
(local variable) const(double[2]) q1
q1
[1] -
(local variable) const(double[2]) q0
q0
[1])];
const
(alias) manim_bezier_eval.P = double[2]
P
(local variable) const(double[2]) c2
c2
= [
(local variable) const(double[2]) q2
q2
[0] + 2.0 / 3 * (
(local variable) const(double[2]) q1
q1
[0] -
(local variable) const(double[2]) q2
q2
[0]),
(local variable) const(double[2]) q2
q2
[1] + 2.0 / 3 * (
(local variable) const(double[2]) q1
q1
[1] -
(local variable) const(double[2]) q2
q2
[1])];
const
(alias) manim_bezier_eval.P = double[2]
P
(local variable) const(double[2]) c3
c3
=
(local variable) const(double[2]) q2
q2
;
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("== quadratic (3-pt) vs its exact cubic (4-pt) elevation ==");
void std.stdio.writefln!(char, const(double[2]), const(double[2]), const(double[2]))(in char[] fmt, const(double[2]) __param_1, const(double[2]) __param_2, const(double[2]) __param_3) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" quadratic control: %s %s %s",
(local variable) const(double[2]) q0
q0
,
(local variable) const(double[2]) q1
q1
,
(local variable) const(double[2]) q2
q2
);
void std.stdio.writefln!(char, const(double[2]), const(double[2]), const(double[2]), const(double[2]))(in char[] fmt, const(double[2]) __param_1, const(double[2]) __param_2, const(double[2]) __param_3, const(double[2]) __param_4) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" elevated cubic : %s %s %s %s",
(local variable) const(double[2]) c0
c0
,
(local variable) const(double[2]) c1
c1
,
(local variable) const(double[2]) c2
c2
,
(local variable) const(double[2]) c3
c3
);
void std.stdio.writefln!char(in char[] fmt) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" t quad(t) cubic(t) |Δ|");
double
(local variable) double elevMax
elevMax
= 0;
foreach (
(local variable) int i
i
; 0 .. 11)
{ const
(local variable) const(double) t
t
=
(local variable) int i
i
/ 10.0;
const
(local variable) const(double[2]) a
a
=
double[2] manim_bezier_eval.quad(in double[2] p0, in double[2] p1, in double[2] p2, double t) pure nothrow @nogc @safe

de Casteljau for a quadratic (3 control points).

quad
(
(local variable) const(double[2]) q0
q0
,
(local variable) const(double[2]) q1
q1
,
(local variable) const(double[2]) q2
q2
,
(local variable) const(double) t
t
);
const
(local variable) const(double[2]) b
b
=
double[2] manim_bezier_eval.cubic(in double[2] p0, in double[2] p1, in double[2] p2, in double[2] p3, double t) pure nothrow @nogc @safe

de Casteljau for a cubic (4 control points).

cubic
(
(local variable) const(double[2]) c0
c0
,
(local variable) const(double[2]) c1
c1
,
(local variable) const(double[2]) c2
c2
,
(local variable) const(double[2]) c3
c3
,
(local variable) const(double) t
t
);
const
(local variable) const(double) d
d
=
double manim_bezier_eval.dist(in double[2] a, in double[2] b) pure nothrow @nogc @safe
dist
(
(local variable) const(double[2]) a
a
,
(local variable) const(double[2]) b
b
);
if (
(local variable) const(double) d
d
>
(local variable) double elevMax
elevMax
)
(local variable) double elevMax
elevMax
=
(local variable) const(double) d
d
;
void std.stdio.writefln!(char, const(double), const(double), const(double), const(double), const(double), const(double))(in char[] fmt, const(double) __param_1, const(double) __param_2, const(double) __param_3, const(double) __param_4, const(double) __param_5, const(double) __param_6) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %4.1f (%7.4f, %7.4f) (%7.4f, %7.4f) %.2e",
(local variable) const(double) t
t
,
(local variable) const(double[2]) a
a
[0],
(local variable) const(double[2]) a
a
[1],
(local variable) const(double[2]) b
b
[0],
(local variable) const(double[2]) b
b
[1],
(local variable) const(double) d
d
);
}
void std.stdio.writefln!(char, double)(in char[] fmt, double __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" max elevation deviation: %.2e (quadratics are a strict subset of cubics)",
(local variable) double elevMax
elevMax
);
// A general cubic with an inflection, and the best single quadratic // through its endpoints (handle at the average of the two cubic handles). const
(alias) manim_bezier_eval.P = double[2]
P
(local variable) const(double[2]) g0
g0
= [0.0, 0.0],
(local variable) const(double[2]) g1
g1
= [1.0, 3.0],
(local variable) const(double[2]) g2
g2
= [2.0, -3.0],
(local variable) const(double[2]) g3
g3
= [3.0, 0.0];
const
(alias) manim_bezier_eval.P = double[2]
P
(local variable) const(double[2]) h
h
= [(
(local variable) const(double[2]) g1
g1
[0] +
(local variable) const(double[2]) g2
g2
[0]) / 2, (
(local variable) const(double[2]) g1
g1
[1] +
(local variable) const(double[2]) g2
g2
[1]) / 2];
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("\n== a cubic with an inflection, approximated by ONE quadratic ==");
void std.stdio.writefln!(char, const(double[2]), const(double[2]), const(double[2]), const(double[2]))(in char[] fmt, const(double[2]) __param_1, const(double[2]) __param_2, const(double[2]) __param_3, const(double[2]) __param_4) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" cubic control : %s %s %s %s",
(local variable) const(double[2]) g0
g0
,
(local variable) const(double[2]) g1
g1
,
(local variable) const(double[2]) g2
g2
,
(local variable) const(double[2]) g3
g3
);
void std.stdio.writefln!(char, const(double[2]))(in char[] fmt, const(double[2]) __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" quad handle (avg of cubic handles): %s",
(local variable) const(double[2]) h
h
);
double
(local variable) double fitMax
fitMax
= 0;
foreach (
(local variable) int i
i
; 0 .. 11)
{ const
(local variable) const(double) t
t
=
(local variable) int i
i
/ 10.0;
const
(local variable) const(double) d
d
=
double manim_bezier_eval.dist(in double[2] a, in double[2] b) pure nothrow @nogc @safe
dist
(
double[2] manim_bezier_eval.cubic(in double[2] p0, in double[2] p1, in double[2] p2, in double[2] p3, double t) pure nothrow @nogc @safe

de Casteljau for a cubic (4 control points).

cubic
(
(local variable) const(double[2]) g0
g0
,
(local variable) const(double[2]) g1
g1
,
(local variable) const(double[2]) g2
g2
,
(local variable) const(double[2]) g3
g3
,
(local variable) const(double) t
t
),
double[2] manim_bezier_eval.quad(in double[2] p0, in double[2] p1, in double[2] p2, double t) pure nothrow @nogc @safe

de Casteljau for a quadratic (3 control points).

quad
(
(local variable) const(double[2]) g0
g0
,
(local variable) const(double[2]) h
h
,
(local variable) const(double[2]) g3
g3
,
(local variable) const(double) t
t
));
if (
(local variable) const(double) d
d
>
(local variable) double fitMax
fitMax
)
(local variable) double fitMax
fitMax
=
(local variable) const(double) d
d
;
}
void std.stdio.writefln!(char, double)(in char[] fmt, double __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" max approximation error: %.4f (the per-curve cost a quadratic-only",
(local variable) double fitMax
fitMax
);
void std.stdio.writefln!char(in char[] fmt) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" store pays; a cubic store lowers to quads only on the GPU backend)");
void std.stdio.writefln!(char, double, double)(in char[] fmt, double __param_1, double __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("\n arc length: quadratic %.4f, inflected cubic %.4f",
double manim_bezier_eval.arcLength(scope double[2] delegate(double) @safe f, ulong n = 256LU) @safe

Polyline arc-length estimate over n samples.

arcLength
((double
(parameter) double t
t
) @safe =>
double[2] manim_bezier_eval.quad(in double[2] p0, in double[2] p1, in double[2] p2, double t) pure nothrow @nogc @safe

de Casteljau for a quadratic (3 control points).

quad
(
(local variable) const(double[2]) q0
q0
,
(local variable) const(double[2]) q1
q1
,
(local variable) const(double[2]) q2
q2
,
(parameter) double t
t
)),
double manim_bezier_eval.arcLength(scope double[2] delegate(double) @safe f, ulong n = 256LU) @safe

Polyline arc-length estimate over n samples.

arcLength
((double
(parameter) double t
t
) @safe =>
double[2] manim_bezier_eval.cubic(in double[2] p0, in double[2] p1, in double[2] p2, in double[2] p3, double t) pure nothrow @nogc @safe

de Casteljau for a cubic (4 control points).

cubic
(
(local variable) const(double[2]) g0
g0
,
(local variable) const(double[2]) g1
g1
,
(local variable) const(double[2]) g2
g2
,
(local variable) const(double[2]) g3
g3
,
(parameter) double t
t
)));
return 0; }