1use std::cmp::Ordering;
2
3use derive_more::{Deref, DerefMut};
4use glam::DVec3;
5use itertools::Itertools;
6
7use crate::anchor::Aabb;
8use crate::traits::*;
9use crate::utils::bezier::{get_subpath_closed_flag, trim_quad_bezier};
10use crate::utils::math::interpolate_usize;
11use crate::utils::{avg, resize_preserving_order_with_repeated_indices};
12
13fn bezier_aabb(p1: DVec3, p2: DVec3, p3: DVec3) -> [DVec3; 2] {
14 let mut min = p1.min(p3);
22 let mut max = p1.max(p3);
23
24 let denom = p1 - 2. * p2 + p3;
25 let numer = p1 - p2;
26
27 for i in 0..3 {
28 if denom[i].abs() > f64::EPSILON {
29 let t = numer[i] / denom[i];
30 if (0.0..=1.0).contains(&t) {
31 let val = (1. - t).powi(2) * p1[i] + 2. * t * (1. - t) * p2[i] + t.powi(2) * p3[i];
32 min[i] = min[i].min(val);
33 max[i] = max[i].max(val);
34 }
35 }
36 }
37
38 [min, max]
39}
40
41#[derive(Debug, Clone, PartialEq, Deref, DerefMut, ranim_macros::Interpolatable)]
55pub struct VPointVec(pub Vec<DVec3>);
56
57impl Aabb for VPointVec {
58 fn aabb(&self) -> [DVec3; 2] {
64 self.0
65 .windows(3)
66 .step_by(2)
67 .map(|w| bezier_aabb(w[0], w[1], w[2]))
68 .reduce(|[acc_min, acc_max], [min, max]| [acc_min.min(min), acc_max.max(max)])
69 .unwrap_or([DVec3::ZERO; 2])
70 }
71}
72
73impl AsRef<[DVec3]> for VPointVec {
74 fn as_ref(&self) -> &[DVec3] {
75 self.0.as_ref()
76 }
77}
78
79impl AsMut<[DVec3]> for VPointVec {
80 fn as_mut(&mut self) -> &mut [DVec3] {
81 self.0.as_mut()
82 }
83}
84
85impl transform::ShiftTransform for VPointVec {
86 fn shift(&mut self, offset: DVec3) -> &mut Self {
87 self.as_mut().shift(offset);
88 self
89 }
90}
91
92impl transform::RotateTransform for VPointVec {
93 fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
94 self.as_mut().rotate_on_axis(axis, angle);
95 self
96 }
97}
98
99impl transform::ScaleTransform for VPointVec {
100 fn scale(&mut self, scale: DVec3) -> &mut Self {
101 self.as_mut().scale(scale);
102 self
103 }
104}
105
106impl Alignable for VPointVec {
107 fn is_aligned(&self, other: &Self) -> bool {
108 self.len() == other.len()
109 }
110 fn align_with(&mut self, other: &mut Self) {
111 if self.is_empty() {
112 self.0 = vec![DVec3::ZERO; 3];
113 }
114 if self.len() > other.len() {
115 other.align_with(self);
116 return;
117 }
118
119 let into_closed_subpaths = |subpaths: Vec<Vec<DVec3>>| -> Vec<Vec<DVec3>> {
120 subpaths
121 .into_iter()
122 .map(|sp| {
123 if !get_subpath_closed_flag(&sp).map(|f| f.1).unwrap() {
125 let sp_len = sp.len();
126 let sp_iter = sp.into_iter();
127 sp_iter
128 .clone()
129 .take(sp_len - 1)
130 .chain(sp_iter.rev())
131 .collect::<Vec<_>>()
132 } else {
133 sp
134 }
135 })
136 .collect::<Vec<_>>()
137 };
138 let mut sps_self = into_closed_subpaths(self.get_subpaths());
139 let mut sps_other = into_closed_subpaths(other.get_subpaths());
140 let len = sps_self.len().max(sps_other.len());
141 let resize_subpaths = |sps: &mut Vec<Vec<DVec3>>| {
142 if sps.len() != len {
143 let (mut x, idxs) = resize_preserving_order_with_repeated_indices(sps, len);
144 for idx in idxs {
145 let center = avg(&x[idx]);
146 x[idx].fill(center);
147 }
148 *sps = x;
149 }
150 };
151 resize_subpaths(&mut sps_self);
152 resize_subpaths(&mut sps_other);
153
154 let points_to_bez_tuples = |points: &[DVec3]| -> Vec<[DVec3; 3]> {
155 points
156 .windows(3)
157 .step_by(2)
158 .map(|w| [w[0], w[1], w[2]])
159 .collect()
160 };
161 let align_points = |points: &[DVec3], len: usize| -> Vec<DVec3> {
162 let bez_tuples = points_to_bez_tuples(points);
163
164 let diff_len = (len - points.len()) / 2;
165 let mut lens = bez_tuples
167 .iter()
168 .map(|[a, b, c]| {
169 if (a - b).length_squared() < f64::EPSILON {
170 0.0
171 } else {
172 (c - a).length()
173 }
174 })
175 .collect::<Vec<_>>();
176 let mut ipc = vec![0usize; bez_tuples.len()];
177
178 for _ in 0..diff_len {
179 let idx = lens
181 .iter()
182 .position_max_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal))
183 .unwrap();
184 ipc[idx] += 1;
185 lens[idx] *= ipc[idx] as f64 / (ipc[idx] + 1) as f64;
186 }
187 let new_segs = bez_tuples
190 .into_iter()
191 .zip(ipc)
192 .map(|(bez, ipc)| {
193 let alphas = (0..ipc + 2)
195 .map(|i: usize| i as f64 / (ipc + 1) as f64)
196 .collect::<Vec<_>>();
197 let mut new_points = Vec::with_capacity((ipc + 1) * 2 + 1);
198 new_points.push(bez[0]);
199 alphas.iter().tuple_windows().for_each(|(a1, a2)| {
201 let partial = trim_quad_bezier(&bez, *a1, *a2);
202 new_points.extend(partial[1..].iter())
204 });
205 new_points
207 })
208 .collect::<Vec<_>>();
209 let mut new_points = Vec::with_capacity(other.len());
210 new_points.extend_from_slice(&new_segs[0]);
211 for seg in new_segs.into_iter().skip(1) {
212 new_points.extend(&seg[1..]);
213 }
214 new_points
215 };
216
217 sps_self
218 .iter_mut()
219 .zip(sps_other.iter_mut())
220 .for_each(|(sp_a, sp_b)| {
221 let len = sp_a.len().max(sp_b.len());
223 if sp_a.len() != len {
224 *sp_a = align_points(sp_a, len)
225 }
226 if sp_b.len() != len {
227 *sp_b = align_points(sp_b, len)
228 }
229 });
230
231 let sps_to_points = |sps: Vec<Vec<DVec3>>| -> Vec<DVec3> {
232 let mut points = sps
233 .into_iter()
234 .flat_map(|sp| {
235 let last = *sp.last().unwrap();
236 sp.into_iter().chain(std::iter::once(last))
237 })
238 .collect::<Vec<_>>();
239 points.pop();
240 points
241 };
242
243 self.0 = sps_to_points(sps_self);
244 other.0 = sps_to_points(sps_other);
245 }
246}
247
248impl VPointVec {
253 pub fn get_subpaths(&self) -> Vec<Vec<DVec3>> {
255 let mut subpaths = Vec::new();
256
257 let mut subpath = Vec::new();
258 let mut iter_a = self.iter().step_by(2).peekable();
259 let mut iter_b = self.iter().skip(1).step_by(2).peekable();
260
261 loop {
262 match (iter_a.next(), iter_b.next()) {
263 (Some(a), Some(b)) => {
264 subpath.push(*a);
265 if a != b {
266 subpath.push(*b);
267 } else {
268 while let (Some(c), Some(d)) = (iter_a.peek(), iter_b.peek())
269 && b == *c
270 && c == d
271 {
272 subpath.extend([**c; 2]);
273 iter_a.next();
274 iter_b.next();
275 }
276 assert!(subpath.len() % 2 != 0);
277 subpaths.push(std::mem::take(&mut subpath));
278 }
279 }
280 (Some(a), None) => {
281 subpath.push(*a);
282 assert!(subpath.len() % 2 != 0);
283 subpaths.push(std::mem::take(&mut subpath));
284 break;
285 }
286 _ => unreachable!(),
287 }
288 }
289
290 subpaths
295 }
296 pub fn get_seg(&self, idx: usize) -> Option<&[DVec3; 3]> {
298 self.get(idx * 2..idx * 2 + 3)
299 .and_then(|seg| seg.try_into().ok())
300 }
301 pub fn get_closepath_flags(&self) -> Vec<bool> {
303 let len = self.len();
304 let mut flags = vec![false; len];
305
306 let mut i = 0;
308 while let Some((end_idx, is_closed)) = self.get(i..).and_then(get_subpath_closed_flag) {
309 let end_idx = i + end_idx + 2;
311 flags[i..=end_idx.clamp(i, len - 1)].fill(is_closed);
312 i = end_idx;
313 }
314 flags
317 }
318
319 pub fn put_start_and_end_on(&mut self, start: DVec3, end: DVec3) -> &mut Self {
321 let (cur_start, cur_end) = (
322 self.first().cloned().unwrap_or_default(),
323 self.last().cloned().unwrap_or_default(),
324 );
325 let cur_v = cur_end - cur_start;
326 if cur_v.length_squared() <= f64::EPSILON {
327 return self;
328 }
329
330 let v = end - start;
331 self.with_origin(cur_start, |x| {
332 x.scale(DVec3::splat(v.length() / cur_v.length()));
333 });
334 let rotate_angle = cur_v.angle_between(v);
335 let mut rotate_axis = cur_v.cross(v);
336 if rotate_axis.length_squared() <= f64::EPSILON {
337 rotate_axis = DVec3::Z;
338 }
339 rotate_axis = rotate_axis.normalize();
340 self.with_origin(cur_start, |x| {
341 x.rotate_on_axis(rotate_axis, rotate_angle);
342 });
343 self.shift(start - cur_start);
344
345 self
346 }
347
348 pub fn get_partial(&self, range: std::ops::Range<f64>) -> Self {
352 let max_anchor_idx = self.len() / 2;
353
354 let (start_index, start_residue) = interpolate_usize(0, max_anchor_idx, range.start);
355 let (end_index, end_residue) = interpolate_usize(0, max_anchor_idx, range.end);
356
357 if end_index - start_index == 0 {
358 let seg = *self.get_seg(start_index).unwrap();
359 let quad = trim_quad_bezier(&seg, start_residue, end_residue);
360 VPointVec(quad.into())
361 } else {
362 let mut partial = Vec::with_capacity((end_index - start_index + 1 + 2) * 2 + 1);
363
364 let seg = *self.get_seg(start_index).unwrap();
365 let start_part = trim_quad_bezier(&seg, start_residue, 1.0);
366 partial.extend_from_slice(&start_part);
367
368 if end_index - start_index > 1 {
372 let mid = self
373 .get((start_index + 1) * 2 + 1..=end_index * 2)
374 .unwrap()
375 .iter();
376 partial.extend(mid);
377 }
378
379 if end_residue != 0.0 {
380 let seg = *self.get_seg(end_index).unwrap();
381 let end_part = trim_quad_bezier(&seg, 0.0, end_residue);
382 partial.extend_from_slice(&end_part[1..]);
383 }
384
385 VPointVec(partial)
386 }
387 }
388}
389
390#[cfg(test)]
391mod test {
392 use std::f64::consts::PI;
393
394 use assert_float_eq::assert_float_absolute_eq;
395 use glam::{DVec3, dvec3};
396
397 use crate::{
398 components::vpoint::VPointVec,
399 traits::{Aabb, RotateTransform},
400 };
401
402 fn assert_dvec3_eq(a: DVec3, b: DVec3) {
403 assert_float_absolute_eq!(a.distance_squared(b), 0.0, 1e-10);
404 }
405
406 fn assert_points_eq(result: &[DVec3], expected: &[DVec3]) {
407 assert_eq!(result.len(), expected.len(), "length mismatch");
408 for (r, e) in result.iter().zip(expected) {
409 assert_dvec3_eq(*r, *e);
410 }
411 }
412
413 #[test]
414 fn test_get_subpath_two_subpaths() {
415 let points = VPointVec(vec![
417 DVec3::X,
418 DVec3::Y,
419 DVec3::Z,
420 DVec3::Z,
421 DVec3::NEG_X,
422 DVec3::NEG_Y,
423 DVec3::ZERO,
424 ]);
425 let sps = points.get_subpaths();
426 assert_eq!(sps.len(), 2);
427 assert_eq!(sps[0], vec![DVec3::X, DVec3::Y, DVec3::Z]);
428 assert_eq!(sps[1], vec![DVec3::NEG_X, DVec3::NEG_Y, DVec3::ZERO]);
429 }
430
431 #[test]
432 fn test_get_subpath_single() {
433 let points = VPointVec(vec![DVec3::X, DVec3::Y, DVec3::Z]);
434 let sps = points.get_subpaths();
435 assert_eq!(sps.len(), 1);
436 assert_eq!(sps[0], vec![DVec3::X, DVec3::Y, DVec3::Z]);
437 }
438
439 #[test]
440 fn test_get_subpath_degenerate_tail() {
441 let points = VPointVec(vec![DVec3::X, DVec3::Y, DVec3::Z, DVec3::Z, DVec3::Z]);
443 let sps = points.get_subpaths();
444 assert_eq!(sps.len(), 2);
445 assert_eq!(sps[0], vec![DVec3::X, DVec3::Y, DVec3::Z]);
446 assert_eq!(sps[1], vec![DVec3::Z]);
447 }
448
449 #[test]
450 fn test_get_partial_full_range() {
451 let points = VPointVec(vec![
452 dvec3(0.0, 0.0, 0.0),
453 dvec3(1.0, 1.0, 1.0),
454 dvec3(2.0, 2.0, 2.0),
455 dvec3(2.0, 2.0, 2.0),
456 dvec3(3.0, 3.0, 3.0),
457 dvec3(4.0, 4.0, 4.0),
458 dvec3(5.0, 5.0, 5.0),
459 ]);
460 let partial = points.get_partial(0.0..1.0);
461 assert_eq!(partial, points);
462 }
463
464 #[test]
465 fn test_get_partial_half() {
466 let points = VPointVec(vec![
467 dvec3(0.0, 0.0, 0.0),
468 dvec3(1.0, 1.0, 1.0),
469 dvec3(2.0, 2.0, 2.0),
470 dvec3(2.0, 2.0, 2.0),
471 dvec3(3.0, 3.0, 3.0),
472 dvec3(4.0, 4.0, 4.0),
473 dvec3(5.0, 5.0, 5.0),
474 ]);
475 let partial = points.get_partial(0.0..0.5);
476 assert_eq!(partial.len(), 5);
477 assert_dvec3_eq(partial[0], dvec3(0.0, 0.0, 0.0));
478 assert_dvec3_eq(*partial.last().unwrap(), dvec3(2.25, 2.25, 2.25));
479 }
480
481 #[test]
482 fn test_get_partial_single_segment() {
483 let points = VPointVec(vec![
484 dvec3(0.0, 0.0, 0.0),
485 dvec3(1.0, 1.0, 1.0),
486 dvec3(2.0, 2.0, 2.0),
487 dvec3(2.0, 2.0, 2.0),
488 dvec3(3.0, 3.0, 3.0),
489 dvec3(4.0, 4.0, 4.0),
490 dvec3(5.0, 5.0, 5.0),
491 ]);
492 let partial = points.get_partial(0.0..1.0 / 6.0);
494 assert_eq!(partial.len(), 3);
495 assert_dvec3_eq(partial[0], dvec3(0.0, 0.0, 0.0));
496 assert_dvec3_eq(partial[1], dvec3(0.5, 0.5, 0.5));
497 assert_dvec3_eq(partial[2], dvec3(1.0, 1.0, 1.0));
498 }
499
500 #[test]
501 fn test_get_partial_exact_segment_boundary() {
502 let points = VPointVec(vec![
503 dvec3(0.0, 0.0, 0.0),
504 dvec3(1.0, 1.0, 1.0),
505 dvec3(2.0, 2.0, 2.0),
506 dvec3(2.0, 2.0, 2.0),
507 dvec3(3.0, 3.0, 3.0),
508 dvec3(4.0, 4.0, 4.0),
509 dvec3(5.0, 5.0, 5.0),
510 ]);
511 let partial = points.get_partial(0.0..1.0 / 3.0);
513 assert_eq!(partial.len(), 3);
514 assert_dvec3_eq(partial[0], dvec3(0.0, 0.0, 0.0));
515 assert_dvec3_eq(partial[2], dvec3(2.0, 2.0, 2.0));
516 }
517
518 #[test]
519 fn test_rotate() {
520 let mut points = VPointVec(vec![
521 dvec3(0.0, 0.0, 0.0),
522 dvec3(1.0, 0.0, 0.0),
523 dvec3(2.0, 2.0, 0.0),
524 ]);
525 points.rotate_on_z(PI);
526 assert_points_eq(
527 &points.0,
528 &[
529 dvec3(0.0, 0.0, 0.0),
530 dvec3(-1.0, 0.0, 0.0),
531 dvec3(-2.0, -2.0, 0.0),
532 ],
533 );
534 }
535
536 #[test]
537 fn test_put_start_and_end_on() {
538 let mut points = VPointVec(vec![
539 dvec3(0.0, 0.0, 0.0),
540 dvec3(1.0, 0.0, 0.0),
541 dvec3(2.0, 2.0, 0.0),
542 ]);
543
544 points.put_start_and_end_on(dvec3(0.0, 0.0, 0.0), dvec3(4.0, 4.0, 0.0));
545 assert_points_eq(
546 &points.0,
547 &[
548 dvec3(0.0, 0.0, 0.0),
549 dvec3(2.0, 0.0, 0.0),
550 dvec3(4.0, 4.0, 0.0),
551 ],
552 );
553
554 points.put_start_and_end_on(dvec3(0.0, 0.0, 0.0), dvec3(-2.0, -2.0, 0.0));
555 assert_points_eq(
556 &points.0,
557 &[
558 dvec3(0.0, 0.0, 0.0),
559 dvec3(-1.0, 0.0, 0.0),
560 dvec3(-2.0, -2.0, 0.0),
561 ],
562 );
563 }
564
565 #[test]
566 fn test_aabb_single_segment_with_extremum() {
567 let points = VPointVec(vec![
569 dvec3(-2., 1., 0.),
570 dvec3(0., -1., 0.),
571 dvec3(2., 1., 0.),
572 ]);
573 let [min, max] = points.aabb();
574 assert_dvec3_eq(min, dvec3(-2., 0., 0.));
575 assert_dvec3_eq(max, dvec3(2., 1., 0.));
576 }
577
578 #[test]
579 fn test_aabb_straight_line() {
580 let points = VPointVec(vec![
582 dvec3(0., 0., 0.),
583 dvec3(1., 1., 0.),
584 dvec3(2., 2., 0.),
585 ]);
586 let [min, max] = points.aabb();
587 assert_dvec3_eq(min, dvec3(0., 0., 0.));
588 assert_dvec3_eq(max, dvec3(2., 2., 0.));
589 }
590
591 #[test]
592 fn test_aabb_multiple_segments() {
593 let points = VPointVec(vec![
595 dvec3(0., 0., 0.),
596 dvec3(1., 2., 0.),
597 dvec3(2., 0., 0.),
598 dvec3(3., -2., 0.),
599 dvec3(4., 0., 0.),
600 ]);
601 let [min, max] = points.aabb();
602 assert_dvec3_eq(min, dvec3(0., -1., 0.));
604 assert_dvec3_eq(max, dvec3(4., 1., 0.));
605 }
606
607 #[test]
608 fn test_aabb_multiple_subpaths() {
609 let points = VPointVec(vec![
611 dvec3(0., 0., 0.),
612 dvec3(0., 2., 0.),
613 dvec3(2., 0., 0.),
614 dvec3(2., 0., 0.), dvec3(3., 0., 0.),
616 dvec3(3., -2., 0.),
617 dvec3(5., 0., 0.),
618 ]);
619 let [min, max] = points.aabb();
620 assert_dvec3_eq(min, dvec3(0., -1., 0.));
621 assert_dvec3_eq(max, dvec3(5., 1., 0.));
622 }
623
624 #[test]
625 fn test_aabb_degenerate_single_point() {
626 let points = VPointVec(vec![DVec3::ONE; 3]);
627 let [min, max] = points.aabb();
628 assert_dvec3_eq(min, DVec3::ONE);
629 assert_dvec3_eq(max, DVec3::ONE);
630 }
631
632 #[test]
633 fn test_aabb_empty() {
634 let points = VPointVec(vec![]);
635 let [min, max] = points.aabb();
636 assert_dvec3_eq(min, DVec3::ZERO);
637 assert_dvec3_eq(max, DVec3::ZERO);
638 }
639}