eazy_core/interpolation/polynomial/
smoothstep.rs

1//! The Smoothstep Interpolating Polynomial Curve.
2//!
3//! Smoothstep is a polynomial S-curve defined as `3t² - 2t³`.
4//! This module provides In, Out, and InOut variants derived mathematically:
5//!
6//! - **InOut** (standard): `3t² - 2t³` - symmetric S-curve
7//! - **In**: First half of InOut stretched to [0,1]: `t² * (3 - t) / 2`
8//! - **Out**: Mirror of In: `t * (3 - t²) / 2`
9
10use crate::easing::Curve;
11
12/// The [`InSmooth`] Curve (ease-in).
13///
14/// Derived from smoothstep InOut by taking the first half and stretching:
15/// `In(t) = 2 * InOut(t/2) = t² * (3 - t) / 2`
16///
17/// Starts slow, accelerates toward the end.
18///
19/// #### examples.
20///
21/// ```
22/// use eazy::Curve;
23/// use eazy::interpolation::polynomial::smoothstep::InSmooth;
24///
25/// let p = InSmooth.y(0.5);
26/// assert!((p - 0.3125).abs() < 0.0001);
27/// ```
28#[derive(Debug)]
29pub struct InSmooth;
30
31impl Curve for InSmooth {
32  #[inline(always)]
33  fn y(&self, p: f32) -> f32 {
34    let p = p.clamp(0.0, 1.0);
35    p * p * (3.0 - p) * 0.5
36  }
37}
38
39#[test]
40fn test_in_smooth() {
41  // In(0) = 0
42  assert_eq!(InSmooth.y(0.0), 0.0);
43  // In(1) = 1
44  assert_eq!(InSmooth.y(1.0), 1.0);
45  // In(0.5) = 0.3125 (ease-in: slower at start)
46  assert!((InSmooth.y(0.5) - 0.3125).abs() < 0.0001);
47}
48
49/// The [`OutSmooth`] Curve (ease-out).
50///
51/// Mirror of InSmooth: `Out(t) = 1 - In(1-t) = t * (3 - t²) / 2`
52///
53/// Starts fast, decelerates toward the end.
54///
55/// #### examples.
56///
57/// ```
58/// use eazy::Curve;
59/// use eazy::interpolation::polynomial::smoothstep::OutSmooth;
60///
61/// let p = OutSmooth.y(0.5);
62/// assert!((p - 0.6875).abs() < 0.0001);
63/// ```
64#[derive(Debug)]
65pub struct OutSmooth;
66
67impl Curve for OutSmooth {
68  #[inline(always)]
69  fn y(&self, p: f32) -> f32 {
70    let p = p.clamp(0.0, 1.0);
71    p * (3.0 - p * p) * 0.5
72  }
73}
74
75#[test]
76fn test_out_smooth() {
77  // Out(0) = 0
78  assert_eq!(OutSmooth.y(0.0), 0.0);
79  // Out(1) = 1
80  assert_eq!(OutSmooth.y(1.0), 1.0);
81  // Out(0.5) = 0.6875 (ease-out: faster at start)
82  assert!((OutSmooth.y(0.5) - 0.6875).abs() < 0.0001);
83}
84
85/// The [`InOutSmooth`] Curve (standard smoothstep).
86///
87/// The classic smoothstep S-curve: `3t² - 2t³`
88///
89/// Starts slow, speeds up in the middle, slows down at the end.
90///
91/// #### examples.
92///
93/// ```
94/// use eazy::Curve;
95/// use eazy::interpolation::polynomial::smoothstep::InOutSmooth;
96///
97/// let p = InOutSmooth.y(0.5);
98/// assert_eq!(p, 0.5);
99/// ```
100#[derive(Debug)]
101pub struct InOutSmooth;
102
103impl Curve for InOutSmooth {
104  #[inline(always)]
105  fn y(&self, p: f32) -> f32 {
106    let p = p.clamp(0.0, 1.0);
107    p * p * (3.0 - 2.0 * p)
108  }
109}
110
111#[test]
112fn test_in_out_smooth() {
113  // InOut(0) = 0
114  assert_eq!(InOutSmooth.y(0.0), 0.0);
115  // InOut(0.5) = 0.5 (symmetric)
116  assert_eq!(InOutSmooth.y(0.5), 0.5);
117  // InOut(1) = 1
118  assert_eq!(InOutSmooth.y(1.0), 1.0);
119}
120
121/// The Non-linear Interpolation.
122///
123/// Interpolates smoothly between `min` and `max`. It will accelerated from the
124/// start and deccelerated toward the end with a cubic easing.
125///
126/// #### params.
127///
128/// |      |                            |
129/// |:-----|:---------------------------|
130/// | `p`  | The progress.              |
131/// | `x0` | The `min` start value.     |
132/// | `x1` | The `max` end value.       |
133///
134/// #### returns.
135///
136/// `f32` — The interpolated result between the two float values.
137///
138/// #### examples.
139///
140/// ```
141/// use eazy::interpolation::polynomial::smoothstep::smoothstep;
142///
143/// let p = smoothstep(0.25, 0.0, 1.0);
144///
145/// assert_eq!(p, 0.15625);
146/// ```
147#[inline(always)]
148pub fn smoothstep(p: f32, x0: f32, x1: f32) -> f32 {
149  let mut p = (p - x0) / (x1 - x0);
150
151  p = p.clamp(0.0, 1.0);
152  p * p * (3.0 - 2.0 * p)
153}