1use crate::Coord;
2
3pub trait Lerp {
4 #[must_use]
15 fn lerp(self, end: Self, percent: f32) -> Self;
16
17 #[must_use]
28 fn inv_lerp(self, end: Self, point: Self) -> f32;
29}
30
31#[inline]
45#[must_use]
46pub fn flerp(start: f32, end: f32, percent: f32) -> f32 {
47 start + ((end - start) * percent)
48}
49
50#[inline]
59#[must_use]
60pub fn inv_flerp(start: f32, end: f32, point: f32) -> f32 {
61 if point == start {
62 return 0.0;
63 }
64 if point == end {
65 return 1.0;
66 }
67 (point - start) / (end - start)
68}
69
70macro_rules! impl_lerp {
71 ($num_type: ty) => {
72 impl Lerp for $num_type {
73 #[inline]
74 fn lerp(self, end: $num_type, percent: f32) -> $num_type {
75 let start = self as f32;
76 let end = end as f32;
77 flerp(start, end, percent).round() as $num_type
78 }
79
80 #[inline]
81 fn inv_lerp(self, end: $num_type, point: $num_type) -> f32 {
82 let start = self as f32;
83 let end = end as f32;
84 let point = point as f32;
85 inv_flerp(start, end, point)
86 }
87 }
88 };
89}
90
91impl_lerp!(u8);
92impl_lerp!(i8);
93impl_lerp!(u16);
94impl_lerp!(i16);
95impl_lerp!(u32);
96impl_lerp!(i32);
97impl_lerp!(u64);
98impl_lerp!(i64);
99impl_lerp!(u128);
100impl_lerp!(i128);
101impl_lerp!(usize);
102impl_lerp!(isize);
103
104impl Lerp for Coord {
105 #[inline]
106 fn lerp(self, end: Coord, percent: f32) -> Coord {
107 Coord {
108 x: self.x.lerp(end.x, percent),
109 y: self.y.lerp(end.y, percent),
110 }
111 }
112
113 #[inline]
114 fn inv_lerp(self, end: Coord, point: Coord) -> f32 {
115 (self.x.inv_lerp(end.x, point.x) + self.y.inv_lerp(end.y, point.y)) / 2.0
116 }
117}
118
119#[cfg(test)]
120mod test {
121 use super::*;
122
123 #[test]
124 fn isize_simple() {
125 assert_eq!(0_isize.lerp(10, 0.), 0);
126 assert_eq!(0_isize.lerp(10, 0.5), 5);
127 assert_eq!(0_isize.lerp(10, 1.), 10);
128 assert_eq!(0_isize.lerp(10, 0.2), 2);
129
130 assert_eq!(5_isize.lerp(10, 0.), 5);
131 assert_eq!(5_isize.lerp(10, 1.), 10);
132
133 assert_eq!(785_isize.lerp(787, 0.), 785);
134 assert_eq!(785_isize.lerp(787, 0.5), 786);
135 assert_eq!(785_isize.lerp(787, 1.), 787);
136
137 assert_eq!(21_isize.lerp(21, 0.), 21);
138 assert_eq!(21_isize.lerp(21, 0.5), 21);
139 assert_eq!(21_isize.lerp(21, 1.), 21);
140
141 assert_eq!(10_isize.lerp(1, 1.), 1);
142 assert_eq!(10_isize.lerp(1, 0.5), 6);
143 assert_eq!(10_isize.lerp(1, 0.), 10);
144
145 assert_eq!((-5_isize).lerp(5, 1.), 5);
146 assert_eq!((-5_isize).lerp(5, 0.5), 0);
147 assert_eq!((-5_isize).lerp(5, 0.), -5);
148
149 assert_eq!(5_isize.lerp(-5, 1.), -5);
150 assert_eq!(5_isize.lerp(-5, 0.5), 0);
151 assert_eq!(5_isize.lerp(-5, 0.), 5);
152
153 assert_eq!(0_isize.inv_lerp(10, 0), 0.);
154 assert_eq!(0_isize.inv_lerp(10, 5), 0.5);
155 assert_eq!(0_isize.inv_lerp(10, 10), 1.);
156 assert_eq!(0_isize.inv_lerp(10, 2), 0.2);
157
158 assert_eq!(5_isize.inv_lerp(10, 5), 0.);
159 assert_eq!(5_isize.inv_lerp(10, 10), 1.);
160
161 assert_eq!(785_isize.inv_lerp(787, 785), 0.);
162 assert_eq!(785_isize.inv_lerp(787, 786), 0.5);
163 assert_eq!(785_isize.inv_lerp(787, 787), 1.);
164
165 assert_eq!(21_isize.inv_lerp(21, 21), 0.);
166
167 assert_eq!(10_isize.inv_lerp(1, 1), 1.);
168 assert_eq!(10_isize.inv_lerp(1, 6), 0.44444445);
169 assert_eq!(10_isize.inv_lerp(1, 10), 0.);
170
171 assert_eq!((-5_isize).inv_lerp(5, 5), 1.);
172 assert_eq!((-5_isize).inv_lerp(5, 0), 0.5);
173 assert_eq!((-5_isize).inv_lerp(5, -5), 0.);
174
175 assert_eq!(5_isize.inv_lerp(-5, -5), 1.);
176 assert_eq!(5_isize.inv_lerp(-5, 0), 0.5);
177 assert_eq!(5_isize.inv_lerp(-5, 5), 0.);
178 }
179
180 #[test]
181 fn point_simple() {
182 let start1 = Coord { x: 0, y: 0 };
183 let end1 = Coord { x: 10, y: 10 };
184
185 let start2 = Coord { x: -1, y: -1 };
186 let end2 = Coord { x: 1, y: 1 };
187
188 let start3 = Coord { x: 1, y: -1 };
189 let end3 = Coord { x: -1, y: 1 };
190
191 assert_eq!(start1.lerp(end1, 0.), Coord { x: 0, y: 0 });
192 assert_eq!(start1.lerp(end1, 0.5), Coord { x: 5, y: 5 });
193 assert_eq!(start1.lerp(end1, 1.), Coord { x: 10, y: 10 });
194
195 assert_eq!(end1.lerp(start1, 0.), Coord { x: 10, y: 10 });
196 assert_eq!(end1.lerp(start1, 0.5), Coord { x: 5, y: 5 });
197 assert_eq!(end1.lerp(start1, 1.), Coord { x: 0, y: 0 });
198
199 assert_eq!(start2.lerp(end2, 0.), Coord { x: -1, y: -1 });
200 assert_eq!(start2.lerp(end2, 0.5), Coord { x: 0, y: 0 });
201 assert_eq!(start2.lerp(end2, 1.), Coord { x: 1, y: 1 });
202
203 assert_eq!(end2.lerp(start2, 0.), Coord { x: 1, y: 1 });
204 assert_eq!(end2.lerp(start2, 0.5), Coord { x: 0, y: 0 });
205 assert_eq!(end2.lerp(start2, 1.), Coord { x: -1, y: -1 });
206
207 assert_eq!(start3.lerp(end3, 0.), Coord { x: 1, y: -1 });
208 assert_eq!(start3.lerp(end3, 0.5), Coord { x: 0, y: 0 });
209 assert_eq!(start3.lerp(end3, 1.), Coord { x: -1, y: 1 });
210
211 assert_eq!(end3.lerp(start3, 0.), Coord { x: -1, y: 1 });
212 assert_eq!(end3.lerp(start3, 0.5), Coord { x: 0, y: 0 });
213 assert_eq!(end3.lerp(start3, 1.), Coord { x: 1, y: -1 });
214
215 assert_eq!(start1.lerp(end1, 2.), Coord { x: 20, y: 20 });
216 assert_eq!(start1.lerp(end1, -1.), Coord { x: -10, y: -10 });
217
218 assert_eq!(start1.inv_lerp(end1, Coord { x: 0, y: 0 }), 0.);
219 assert_eq!(start1.inv_lerp(end1, Coord { x: 5, y: 5 }), 0.5);
220 assert_eq!(start1.inv_lerp(end1, Coord { x: 10, y: 10 }), 1.);
221
222 assert_eq!(end1.inv_lerp(start1, Coord { x: 10, y: 10 }), 0.);
223 assert_eq!(end1.inv_lerp(start1, Coord { x: 5, y: 5 }), 0.5);
224 assert_eq!(end1.inv_lerp(start1, Coord { x: 0, y: 0 }), 1.);
225
226 assert_eq!(start2.inv_lerp(end2, Coord { x: -1, y: -1 }), 0.);
227 assert_eq!(start2.inv_lerp(end2, Coord { x: 0, y: 0 }), 0.5);
228 assert_eq!(start2.inv_lerp(end2, Coord { x: 1, y: 1 }), 1.);
229
230 assert_eq!(end2.inv_lerp(start2, Coord { x: 1, y: 1 }), 0.);
231 assert_eq!(end2.inv_lerp(start2, Coord { x: 0, y: 0 }), 0.5);
232 assert_eq!(end2.inv_lerp(start2, Coord { x: -1, y: -1 }), 1.);
233
234 assert_eq!(start3.inv_lerp(end3, Coord { x: 1, y: -1 }), 0.);
235 assert_eq!(start3.inv_lerp(end3, Coord { x: 0, y: 0 }), 0.5);
236 assert_eq!(start3.inv_lerp(end3, Coord { x: -1, y: 1 }), 1.);
237
238 assert_eq!(end3.inv_lerp(start3, Coord { x: -1, y: 1 }), 0.);
239 assert_eq!(end3.inv_lerp(start3, Coord { x: 0, y: 0 }), 0.5);
240 assert_eq!(end3.inv_lerp(start3, Coord { x: 1, y: -1 }), 1.);
241
242 assert_eq!(start1.inv_lerp(end1, Coord { x: 20, y: 20 }), 2.);
243 assert_eq!(start1.inv_lerp(end1, Coord { x: -10, y: -10 }), -1.);
244 }
245}