Skip to main content

aeon_tk/geometry/
axis.rs

1use crate::geometry::Face;
2
3use super::{Region, Side};
4
5/// Stores a bitset flag for each axis
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
7pub struct Split<const N: usize>(usize);
8
9impl<const N: usize> Split<N> {
10    /// Total permutations of axis maskes for a given dimension.
11    pub const COUNT: usize = 2usize.pow(N as u32);
12
13    /// Iterates of all axis maskes of a given dimension.
14    pub const fn enumerate() -> SplitIter<N> {
15        SplitIter { cursor: 0 }
16    }
17
18    /// Constructs an empty axis mask.
19    pub const fn empty() -> Self {
20        Self(0)
21    }
22
23    /// Constructs an axis mask with all axes set to true.
24    pub const fn full() -> Self {
25        Self(usize::MAX)
26    }
27
28    /// Converts a linear value into an axis mask.
29    pub fn from_linear(linear: usize) -> Self {
30        Self(linear)
31    }
32
33    /// Transforms this mask into a linear index.
34    pub fn to_linear(self) -> usize {
35        self.0.min(Self::COUNT - 1)
36    }
37
38    /// Transforms an axis mask into an array of bit values.
39    pub fn unpack(self) -> [bool; N] {
40        let mut result = [false; N];
41
42        for axis in 0..N {
43            result[axis] = self.is_set(axis);
44        }
45
46        result
47    }
48
49    /// Transforms an array of bit values into an axis mask.
50    pub fn pack(bits: [bool; N]) -> Self {
51        let mut result = Self::empty();
52
53        for (i, bit) in bits.into_iter().enumerate() {
54            result.set_to(i, bit);
55        }
56
57        result
58    }
59
60    /// Sets the given axis.
61    pub fn set(&mut self, axis: usize) {
62        self.0 |= 1 << axis
63    }
64
65    /// Unsets the given axis.
66    pub fn clear(&mut self, axis: usize) {
67        self.0 &= !(1 << axis)
68    }
69
70    /// Sets the axis to the given value.
71    pub fn set_to(&mut self, axis: usize, value: bool) {
72        self.0 &= !(1 << axis);
73        self.0 |= (value as usize) << axis;
74    }
75
76    /// Toggles an axis.
77    pub fn toggle(&mut self, axis: usize) {
78        self.0 ^= 1 << axis
79    }
80
81    /// Returns a new axis mask with the given axis toggled.
82    pub fn toggled(mut self, axis: usize) -> Self {
83        self.0 ^= 1 << axis;
84        self
85    }
86
87    /// Checks if the given axis is set.
88    pub fn is_set(self, axis: usize) -> bool {
89        (self.0 & (1 << axis)) != 0
90    }
91
92    pub fn is_inner_face(self, face: Face<N>) -> bool {
93        self.is_set(face.axis) != face.side
94    }
95
96    pub fn is_outer_face(self, face: Face<N>) -> bool {
97        self.is_set(face.axis) == face.side
98    }
99
100    pub fn inner_faces(self) -> impl Iterator<Item = Face<N>> {
101        Face::<N>::iterate().filter(move |&face| self.is_inner_face(face))
102    }
103
104    pub fn outer_faces(self) -> impl Iterator<Item = Face<N>> {
105        Face::<N>::iterate().filter(move |&face| self.is_outer_face(face))
106    }
107
108    pub fn as_inner_face(mut self, face: Face<N>) -> Self {
109        self.set_to(face.axis, !face.side);
110        self
111    }
112
113    pub fn as_outer_face(mut self, face: Face<N>) -> Self {
114        self.set_to(face.axis, face.side);
115        self
116    }
117
118    pub fn is_inner_region(self, region: Region<N>) -> bool {
119        for axis in 0..N {
120            match (region.side(axis), self.is_set(axis)) {
121                (Side::Left, false) => return false,
122                (Side::Right, true) => return false,
123                _ => {}
124            }
125        }
126
127        true
128    }
129
130    pub fn is_outer_region(self, region: Region<N>) -> bool {
131        !self.is_inner_region(region)
132    }
133
134    pub fn as_inner_region(mut self, region: Region<N>) -> Self {
135        for axis in 0..N {
136            match region.side(axis) {
137                Side::Left => self.set_to(axis, true),
138                Side::Right => self.set_to(axis, false),
139                _ => {}
140            }
141        }
142
143        self
144    }
145
146    pub fn as_outer_region(mut self, region: Region<N>) -> Self {
147        for axis in 0..N {
148            match region.side(axis) {
149                Side::Left => self.set_to(axis, false),
150                Side::Right => self.set_to(axis, true),
151                _ => {}
152            }
153        }
154
155        self
156    }
157}
158
159impl<const N: usize> datasize::DataSize for Split<N> {
160    const IS_DYNAMIC: bool = false;
161    const STATIC_HEAP_SIZE: usize = 0;
162
163    fn estimate_heap_size(&self) -> usize {
164        0
165    }
166}
167
168/// Iterates over all possible axis masks for a given dimension.
169pub struct SplitIter<const N: usize> {
170    cursor: usize,
171}
172
173impl<const N: usize> Iterator for SplitIter<N> {
174    type Item = Split<N>;
175
176    fn next(&mut self) -> Option<Self::Item> {
177        if self.cursor >= Split::<N>::COUNT {
178            return None;
179        }
180
181        let result = self.cursor;
182        self.cursor += 1;
183        Some(Split::from_linear(result))
184    }
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190
191    #[test]
192    fn masks() {
193        let mut splits = Split::<2>::enumerate();
194        assert_eq!(splits.next(), Some(Split::pack([false, false])));
195        assert_eq!(splits.next(), Some(Split::pack([true, false])));
196        assert_eq!(splits.next(), Some(Split::pack([false, true])));
197        assert_eq!(splits.next(), Some(Split::pack([true, true])));
198        assert_eq!(splits.next(), None);
199
200        let mut faces = Split::<2>::pack([false, true]).outer_faces();
201        assert_eq!(faces.next(), Some(Face::<2>::negative(0)));
202        assert_eq!(faces.next(), Some(Face::<2>::positive(1)));
203        assert_eq!(faces.next(), None);
204    }
205}