1pub trait Interpolator: Sized + Copy + PartialOrd {
35 fn normalize(self, start: Self, end: Self) -> Self;
37}
38
39macro_rules! impl_Interpolator {
40 ($t:ty) => {
41 impl Interpolator for $t {
42 fn normalize(self, start: Self, end: Self) -> Self {
43 (self - start) / (end - start)
44 }
45 }
46 };
47}
48
49impl_Interpolator!(f32);
50impl_Interpolator!(f64);
51
52pub trait Interpolate<T>: Sized + Copy {
56 fn step(t: T, threshold: T, a: Self, b: Self) -> Self;
58
59 fn lerp(t: T, a: Self, b: Self) -> Self;
61
62 fn cosine(t: T, a: Self, b: Self) -> Self;
64
65 fn cubic_hermite(t: T, x: (T, Self), a: (T, Self), b: (T, Self), y: (T, Self)) -> Self;
67
68 fn quadratic_bezier(t: T, a: Self, u: Self, b: Self) -> Self;
72
73 fn cubic_bezier(t: T, a: Self, u: Self, v: Self, b: Self) -> Self;
78
79 fn cubic_bezier_mirrored(t: T, a: Self, u: Self, v: Self, b: Self) -> Self;
85}
86
87#[macro_export]
88macro_rules! impl_Interpolate {
89 ($t:ty, $v:ty, $pi:expr) => {
90 #[cfg(any(feature = "std", feature = "num-traits"))]
92 impl $crate::interpolate::Interpolate<$t> for $v {
93 fn step(t: $t, threshold: $t, a: Self, b: Self) -> Self {
94 if t < threshold { a } else { b }
95 }
96
97 fn cosine(t: $t, a: Self, b: Self) -> Self {
98 #[cfg(feature = "std")]
99 let cos_nt = (1. - (t * $pi).cos()) * 0.5;
100 #[cfg(all(not(feature = "std"), feature = "num-traits"))]
101 let cos_nt = (1. - num_traits::Float::cos(t * $pi)) * 0.5;
102 <Self as $crate::interpolate::Interpolate<$t>>::lerp(cos_nt, a, b)
103 }
104
105 fn lerp(t: $t, a: Self, b: Self) -> Self {
106 a * (1. - t) + b * t
107 }
108
109 fn cubic_hermite(t: $t, x: ($t, Self), a: ($t, Self), b: ($t, Self), y: ($t, Self)) -> Self {
110 let two_t = t * 2.;
112 let three_t = t * 3.;
113 let t2 = t * t;
114 let t3 = t2 * t;
115 let two_t3 = t2 * two_t;
116 let two_t2 = t * two_t;
117 let three_t2 = t * three_t;
118
119 let m0 = (b.1 - x.1) / (b.0 - x.0) * (b.0 - a.0);
121 let m1 = (y.1 - a.1) / (y.0 - a.0) * (b.0 - a.0);
122
123 a.1 * (two_t3 - three_t2 + 1.)
124 + m0 * (t3 - two_t2 + t)
125 + b.1 * (three_t2 - two_t3)
126 + m1 * (t3 - t2)
127 }
128
129 fn quadratic_bezier(t: $t, a: Self, u: Self, b: Self) -> Self {
130 let one_t = 1. - t;
131 let one_t2 = one_t * one_t;
132
133 u + (a - u) * one_t2 + (b - u) * t * t
134 }
135
136 fn cubic_bezier(t: $t, a: Self, u: Self, v: Self, b: Self) -> Self {
137 let one_t = 1. - t;
138 let one_t2 = one_t * one_t;
139 let one_t3 = one_t2 * one_t;
140 let t2 = t * t;
141
142 a * one_t3 + (u * one_t2 * t + v * one_t * t2) * 3. + b * t2 * t
143 }
144
145 fn cubic_bezier_mirrored(t: $t, a: Self, u: Self, v: Self, b: Self) -> Self {
146 <Self as $crate::interpolate::Interpolate<$t>>::cubic_bezier(t, a, u, b + b - v, b)
147 }
148 }
149 };
150}
151
152#[macro_export]
153macro_rules! impl_InterpolateT {
154 ($t:ty, $v:ty, $pi:expr) => {
155 #[cfg(any(feature = "std", feature = "num-traits"))]
157 impl $crate::interpolate::Interpolate<$t> for $v {
158 fn step(t: $t, threshold: $t, a: Self, b: Self) -> Self {
159 if t < threshold { a } else { b }
160 }
161
162 fn cosine(t: $t, a: Self, b: Self) -> Self {
163 #[cfg(feature = "std")]
164 let cos_nt = (1. - (t * $pi).cos()) * 0.5;
165 #[cfg(all(not(feature = "std"), feature = "num-traits"))]
166 let cos_nt = (1. - num_traits::Float::cos(t * $pi)) * 0.5;
167 <Self as $crate::interpolate::Interpolate<$t>>::lerp(cos_nt, a, b)
168 }
169
170 fn lerp(t: $t, a: Self, b: Self) -> Self {
171 let t = Self::from(t);
172 a * (1. - t) + b * t
173 }
174
175 fn cubic_hermite(t: $t, x: ($t, Self), a: ($t, Self), b: ($t, Self), y: ($t, Self)) -> Self {
176 let t = Self::from(t);
178 let two_t = t * 2.;
179 let three_t = t * 3.;
180 let t2 = t * t;
181 let t3 = t2 * t;
182 let two_t3 = t2 * two_t;
183 let two_t2 = t * two_t;
184 let three_t2 = t * three_t;
185
186 let m0 = (b.1 - x.1) / (Self::from(b.0 - x.0)) * (Self::from(b.0 - a.0));
188 let m1 = (y.1 - a.1) / (Self::from(y.0 - a.0)) * (Self::from(b.0 - a.0));
189
190 a.1 * (two_t3 - three_t2 + 1.)
191 + m0 * (t3 - two_t2 + t)
192 + b.1 * (three_t2 - two_t3)
193 + m1 * (t3 - t2)
194 }
195
196 fn quadratic_bezier(t: $t, a: Self, u: Self, b: Self) -> Self {
197 let t = Self::from(t);
198 let one_t = 1. - t;
199 let one_t2 = one_t * one_t;
200
201 u + (a - u) * one_t2 + (b - u) * t * t
202 }
203
204 fn cubic_bezier(t: $t, a: Self, u: Self, v: Self, b: Self) -> Self {
205 let t = Self::from(t);
206 let one_t = 1. - t;
207 let one_t2 = one_t * one_t;
208 let one_t3 = one_t2 * one_t;
209 let t2 = t * t;
210
211 a * one_t3 + (u * one_t2 * t + v * one_t * t2) * 3. + b * t2 * t
212 }
213
214 fn cubic_bezier_mirrored(t: $t, a: Self, u: Self, v: Self, b: Self) -> Self {
215 <Self as $crate::interpolate::Interpolate<$t>>::cubic_bezier(t, a, u, b + b - v, b)
216 }
217 }
218 };
219}
220
221impl_Interpolate!(f32, f32, core::f32::consts::PI);
222impl_Interpolate!(f64, f64, core::f64::consts::PI);
223impl_InterpolateT!(f32, f64, core::f32::consts::PI);