1#[cfg(feature = "std")] use std::f32;
32#[cfg(not(feature = "std"))] use core::f32;
33#[cfg(not(feature = "std"))] use core::intrinsics::cosf32;
34#[cfg(feature = "std")] use std::f64;
35#[cfg(not(feature = "std"))] use core::f64;
36#[cfg(not(feature = "std"))] use core::intrinsics::cosf64;
37#[cfg(feature = "std")] use std::ops::{Add, Mul, Sub};
38#[cfg(not(feature = "std"))] use core::ops::{Add, Mul, Sub};
39
40pub trait Interpolate<T>: Sized + Copy {
49 fn lerp(a: Self, b: Self, t: T) -> Self;
51
52 fn cubic_hermite(_: (Self, T), a: (Self, T), b: (Self, T), _: (Self, T), t: T) -> Self {
58 Self::lerp(a.0, b.0, t)
59 }
60
61 fn quadratic_bezier(a: Self, u: Self, b: Self, t: T) -> Self;
63
64 fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: T) -> Self;
66}
67
68pub trait Additive:
72 Copy +
73 Add<Self, Output = Self> +
74 Sub<Self, Output = Self> {
75}
76
77impl<T> Additive for T
78where T: Copy +
79 Add<Self, Output = Self> +
80 Sub<Self, Output = Self> {
81}
82
83pub trait Linear<T>: Additive {
85 fn outer_mul(self, t: T) -> Self;
87
88 fn outer_div(self, t: T) -> Self;
90}
91
92macro_rules! impl_linear_simple {
93 ($t:ty) => {
94 impl Linear<$t> for $t {
95 fn outer_mul(self, t: $t) -> Self {
96 self * t
97 }
98
99 fn outer_div(self, t: $t) -> Self {
101 self / t
102 }
103 }
104 }
105}
106
107impl_linear_simple!(f32);
108impl_linear_simple!(f64);
109
110macro_rules! impl_linear_cast {
111 ($t:ty, $q:ty) => {
112 impl Linear<$t> for $q {
113 fn outer_mul(self, t: $t) -> Self {
114 self * t as $q
115 }
116
117 fn outer_div(self, t: $t) -> Self {
119 self / t as $q
120 }
121 }
122 }
123}
124
125impl_linear_cast!(f32, f64);
126impl_linear_cast!(f64, f32);
127
128pub trait One {
130 fn one() -> Self;
132}
133
134macro_rules! impl_one_float {
135 ($t:ty) => {
136 impl One for $t {
137 #[inline(always)]
138 fn one() -> Self {
139 1.
140 }
141 }
142 }
143}
144
145impl_one_float!(f32);
146impl_one_float!(f64);
147
148pub trait Trigo {
150 fn pi() -> Self;
152
153 fn cos(self) -> Self;
155}
156
157impl Trigo for f32 {
158 #[inline(always)]
159 fn pi() -> Self {
160 f32::consts::PI
161 }
162
163 #[inline(always)]
164 fn cos(self) -> Self {
165 #[cfg(feature = "std")]
166 {
167 self.cos()
168 }
169
170 #[cfg(not(feature = "std"))]
171 {
172 unsafe { cosf32(self) }
173 }
174 }
175}
176
177impl Trigo for f64 {
178 #[inline(always)]
179 fn pi() -> Self {
180 f64::consts::PI
181 }
182
183 #[inline(always)]
184 fn cos(self) -> Self {
185 #[cfg(feature = "std")]
186 {
187 self.cos()
188 }
189
190 #[cfg(not(feature = "std"))]
191 {
192 unsafe { cosf64(self) }
193 }
194 }
195}
196
197pub fn cubic_hermite_def<V, T>(x: (V, T), a: (V, T), b: (V, T), y: (V, T), t: T) -> V
201where V: Linear<T>,
202 T: Additive + Mul<T, Output = T> + One {
203 let one_t = T::one();
205 let two_t = one_t + one_t; let three_t = two_t + one_t; let t2 = t * t;
210 let t3 = t2 * t;
211 let two_t3 = t3 * two_t;
212 let three_t2 = t2 * three_t;
213
214 let m0 = (b.0 - x.0).outer_div(b.1 - x.1);
216 let m1 = (y.0 - a.0).outer_div(y.1 - a.1);
217
218 a.0.outer_mul(two_t3 - three_t2 + one_t) + m0.outer_mul(t3 - t2 * two_t + t) + b.0.outer_mul(three_t2 - two_t3) + m1.outer_mul(t3 - t2)
219}
220
221pub fn quadratic_bezier_def<V, T>(a: V, u: V, b: V, t: T) -> V
225where V: Linear<T>,
226 T: Additive + Mul<T, Output = T> + One {
227 let one_t = T::one() - t;
228 let one_t_2 = one_t * one_t;
229 u + (a - u).outer_mul(one_t_2) + (b - u).outer_mul(t * t)
230}
231
232pub fn cubic_bezier_def<V, T>(a: V, u: V, v: V, b: V, t: T) -> V
236where V: Linear<T>,
237 T: Additive + Mul<T, Output = T> + One {
238 let one_t = T::one() - t;
239 let one_t_2 = one_t * one_t;
240 let one_t_3 = one_t_2 * one_t;
241 let three = T::one() + T::one() + T::one();
242
243 let v_ = b + b - v;
245
246 a.outer_mul(one_t_3) + u.outer_mul(three * one_t_2 * t) + v_.outer_mul(three * one_t * t * t) + b.outer_mul(t * t * t)
247}
248
249macro_rules! impl_interpolate_simple {
250 ($t:ty) => {
251 impl Interpolate<$t> for $t {
252 fn lerp(a: Self, b: Self, t: $t) -> Self {
253 a * (1. - t) + b * t
254 }
255
256 fn cubic_hermite(x: (Self, $t), a: (Self, $t), b: (Self, $t), y: (Self, $t), t: $t) -> Self {
257 cubic_hermite_def(x, a, b, y, t)
258 }
259
260 fn quadratic_bezier(a: Self, u: Self, b: Self, t: $t) -> Self {
261 quadratic_bezier_def(a, u, b, t)
262 }
263
264 fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: $t) -> Self {
265 cubic_bezier_def(a, u, v, b, t)
266 }
267 }
268 }
269}
270
271impl_interpolate_simple!(f32);
272impl_interpolate_simple!(f64);
273
274macro_rules! impl_interpolate_via {
275 ($t:ty, $v:ty) => {
276 impl Interpolate<$t> for $v {
277 fn lerp(a: Self, b: Self, t: $t) -> Self {
278 a * (1. - t as $v) + b * t as $v
279 }
280
281 fn cubic_hermite((x, xt): (Self, $t), (a, at): (Self, $t), (b, bt): (Self, $t), (y, yt): (Self, $t), t: $t) -> Self {
282 cubic_hermite_def((x, xt as $v), (a, at as $v), (b, bt as $v), (y, yt as $v), t as $v)
283 }
284
285 fn quadratic_bezier(a: Self, u: Self, b: Self, t: $t) -> Self {
286 quadratic_bezier_def(a, u, b, t as $v)
287 }
288
289 fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: $t) -> Self {
290 cubic_bezier_def(a, u, v, b, t as $v)
291 }
292 }
293 }
294}
295
296impl_interpolate_via!(f32, f64);
297impl_interpolate_via!(f64, f32);