1use crate::int32::div_u64_by_u32;
11use core::mem::MaybeUninit;
12
13#[derive(Copy, Clone, Debug, Eq, PartialEq)]
19pub enum ClipTraversal {
20 PreviousToCurrent,
22 CurrentToNext,
24}
25
26#[inline(always)]
34pub fn crossing_fraction_q12_i32(first_distance: i32, second_distance: i32) -> i32 {
35 ratio_q12_i32(first_distance, first_distance.wrapping_sub(second_distance))
36}
37
38#[inline(always)]
47pub fn crossing_fraction_q16_i32(first_distance: i32, second_distance: i32) -> u32 {
48 let difference_positive = first_distance > second_distance;
51 if first_distance == second_distance {
52 return 1 << 16;
53 }
54 if (first_distance >= 0) != difference_positive {
55 return 0;
56 }
57 let numerator = first_distance.unsigned_abs();
58 let denominator = first_distance.abs_diff(second_distance);
59 let magnitude = if numerator < (1 << 16) {
60 (numerator << 16) / denominator
61 } else {
62 if (numerator >> 16) >= denominator {
66 return 1 << 16;
67 }
68 div_u64_by_u32(numerator >> 16, numerator << 16, denominator)
69 };
70 magnitude.min(1 << 16)
71}
72
73#[inline(always)]
80pub fn lerp_q16_i32_exact(first: i32, second: i32, fraction_q16: u32) -> i32 {
81 let delta = second.wrapping_sub(first);
82 debug_assert!(delta.unsigned_abs() < (1 << 23));
83 let high = (fraction_q16 >> 8) as i32;
84 let low = (fraction_q16 & 0xff) as i32;
85 first.wrapping_add(
89 (delta
90 .wrapping_mul(high)
91 .wrapping_add((delta.wrapping_mul(low)) >> 8))
92 >> 8,
93 )
94}
95
96#[inline(always)]
102pub fn lerp_q12_i32(first: i32, second: i32, fraction: i32) -> i32 {
103 let delta = second.wrapping_sub(first);
104 first.wrapping_add(delta.wrapping_mul(fraction) >> 12)
105}
106
107#[inline(always)]
110pub fn lerp_q12_i32_rounded(first: i32, second: i32, fraction: i32) -> i32 {
111 first.wrapping_add(
112 (second
113 .wrapping_sub(first)
114 .wrapping_mul(fraction)
115 .wrapping_add(1 << 11))
116 >> 12,
117 )
118}
119
120#[inline(always)]
122pub fn lerp_q12_i32_wide(first: i32, second: i32, fraction: i32) -> i32 {
123 let delta = second.wrapping_sub(first);
124 first
125 .wrapping_add((delta / 4096).wrapping_mul(fraction))
126 .wrapping_add(((delta % 4096).wrapping_mul(fraction)) >> 12)
127}
128
129#[inline(always)]
135pub fn ratio_q12_i32(numerator: i32, denominator: i32) -> i32 {
136 if denominator == 0 || (numerator < 0) != (denominator < 0) {
137 return 0;
138 }
139 let mut numerator = numerator.unsigned_abs();
140 let mut denominator = denominator.unsigned_abs();
141 while numerator > (i32::MAX as u32 >> 12) {
142 numerator = (numerator + 1) >> 1;
143 denominator = (denominator + 1) >> 1;
144 }
145 if denominator == 0 {
146 return 0;
147 }
148 ((numerator << 12) / denominator).min(4096) as i32
149}
150
151pub trait AttributedClipPlane<Vertex> {
157 type Distance: Copy;
159
160 fn distance(&self, source_index: usize, vertex: &Vertex) -> Self::Distance;
162
163 fn inside(&self, distance: Self::Distance) -> bool;
165
166 fn intersection(
168 &self,
169 first_index: usize,
170 first: &Vertex,
171 first_distance: Self::Distance,
172 second_index: usize,
173 second: &Vertex,
174 second_distance: Self::Distance,
175 ) -> Vertex;
176}
177
178#[derive(Clone, Copy, Debug, PartialEq, Eq)]
181pub struct ClipOverflow;
182
183impl core::fmt::Display for ClipOverflow {
184 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
185 f.write_str("clip output does not fit the destination")
186 }
187}
188
189#[inline(always)]
202pub fn clip_to_plane<Vertex: Copy, Plane: AttributedClipPlane<Vertex>>(
203 source: &[Vertex],
204 destination: &mut [Vertex],
205 plane: &Plane,
206 traversal: ClipTraversal,
207) -> Result<usize, ClipOverflow> {
208 unsafe {
213 clip_convex_plane_raw::<_, _, true>(
214 source,
215 destination.as_mut_ptr(),
216 destination.len(),
217 plane,
218 traversal,
219 )
220 }
221 .map_err(|_| ClipOverflow)
222}
223
224#[inline(always)]
234pub unsafe fn clip_to_plane_unchecked<Vertex: Copy, Plane: AttributedClipPlane<Vertex>>(
235 source: &[Vertex],
236 destination: &mut [Vertex],
237 plane: &Plane,
238 traversal: ClipTraversal,
239) -> usize {
240 match unsafe {
245 clip_convex_plane_raw::<_, _, false>(
246 source,
247 destination.as_mut_ptr(),
248 destination.len(),
249 plane,
250 traversal,
251 )
252 } {
253 Ok(written) | Err(written) => written,
254 }
255}
256
257#[deprecated(
268 note = "use the safe `clip_to_plane` (checked) or `clip_to_plane_unchecked` (proven capacity)"
269)]
270#[inline(always)]
271pub unsafe fn clip_convex_plane<
272 Vertex: Copy,
273 Plane: AttributedClipPlane<Vertex>,
274 const CHECK_CAPACITY: bool,
275>(
276 source: &[Vertex],
277 destination: &mut [Vertex],
278 plane: &Plane,
279 traversal: ClipTraversal,
280) -> usize {
281 match unsafe {
286 clip_convex_plane_raw::<_, _, CHECK_CAPACITY>(
287 source,
288 destination.as_mut_ptr(),
289 destination.len(),
290 plane,
291 traversal,
292 )
293 } {
294 Ok(written) | Err(written) => written,
295 }
296}
297
298#[inline(always)]
306pub fn clip_to_plane_uninit<Vertex: Copy, Plane: AttributedClipPlane<Vertex>>(
307 source: &[Vertex],
308 destination: &mut [MaybeUninit<Vertex>],
309 plane: &Plane,
310 traversal: ClipTraversal,
311) -> Result<usize, ClipOverflow> {
312 unsafe {
317 clip_convex_plane_raw::<_, _, true>(
318 source,
319 destination.as_mut_ptr().cast::<Vertex>(),
320 destination.len(),
321 plane,
322 traversal,
323 )
324 }
325 .map_err(|_| ClipOverflow)
326}
327
328#[inline(always)]
335pub unsafe fn clip_to_plane_uninit_unchecked<Vertex: Copy, Plane: AttributedClipPlane<Vertex>>(
336 source: &[Vertex],
337 destination: &mut [MaybeUninit<Vertex>],
338 plane: &Plane,
339 traversal: ClipTraversal,
340) -> usize {
341 match unsafe {
344 clip_convex_plane_raw::<_, _, false>(
345 source,
346 destination.as_mut_ptr().cast::<Vertex>(),
347 destination.len(),
348 plane,
349 traversal,
350 )
351 } {
352 Ok(written) | Err(written) => written,
353 }
354}
355
356#[deprecated(
363 note = "use the safe `clip_to_plane_uninit` (checked) or `clip_to_plane_uninit_unchecked` (proven capacity)"
364)]
365#[inline(always)]
366pub unsafe fn clip_convex_plane_uninit<
367 Vertex: Copy,
368 Plane: AttributedClipPlane<Vertex>,
369 const CHECK_CAPACITY: bool,
370>(
371 source: &[Vertex],
372 destination: &mut [MaybeUninit<Vertex>],
373 plane: &Plane,
374 traversal: ClipTraversal,
375) -> usize {
376 match unsafe {
382 clip_convex_plane_raw::<_, _, CHECK_CAPACITY>(
383 source,
384 destination.as_mut_ptr().cast::<Vertex>(),
385 destination.len(),
386 plane,
387 traversal,
388 )
389 } {
390 Ok(written) | Err(written) => written,
391 }
392}
393
394#[inline(always)]
398unsafe fn clip_convex_plane_raw<
399 Vertex: Copy,
400 Plane: AttributedClipPlane<Vertex>,
401 const CHECK_CAPACITY: bool,
402>(
403 source: &[Vertex],
404 destination: *mut Vertex,
405 destination_len: usize,
406 plane: &Plane,
407 traversal: ClipTraversal,
408) -> Result<usize, usize> {
409 if source.is_empty() {
410 return Ok(0);
411 }
412 if !CHECK_CAPACITY {
413 debug_assert!(destination_len >= source.len().saturating_add(1));
414 }
415
416 #[inline(always)]
417 unsafe fn emit<Vertex: Copy, const CHECK_CAPACITY: bool>(
418 destination: *mut Vertex,
419 destination_len: usize,
420 written: &mut usize,
421 vertex: Vertex,
422 ) -> bool {
423 if CHECK_CAPACITY && *written >= destination_len {
424 return false;
425 }
426 debug_assert!(*written < destination_len);
427 unsafe { destination.add(*written).write(vertex) };
432 *written += 1;
433 true
434 }
435
436 let mut written = 0usize;
437 match traversal {
438 ClipTraversal::PreviousToCurrent => {
439 let mut previous_index = source.len() - 1;
440 let mut previous = unsafe { *source.get_unchecked(previous_index) };
443 let mut previous_distance = plane.distance(previous_index, &previous);
444 let mut current_index = 0usize;
445 while current_index < source.len() {
446 let current = unsafe { *source.get_unchecked(current_index) };
448 let current_distance = plane.distance(current_index, ¤t);
449 let current_inside = plane.inside(current_distance);
450 if current_inside != plane.inside(previous_distance) {
451 let crossing = plane.intersection(
452 previous_index,
453 &previous,
454 previous_distance,
455 current_index,
456 ¤t,
457 current_distance,
458 );
459 if unsafe {
463 !emit::<Vertex, CHECK_CAPACITY>(
464 destination,
465 destination_len,
466 &mut written,
467 crossing,
468 )
469 } {
470 return Err(written);
471 }
472 }
473 if current_inside
474 && unsafe {
477 !emit::<Vertex, CHECK_CAPACITY>(
478 destination,
479 destination_len,
480 &mut written,
481 current,
482 )
483 }
484 {
485 return Err(written);
486 }
487 previous_index = current_index;
488 previous = current;
489 previous_distance = current_distance;
490 current_index += 1;
491 }
492 }
493 ClipTraversal::CurrentToNext => {
494 let mut current_index = 0usize;
495 while current_index < source.len() {
496 let next_index = if current_index + 1 == source.len() {
497 0
498 } else {
499 current_index + 1
500 };
501 let current = unsafe { *source.get_unchecked(current_index) };
503 let next = unsafe { *source.get_unchecked(next_index) };
506 let current_distance = plane.distance(current_index, ¤t);
507 let next_distance = plane.distance(next_index, &next);
508 let current_inside = plane.inside(current_distance);
509 if current_inside
510 && unsafe {
513 !emit::<Vertex, CHECK_CAPACITY>(
514 destination,
515 destination_len,
516 &mut written,
517 current,
518 )
519 }
520 {
521 return Err(written);
522 }
523 if current_inside != plane.inside(next_distance) {
524 let crossing = plane.intersection(
525 current_index,
526 ¤t,
527 current_distance,
528 next_index,
529 &next,
530 next_distance,
531 );
532 if unsafe {
536 !emit::<Vertex, CHECK_CAPACITY>(
537 destination,
538 destination_len,
539 &mut written,
540 crossing,
541 )
542 } {
543 return Err(written);
544 }
545 }
546 current_index += 1;
547 }
548 }
549 }
550 Ok(written)
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556
557 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
558 struct Vertex(i32, i32);
559
560 struct Plane<'a>(Option<&'a [i32]>);
561
562 impl AttributedClipPlane<Vertex> for Plane<'_> {
563 type Distance = i32;
564
565 fn distance(&self, index: usize, vertex: &Vertex) -> i32 {
566 self.0.map_or(vertex.0, |distances| distances[index])
567 }
568
569 fn inside(&self, distance: i32) -> bool {
570 distance >= 0
571 }
572
573 fn intersection(
574 &self,
575 _: usize,
576 first: &Vertex,
577 first_distance: i32,
578 _: usize,
579 second: &Vertex,
580 second_distance: i32,
581 ) -> Vertex {
582 Vertex(
583 0,
584 first.1
585 + (second.1 - first.1) * first_distance / (first_distance - second_distance),
586 )
587 }
588 }
589
590 fn clip<const CHECK: bool>(
591 source: &[Vertex],
592 traversal: ClipTraversal,
593 ) -> ([Vertex; 8], usize) {
594 let mut output = [Vertex::default(); 8];
595 assert!(2 * source.len() <= output.len());
596 let count = if CHECK {
597 clip_to_plane(source, &mut output, &Plane(None), traversal).expect("fits")
598 } else {
599 unsafe { clip_to_plane_unchecked(source, &mut output, &Plane(None), traversal) }
602 };
603 (output, count)
604 }
605
606 #[test]
607 fn traversal_preserves_each_historical_fan_start() {
608 let source = [Vertex(-2, 0), Vertex(2, 40), Vertex(2, 80)];
609 let (previous, previous_count) = clip::<true>(&source, ClipTraversal::PreviousToCurrent);
610 assert_eq!(previous_count, 4);
611 assert_eq!(
612 &previous[..previous_count],
613 &[Vertex(0, 40), Vertex(0, 20), source[1], source[2]]
614 );
615 let (current, current_count) = clip::<false>(&source, ClipTraversal::CurrentToNext);
616 assert_eq!(current_count, 4);
617 assert_eq!(
618 ¤t[..current_count],
619 &[Vertex(0, 20), source[1], source[2], Vertex(0, 40)]
620 );
621 }
622
623 #[test]
624 fn cached_distance_domain_is_authoritative() {
625 let source = [Vertex(100, 0), Vertex(100, 40), Vertex(100, 80)];
626 let mut output = [Vertex::default(); 4];
627 let count = clip_to_plane(
628 &source,
629 &mut output,
630 &Plane(Some(&[-2, 2, 2])),
631 ClipTraversal::CurrentToNext,
632 );
633 assert_eq!(count, Ok(4));
634 assert_eq!(output, [Vertex(0, 20), source[1], source[2], Vertex(0, 40)]);
635 }
636
637 #[test]
641 fn non_convex_input_overflows_len_plus_one_but_fits_twice_len() {
642 let zigzag = [Vertex(1, 0), Vertex(-1, 10), Vertex(1, 20), Vertex(-1, 30)];
643 for traversal in [
644 ClipTraversal::PreviousToCurrent,
645 ClipTraversal::CurrentToNext,
646 ] {
647 let mut tight = [Vertex::default(); 5];
648 assert_eq!(
649 clip_to_plane(&zigzag, &mut tight, &Plane(None), traversal),
650 Err(ClipOverflow)
651 );
652 let mut roomy = [Vertex::default(); 8];
653 assert_eq!(
654 clip_to_plane(&zigzag, &mut roomy, &Plane(None), traversal),
655 Ok(6)
656 );
657 let mut uninit = [MaybeUninit::<Vertex>::uninit(); 5];
658 assert_eq!(
659 clip_to_plane_uninit(&zigzag, &mut uninit, &Plane(None), traversal),
660 Err(ClipOverflow)
661 );
662 }
663 }
664
665 #[allow(deprecated)]
668 #[test]
669 fn deprecated_forwarders_keep_partial_counts() {
670 let zigzag = [Vertex(1, 0), Vertex(-1, 10), Vertex(1, 20), Vertex(-1, 30)];
671 let mut tight = [Vertex::default(); 5];
672 let count = unsafe {
674 clip_convex_plane::<_, _, true>(
675 &zigzag,
676 &mut tight,
677 &Plane(None),
678 ClipTraversal::PreviousToCurrent,
679 )
680 };
681 assert_eq!(count, 5);
682 }
683
684 #[test]
685 fn canonical_q12_crossing_is_direction_independent() {
686 let interpolate =
687 |mut first: i32, mut second: i32, mut first_distance: i32, mut second_distance: i32| {
688 if second < first {
689 core::mem::swap(&mut first, &mut second);
690 core::mem::swap(&mut first_distance, &mut second_distance);
691 }
692 lerp_q12_i32(
693 first,
694 second,
695 crossing_fraction_q12_i32(first_distance, second_distance),
696 )
697 };
698 assert_eq!(interpolate(10, 110, 7, -3), 79);
699 assert_eq!(interpolate(110, 10, -3, 7), 79);
700 }
701
702 #[test]
703 fn measured_numeric_policies_keep_their_rounding_contracts() {
704 let q12 = crossing_fraction_q12_i32(7, -3);
705 assert_eq!(lerp_q12_i32(10, 110, q12), 79);
706 assert_eq!(lerp_q12_i32_rounded(10, 110, q12), 80);
707
708 let q16 = crossing_fraction_q16_i32(7, -3);
709 assert_eq!(lerp_q16_i32_exact(10, 110, q16), 79);
710 }
711
712 #[test]
713 fn all_inside_and_all_outside_are_stable() {
714 let inside = [Vertex(1, 1), Vertex(2, 2), Vertex(3, 3)];
715 let outside = [Vertex(-1, 1), Vertex(-2, 2), Vertex(-3, 3)];
716 let (inside_output, inside_count) = clip::<true>(&inside, ClipTraversal::PreviousToCurrent);
717 assert_eq!(inside_count, inside.len());
718 assert_eq!(&inside_output[..inside_count], &inside);
719 let (_, outside_count) = clip::<true>(&outside, ClipTraversal::PreviousToCurrent);
720 assert_eq!(outside_count, 0);
721 }
722
723 fn crossing_fraction_q16_i64(first: i64, second: i64) -> i64 {
725 ((first << 16) / first.wrapping_sub(second)).clamp(0, 1 << 16)
726 }
727
728 fn lerp_q16_i64(first: i32, second: i32, fraction: i64) -> i32 {
729 (first as i64 + ((second.wrapping_sub(first) as i64).wrapping_mul(fraction) >> 16)) as i32
730 }
731
732 #[test]
733 #[cfg_attr(
734 miri,
735 ignore = "exhaustive sweep, minutes under Miri; make test runs it natively"
736 )]
737 fn q16_crossing_and_lerp_match_the_wide_oracles() {
738 let mut state = 0x9e37_79b9_7f4a_7c15u64;
739 let mut next = || {
740 state ^= state << 13;
741 state ^= state >> 7;
742 state ^= state << 17;
743 state
744 };
745 for iteration in 0..100_000u32 {
746 let span: i32 = if iteration % 3 == 0 {
747 i32::MAX
748 } else {
749 1 << 24
750 };
751 let first = (next() as i32) % span;
752 let second = (next() as i32) % span;
753 if first == second {
754 continue;
755 }
756 let expected = crossing_fraction_q16_i64(i64::from(first), i64::from(second));
757 let actual = crossing_fraction_q16_i32(first, second);
758 assert_eq!(i64::from(actual), expected, "first {first} second {second}");
759 let a = (next() as i32) % (1 << 22);
760 let b = (next() as i32) % (1 << 22);
761 assert_eq!(
762 lerp_q16_i32_exact(a, b, actual),
763 lerp_q16_i64(a, b, expected),
764 "lerp {a} {b} fraction {actual}"
765 );
766 }
767 }
768}