1use std::fmt::Debug;
4
5use cgmath::num_traits::Float;
6use serde::{Deserialize, Serialize};
7
8#[derive(Copy, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
10pub struct Interval<T> {
11 pub min: T,
13 pub max: T,
15}
16
17impl<T> Interval<T> {
18 pub const fn new(min: T, max: T) -> Self {
20 Self { min, max }
21 }
22}
23
24impl<T: std::cmp::PartialOrd> Interval<T> {
25 pub fn overlaps(&self, other: &Self) -> bool {
27 self.max > other.min && other.max > self.min
28 }
29
30 pub fn contains(&self, value: T) -> bool {
32 value >= self.min && value <= self.max
33 }
34}
35
36impl<T: std::ops::Sub<T, Output = T> + Copy> Interval<T> {
37 pub fn length(&self) -> T {
39 self.max - self.min
40 }
41}
42
43impl<T: Copy> Interval<T> {
44 pub fn as_array(&self) -> [T; 2] {
46 [self.min, self.max]
47 }
48}
49
50impl<T: Float> Interval<T> {
51 pub fn disc(centre: T, radius: T) -> Self {
53 Self {
54 min: centre - radius,
55 max: centre + radius,
56 }
57 }
58
59 pub fn midpoint(&self) -> T {
61 T::from(0.5).unwrap() * (self.min + self.max)
62 }
63
64 pub fn clearance_with(&self, other: &Self) -> T {
67 T::max(other.min - self.max, self.min - other.max)
68 }
69
70 pub fn distance(&self, other: T) -> T {
73 T::max(other - self.max, self.min - other)
74 }
75
76 pub fn lerp(&self, t: T) -> T {
79 self.min + t * (self.max - self.min)
80 }
81
82 pub fn inv_lerp(&self, value: T) -> T {
85 (value - self.min) / (self.max - self.min)
86 }
87}
88
89impl<T: Float> std::ops::Add<T> for Interval<T> {
90 type Output = Interval<T>;
91
92 fn add(self, rhs: T) -> Self::Output {
93 Self {
94 min: self.min + rhs,
95 max: self.max + rhs,
96 }
97 }
98}
99
100impl<T: Float> std::ops::Sub<T> for Interval<T> {
101 type Output = Interval<T>;
102
103 fn sub(self, rhs: T) -> Self::Output {
104 Self {
105 min: self.min - rhs,
106 max: self.max - rhs,
107 }
108 }
109}
110
111impl<T: Debug> Debug for Interval<T> {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 write!(f, "Interval({:?}, {:?})", &self.min, &self.max)
114 }
115}
116
117pub fn rotated_range(count: usize, start: usize) -> impl Iterator<Item = usize> {
118 (0..count)
119 .map(move |i| i + start)
120 .map(move |i| if i >= count { i - count } else { i })
121}