eazy_core/interpolation/polynomial/
quartic.rs

1//! Quartic Smoothstep (C1 continuity).
2//!
3//! From Inigo Quilez: https://iquilezles.org/articles/smoothsteps/
4//!
5//! Uses only even powers of x, which is useful when x represents
6//! distance (avoiding square roots in distance calculations).
7//!
8//! - **Quartic**: `x²(2-x²)` - the smoothstep function
9//! - **InvQuartic**: `sqrt(1-sqrt(1-x))` - the inverse function
10
11use crate::easing::Curve;
12
13use libm::sqrtf;
14
15/// Quartic Smoothstep: `x²(2-x²)`
16///
17/// C1 continuous smoothstep using only even powers.
18///
19/// #### examples.
20///
21/// ```
22/// use eazy::Curve;
23/// use eazy::interpolation::polynomial::quartic::Quartic;
24///
25/// let p = Quartic.y(0.5);
26/// assert!((p - 0.4375).abs() < 0.0001);
27/// ```
28#[derive(Debug)]
29pub struct Quartic;
30
31impl Curve for Quartic {
32  #[inline(always)]
33  fn y(&self, p: f32) -> f32 {
34    p * p * (2.0 - p * p)
35  }
36}
37
38#[test]
39fn test_quartic() {
40  // Quartic(0) = 0
41  assert_eq!(Quartic.y(0.0), 0.0);
42  // Quartic(1) = 1
43  assert_eq!(Quartic.y(1.0), 1.0);
44  // Quartic(0.5) = 0.25 * 1.75 = 0.4375
45  assert!((Quartic.y(0.5) - 0.4375).abs() < 0.0001);
46}
47
48/// Inverse Quartic Smoothstep: `sqrt(1-sqrt(1-x))`
49///
50/// Maps output values back to input values.
51/// `InvQuartic(Quartic(x)) = x`
52///
53/// #### examples.
54///
55/// ```
56/// use eazy::Curve;
57/// use eazy::interpolation::polynomial::quartic::{Quartic, InvQuartic};
58///
59/// let x = 0.3;
60/// let y = Quartic.y(x);
61/// let x_back = InvQuartic.y(y);
62/// assert!((x - x_back).abs() < 0.0001);
63/// ```
64#[derive(Debug)]
65pub struct InvQuartic;
66
67impl Curve for InvQuartic {
68  #[inline(always)]
69  fn y(&self, p: f32) -> f32 {
70    sqrtf(1.0 - sqrtf(1.0 - p))
71  }
72}
73
74#[test]
75fn test_inv_quartic() {
76  // InvQuartic(0) = 0
77  assert_eq!(InvQuartic.y(0.0), 0.0);
78  // InvQuartic(1) = 1
79  assert_eq!(InvQuartic.y(1.0), 1.0);
80  // Round-trip: InvQuartic(Quartic(0.3)) ≈ 0.3
81  let x = 0.3;
82  let round_trip = InvQuartic.y(Quartic.y(x));
83  assert!((x - round_trip).abs() < 0.0001);
84}