1use crate::{cubicf, inf_sup_cubicf, lerpf, Rect};
22use std::cmp::Ordering;
23use uuid::Uuid;
24
25fn stepf(p0: f32, p1: f32, t: f32) -> f32 {
26 if t.eq(&1.0) {
27 p1
28 } else {
29 p0
30 }
31}
32
33#[derive(Default, Clone, Debug, PartialEq)]
34pub enum CurveKeyKind {
35 #[default]
36 Constant,
37 Linear,
38 Cubic {
39 left_tangent: f32,
41 right_tangent: f32,
43 },
44}
45
46impl CurveKeyKind {
47 #[inline]
48 pub fn new_cubic(left_angle_radians: f32, right_angle_radians: f32) -> Self {
49 Self::Cubic {
50 left_tangent: left_angle_radians.tan(),
51 right_tangent: right_angle_radians.tan(),
52 }
53 }
54}
55
56#[derive(Clone, Default, Debug, PartialEq)]
57pub struct CurveKey {
58 pub id: Uuid,
59 pub location: f32,
60 pub value: f32,
61 pub kind: CurveKeyKind,
62}
63
64impl CurveKey {
65 #[inline]
66 pub fn new(location: f32, value: f32, kind: CurveKeyKind) -> Self {
67 Self {
68 id: Uuid::new_v4(),
69 location,
70 value,
71 kind,
72 }
73 }
74}
75
76fn short_path_angles(mut start: f32, mut end: f32) -> (f32, f32) {
77 if (end - start).abs() > std::f32::consts::PI {
78 if end > start {
79 start += std::f32::consts::TAU;
80 } else {
81 end += std::f32::consts::TAU;
82 }
83 }
84 (start, end)
85}
86
87fn interpolate(
88 left_value: f32,
89 left_kind: &CurveKeyKind,
90 right_value: f32,
91 right_kind: &CurveKeyKind,
92 t: f32,
93) -> f32 {
94 match (left_kind, right_kind) {
95 (CurveKeyKind::Constant, CurveKeyKind::Constant)
97 | (CurveKeyKind::Constant, CurveKeyKind::Linear)
98 | (CurveKeyKind::Constant, CurveKeyKind::Cubic { .. }) => stepf(left_value, right_value, t),
99
100 (CurveKeyKind::Linear, CurveKeyKind::Constant)
102 | (CurveKeyKind::Linear, CurveKeyKind::Linear)
103 | (CurveKeyKind::Linear, CurveKeyKind::Cubic { .. }) => lerpf(left_value, right_value, t),
104
105 (
107 CurveKeyKind::Cubic {
108 right_tangent: left_tangent,
109 ..
110 },
111 CurveKeyKind::Constant,
112 )
113 | (
114 CurveKeyKind::Cubic {
115 right_tangent: left_tangent,
116 ..
117 },
118 CurveKeyKind::Linear,
119 ) => cubicf(left_value, right_value, t, *left_tangent, 0.0),
120
121 (
123 CurveKeyKind::Cubic {
124 right_tangent: left_tangent,
125 ..
126 },
127 CurveKeyKind::Cubic {
128 left_tangent: right_tangent,
129 ..
130 },
131 ) => cubicf(left_value, right_value, t, *left_tangent, *right_tangent),
132 }
133}
134
135impl CurveKey {
136 #[inline]
137 pub fn location(&self) -> f32 {
138 self.location
139 }
140
141 #[inline]
142 pub fn interpolate(&self, other: &Self, t: f32) -> f32 {
143 interpolate(self.value, &self.kind, other.value, &other.kind, t)
144 }
145
146 #[inline]
147 pub fn interpolate_angles(&self, other: &Self, t: f32) -> f32 {
148 let (left_value, right_value) = short_path_angles(self.value, other.value);
149 interpolate(left_value, &self.kind, right_value, &other.kind, t)
150 }
151}
152
153#[derive(Clone, Debug, PartialEq)]
154pub struct Curve {
155 pub id: Uuid,
156 pub name: String,
157 pub keys: Vec<CurveKey>,
158}
159
160impl Default for Curve {
161 fn default() -> Self {
162 Self {
163 id: Uuid::new_v4(),
164 name: Default::default(),
165 keys: Default::default(),
166 }
167 }
168}
169
170fn sort_keys(keys: &mut [CurveKey]) {
171 keys.sort_by(|a, b| {
172 if a.location > b.location {
173 Ordering::Greater
174 } else if a.location < b.location {
175 Ordering::Less
176 } else {
177 Ordering::Equal
178 }
179 });
180}
181
182impl From<Vec<CurveKey>> for Curve {
183 fn from(mut keys: Vec<CurveKey>) -> Self {
184 sort_keys(&mut keys);
185 Self {
186 id: Uuid::new_v4(),
187 name: Default::default(),
188 keys,
189 }
190 }
191}
192
193impl Curve {
194 #[inline]
195 pub fn set_id(&mut self, id: Uuid) {
196 self.id = id;
197 }
198
199 #[inline]
200 pub fn id(&self) -> Uuid {
201 self.id
202 }
203
204 #[inline]
205 pub fn set_name<S: AsRef<str>>(&mut self, name: S) {
206 name.as_ref().clone_into(&mut self.name);
207 }
208
209 #[inline]
210 pub fn name(&self) -> &str {
211 &self.name
212 }
213
214 #[inline]
215 pub fn clear(&mut self) {
216 self.keys.clear()
217 }
218
219 #[inline]
220 pub fn is_empty(&self) -> bool {
221 self.keys.is_empty()
222 }
223
224 #[inline]
225 pub fn keys(&self) -> &[CurveKey] {
226 &self.keys
227 }
228
229 #[inline]
230 pub fn keys_values(&mut self) -> impl Iterator<Item = &mut f32> {
231 self.keys.iter_mut().map(|k| &mut k.value)
232 }
233
234 #[inline]
235 pub fn add_key(&mut self, new_key: CurveKey) {
236 let pos = self.keys.partition_point(|k| k.location < new_key.location);
237 self.keys.insert(pos, new_key);
238 }
239
240 #[inline]
241 pub fn move_key(&mut self, key_id: usize, location: f32) {
242 if let Some(key) = self.keys.get_mut(key_id) {
243 key.location = location;
244 sort_keys(&mut self.keys);
245 }
246 }
247
248 #[inline]
249 pub fn max_location(&self) -> f32 {
250 self.keys.last().map(|k| k.location).unwrap_or_default()
251 }
252
253 #[inline]
254 fn fetch_at<I>(&self, location: f32, interpolator: I) -> f32
255 where
256 I: FnOnce(&CurveKey, &CurveKey, f32) -> f32,
257 {
258 if let (Some(first), Some(last)) = (self.keys.first(), self.keys.last()) {
259 if location <= first.location {
260 first.value
261 } else if location >= last.location {
262 last.value
263 } else {
264 let pos = self.keys.partition_point(|k| k.location < location);
266 let left = self.keys.get(pos.saturating_sub(1)).unwrap();
267 let right = self.keys.get(pos).unwrap();
268 let t = (location - left.location) / (right.location - left.location);
269 interpolator(left, right, t)
270 }
271 } else {
272 0.0
273 }
274 }
275
276 #[inline]
277 pub fn value_at(&self, location: f32) -> f32 {
278 self.fetch_at(location, |a, b, t| a.interpolate(b, t))
279 }
280
281 #[inline]
282 pub fn angle_at(&self, location: f32) -> f32 {
283 self.fetch_at(location, |a, b, t| a.interpolate_angles(b, t))
284 }
285
286 pub fn bounds(&self) -> Rect<f32> {
287 if self.keys.is_empty() {
289 return Rect::new(0.0, 0.0, 0.0, 0.0);
290 }
291
292 if self.keys.len() == 1 {
293 let first = self.keys().first().unwrap();
294 return Rect::new(first.location, first.value, 0.0, 0.0);
295 }
296
297 let mut max_y = -f32::MAX;
299 let mut min_y = f32::MAX;
300 let mut max_x = -f32::MAX;
301 let mut min_x = f32::MAX;
302
303 let mut push = |x: f32, y: f32| {
304 if x > max_x {
305 max_x = x;
306 }
307 if x < min_x {
308 min_x = x;
309 }
310 if y > max_y {
311 max_y = y;
312 }
313 if y < min_y {
314 min_y = y;
315 }
316 };
317
318 for keys in self.keys.windows(2) {
319 let left = &keys[0];
320 let right = &keys[1];
321 match (&left.kind, &right.kind) {
322 (
324 CurveKeyKind::Cubic {
325 right_tangent: left_tangent,
326 ..
327 },
328 CurveKeyKind::Constant,
329 )
330 | (
331 CurveKeyKind::Cubic {
332 right_tangent: left_tangent,
333 ..
334 },
335 CurveKeyKind::Linear,
336 ) => {
337 let (y0, y1) = inf_sup_cubicf(left.value, right.value, *left_tangent, 0.0);
338 push(left.location, y0);
339 push(right.location, y1);
340 }
341
342 (
344 CurveKeyKind::Cubic {
345 right_tangent: left_tangent,
346 ..
347 },
348 CurveKeyKind::Cubic {
349 left_tangent: right_tangent,
350 ..
351 },
352 ) => {
353 let (y0, y1) =
354 inf_sup_cubicf(left.value, right.value, *left_tangent, *right_tangent);
355 push(left.location, y0);
356 push(right.location, y1);
357 }
358 _ => {
359 push(left.location, left.value);
360 push(right.location, right.value);
361 }
362 }
363 }
364
365 Rect::new(min_x, min_y, max_x - min_x, max_y - min_y)
366 }
367}
368
369#[cfg(test)]
370mod test {
371 use uuid::Uuid;
372
373 use crate::curve::{Curve, CurveKey, CurveKeyKind};
374
375 #[test]
376 fn test_curve_key_insertion_order() {
377 let mut curve = Curve::default();
378
379 curve.add_key(CurveKey::new(0.0, 0.0, CurveKeyKind::Constant));
381 curve.add_key(CurveKey::new(-1.0, 0.0, CurveKeyKind::Constant));
382 curve.add_key(CurveKey::new(3.0, 0.0, CurveKeyKind::Constant));
383 curve.add_key(CurveKey::new(2.0, 0.0, CurveKeyKind::Constant));
384 curve.add_key(CurveKey::new(-5.0, 0.0, CurveKeyKind::Constant));
385
386 assert_eq!(curve.keys[0].location, -5.0);
388 assert_eq!(curve.keys[1].location, -1.0);
389 assert_eq!(curve.keys[2].location, 0.0);
390 assert_eq!(curve.keys[3].location, 2.0);
391 assert_eq!(curve.keys[4].location, 3.0);
392 }
393
394 #[test]
395 fn test_curve() {
396 let mut curve = Curve::default();
397
398 assert_eq!(curve.value_at(0.0), 0.0);
400
401 curve.add_key(CurveKey::new(0.0, 1.0, CurveKeyKind::Linear));
402
403 assert_eq!(curve.value_at(-1.0), 1.0);
405 assert_eq!(curve.value_at(1.0), 1.0);
406 assert_eq!(curve.value_at(0.0), 1.0);
407
408 curve.add_key(CurveKey::new(1.0, 0.0, CurveKeyKind::Linear));
409
410 assert_eq!(curve.value_at(-1.0), 1.0);
412 assert_eq!(curve.value_at(2.0), 0.0);
413 assert_eq!(curve.value_at(0.5), 0.5);
414
415 curve.add_key(CurveKey::new(2.0, 1.0, CurveKeyKind::Linear));
417
418 assert!(curve.keys[0].location <= curve.keys[1].location);
420 assert!(curve.keys[1].location <= curve.keys[2].location);
421
422 assert_eq!(curve.value_at(-1.0), 1.0); assert_eq!(curve.value_at(3.0), 1.0); assert_eq!(curve.value_at(0.0), 1.0); assert_eq!(curve.value_at(2.0), 1.0); assert_eq!(curve.value_at(0.5), 0.5);
432
433 let id = Uuid::new_v4();
435 curve.set_id(id);
436 assert_eq!(curve.id(), id);
437
438 let name = "name";
440 curve.set_name(name);
441 assert_eq!(curve.name(), name);
442
443 assert!(!curve.is_empty());
445 curve.clear();
446 assert!(curve.is_empty());
447
448 let key = CurveKey::new(0.0, 5.0, CurveKeyKind::Constant);
450 let key2 = CurveKey::new(1.0, 10.0, CurveKeyKind::Linear);
451 curve.add_key(key.clone());
452 curve.add_key(key2.clone());
453 assert_eq!(curve.keys(), vec![key.clone(), key2.clone()]);
454
455 let mut values = [5.0, 10.0];
457 assert!(curve.keys_values().eq(values.iter_mut()));
458
459 assert_eq!(curve.max_location(), 1.0);
461
462 let mut curve2 = curve.clone();
464 let key3 = CurveKey::default();
465 curve2.add_key(key3.clone());
466 assert_eq!(curve2.keys(), vec![key3.clone(), key.clone(), key2.clone()]);
467 curve2.move_key(key3.id.get_version_num(), 20.0);
468 assert_eq!(
469 curve2.keys(),
470 vec![
471 key.clone(),
472 key2.clone(),
473 CurveKey {
474 location: 20.0,
475 ..Default::default()
476 }
477 ]
478 );
479 }
480
481 #[test]
482 fn test_curve_key_kind() {
483 assert_eq!(CurveKeyKind::default(), CurveKeyKind::Constant);
484 assert_eq!(
485 CurveKeyKind::new_cubic(0.0, 0.0),
486 CurveKeyKind::Cubic {
487 left_tangent: 0.0,
488 right_tangent: 0.0
489 }
490 );
491 }
492
493 #[test]
494 fn test_curve_key() {
495 assert_eq!(
496 CurveKey::default(),
497 CurveKey {
498 id: Uuid::default(),
499 location: 0.0,
500 value: 0.0,
501 kind: CurveKeyKind::Constant,
502 },
503 );
504
505 let key = CurveKey::new(0.0, 5.0, CurveKeyKind::Constant);
506 let key2 = CurveKey::new(1.0, 10.0, CurveKeyKind::Linear);
507 let key3 = CurveKey::new(2.0, 20.0, CurveKeyKind::new_cubic(0.0, 0.0));
508 let key4 = CurveKey::new(3.0, 30.0, CurveKeyKind::new_cubic(0.0, 0.0));
509
510 assert_eq!(key.location(), 0.0);
511
512 assert_eq!(key.interpolate(&key2, 1.0), 10.0);
514 assert_eq!(key.interpolate(&key2, 0.0), 5.0);
515 assert_eq!(key.interpolate(&key3, 1.0), 20.0);
516 assert_eq!(key.interpolate(&key3, 0.0), 5.0);
517
518 assert_eq!(key2.interpolate(&key, 1.0), 5.0);
520 assert_eq!(key2.interpolate(&key, 0.0), 10.0);
521 assert_eq!(key2.interpolate(&key3, 1.0), 20.0);
522 assert_eq!(key2.interpolate(&key3, 0.0), 10.0);
523
524 assert_eq!(key3.interpolate(&key, 1.0), 5.0);
526 assert_eq!(key3.interpolate(&key, 0.0), 20.0);
527 assert_eq!(key3.interpolate(&key2, 1.0), 10.0);
528 assert_eq!(key3.interpolate(&key2, 0.0), 20.0);
529
530 assert_eq!(key3.interpolate(&key4, 1.0), 30.0);
532 assert_eq!(key3.interpolate(&key4, 0.0), 20.0);
533 }
534
535 #[test]
536 fn test_curve_from_vec() {
537 let key = CurveKey::new(-1.0, -1.0, CurveKeyKind::Constant);
538 let key2 = CurveKey::new(0.0, 0.0, CurveKeyKind::Constant);
539 let key3 = CurveKey::new(1.0, 1.0, CurveKeyKind::Constant);
540 let key4 = key2.clone();
541 let curve = Curve::from(vec![key2.clone(), key3.clone(), key.clone(), key4.clone()]);
542 assert_eq!(curve.name(), "");
543 assert_eq!(curve.keys(), vec![key, key2, key4, key3,]);
544 }
545}