sepax2d/
aabb.rs

1#[cfg(feature = "serde")]
2use serde::{Serialize, Deserialize};
3
4/// An axis-aligned bounding box, that is a rectangle aligned
5/// along the Cartesian coordinate system.
6/// 
7/// # Examples
8/// 
9/// ```
10/// use sepax2d::prelude::*;
11/// 
12/// let box1 = AABB::new((0.0, 0.0), 10.0, 5.0);
13/// let box2 = AABB::new((-1.0, -0.5), 2.0, 1.0);
14/// let box3 = AABB::new((8.0, 2.0), 4.0, 2.0);
15/// 
16/// let circle = Circle::new((-2.0, -2.0), 3.0);
17/// 
18/// assert!(sat_overlap(&box1, &circle));
19/// assert!(sat_overlap(&box2, &box1));
20/// 
21/// let resolution = sat_collision(&box1, &box3);
22/// assert!(resolution.0 - 2.0 < f32::EPSILON && resolution.0 - 2.0 > -f32::EPSILON);
23/// assert!(resolution.1 - 0.0 < f32::EPSILON && resolution.1 - 0.0 > -f32::EPSILON);
24/// ```
25#[derive(Clone, Copy, Debug)]
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27pub struct AABB
28{
29
30    pub position: (f32, f32),
31    pub width: f32,
32    pub height: f32
33    
34}
35
36impl AABB
37{
38
39    /// Create a new AABB at the given position with the given width and height.
40    pub fn new(position: (f32, f32), width: f32, height: f32) -> AABB
41    {
42
43        return AABB { position, width, height };
44
45    }
46
47    fn points(&self) -> [(f32, f32); 4]
48    {
49
50        //TODO: Determine if this needs to be optimized or if the compiler does it for us
51        return 
52        [
53            
54            (0.0, 0.0),
55            (self.width, 0.0),
56            (self.width, self.height),
57            (0.0, self.height)
58
59        ];
60
61    }
62
63}
64
65impl crate::Shape for AABB
66{
67
68    fn position(&self) -> (f32, f32)
69    {
70
71        return self.position;
72
73    }
74
75    fn set_position(&mut self, position: (f32, f32))
76    {
77
78        self.position = position;
79
80    }
81    
82    fn num_axes(&self) -> usize
83    {
84
85        return 2;
86
87    }
88
89    fn get_axis(&self, index: usize, _target: (f32, f32)) -> (f32, f32)
90    {
91
92        return match index
93        {
94
95            0 => (1.0, 0.0),
96            _ => (0.0, 1.0)
97            
98        };
99
100    }
101
102    fn project(&self, axis: (f32, f32), _normalize: bool) -> (f32, f32)
103    {
104
105        return crate::project(self.position, axis, &self.points());
106
107    }
108
109    fn needs_closest(&self, _index: usize) -> bool
110    {
111
112        return false;
113
114    }
115
116    fn get_closest(&self, target: (f32, f32)) -> (f32, f32)
117    {
118
119        return crate::closest(self.position, target, &self.points());
120
121    }
122
123    fn point(&self, _index: usize) -> (f32, f32)
124    {
125
126        return self.position;
127
128    }
129
130}
131
132#[cfg(test)]
133mod aabb_tests
134{
135
136    use super::*;
137    use crate::{float_equal, Shape};
138
139    #[test]
140    fn test_num_axes()
141    {
142
143        let aabb = AABB::new((1.0, 2.0), 3.0, 2.0);
144
145        assert_eq!(aabb.num_axes(), 2);
146
147    }
148
149    #[test]
150    fn test_get_axis()
151    {
152
153        let aabb = AABB::new((4.0, 10.0), 2.0, 5.0);
154
155        let axis1 = aabb.get_axis(0, (1.0, 0.0));
156        let axis2 = aabb.get_axis(1, (13.0, 20.0));
157
158        assert!(float_equal(axis1.0, 1.0));
159        assert!(float_equal(axis1.1, 0.0));
160        assert!(float_equal(axis2.0, 0.0));
161        assert!(float_equal(axis2.1, 1.0));
162
163    }
164
165    #[test]
166    fn test_project()
167    {
168
169        let aabb = AABB::new((1.0, 2.0), 3.0, 4.0);
170
171        let axis1 = (1.0, 0.0);
172        let axis2 = (1.0, -1.0);
173
174        let projection1 = aabb.project(axis1, true);
175        let projection2 = aabb.project(axis2, false);
176
177        assert!(float_equal(projection1.0, 1.0));
178        assert!(float_equal(projection1.1, 4.0));
179        assert!(float_equal(projection2.0, -5.0));
180        assert!(float_equal(projection2.1, 2.0));
181
182    }
183
184    #[test]
185    fn test_needs_closest()
186    {
187
188        let aabb = AABB::new((1.0, 2.0), 3.0, 2.0);
189
190        assert!(!aabb.needs_closest(1));
191
192    }
193
194}