Uniform cubic spline interpolation & inversion.
This crate supports the following types of splines:
- B-spline
- Bezier
- Catmull-Rom
- Hermite
- Linear
- Power
Curve widget with a 1D Catmull-Rom spline with non-uniform knot
spacing and knot multiplicity using this crate for interpolation
(drawn using tiny-skia
).
The crate uses generics to allow interpolation of any type for which certain traits are defined.
I.e. you can use this crate to interpolate splines in 1D, 2D, 3D, etc.
[dependencies]
uniform-cubic-splines = { version = "0.3" }
Using a combination of spline_inverse()
and spline()
it is
possible to compute a full spline-with-nonuniform-abscissæ:
use uniform_cubic_splines::{
basis::CatmullRom, spline_inverse, spline,
};
// We want to evaluate the spline at knot value 0.3.
let x = 0.3;
// The first and last points are never interpolated.
let knot_spacing = [0.0, 0.0, 0.1, 0.3, 1.0, 1.0];
let knots = [0.0, 0.0, 1.3, 4.2, 3.2, 3.2];
let v = spline_inverse::<CatmullRom, _>(x, &knot_spacing).unwrap();
let y = spline::<CatmullRom, _, _>(v, &knots);
assert!(y - 4.2 < 1e-6);
monotonic_check
-- Thespline_inverse()
/spline_inverse_with()
code will check if the knot vector is monotonic (enabled by default).
This crate supports f16
and f128
types on a nightly
toolchain if you use this repository as an overlay in your Cargo.toml
.
[patch.crates-io]
uniform-cubic-splines = {
git = "https://github.com/virtualritz/uniform-cubic-splines.git"
}
This will be supported without an overlay once this PR on
num-traits
is merged and published.
The code is a Rust port of the implementation found in the Open Shading Language C++ source.
If you come from a background of computer graphics/shading languages used in offline rendering this crate should feel like home.
The code was originally a faithful but idiomatic Rust port of the C++ source. It was optimized quite a bit afterwards. The optimized code is in version 0.3.3
of the crate and after.
For perspective, the current version's spline()
function is about twice as fast and the spline_inverse()
up to 3.5 times as fast as the original, faithful Rust port.
Points | spline() |
spline_inverse() |
---|---|---|
10 | 15.5 ns | 95 ns |
50 | 16.4 ns | 181.2 ns |
100 | 16.8 ns | 277.7 ns |
500 | 20.6 ns | 1.275 µs |
These were taken on Ubuntu 25.04 with rustc 1.89.0-nightly
and target_cpu = "native"
on an AMD Ryzen 7 6800H laptop.