1use hashbrown::HashMap;
2use itertools::iproduct;
3use serde::{
4 Deserialize,
5 Serialize,
6};
7
8use crate::{
9 corners::Corners,
10 items::Item,
11 vector::Vector6,
12};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct AABBVersion1 {
17 grid: HashMap<(u32, u32, u32), Vec<Vector6<u32>>>,
18 cell_size: u32,
19}
20impl Default for AABBVersion1 {
21 fn default() -> Self {
22 Self {
23 grid: Default::default(),
24 cell_size: 10,
25 }
26 }
27}
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct AABBVersion1CheckedItem(pub Item);
31
32impl AABBVersion1 {
33 #[must_use]
35 pub fn new(length: usize) -> Self {
36 Self {
37 grid: HashMap::with_capacity(length),
38 cell_size: 8,
39 }
40 }
41 pub fn add(&mut self, item: AABBVersion1CheckedItem, corner: &Corners) -> anyhow::Result<()> {
43 let item = item.0;
44 let mut position_minimum = corner.position;
45 let x_position_minimum = position_minimum;
46 let mut position_maximum = position_minimum + item.size_cube;
47 let x_position_maximum = position_maximum;
48 position_minimum.divide_all(self.cell_size, 1);
49 position_maximum.divide_all(self.cell_size, 1);
50 let aabb = Vector6::new(
51 x_position_minimum.x,
52 x_position_minimum.y,
53 x_position_minimum.z,
54 x_position_maximum.x,
55 x_position_maximum.y,
56 x_position_maximum.z,
57 );
58 let end_x = position_maximum.x;
59 let end_y = position_maximum.y;
60 let end_z = position_maximum.z;
61 for x in position_minimum.x..=end_x {
62 for y in position_minimum.y..=end_y {
63 for z in position_minimum.z..=end_z {
64 self.grid
65 .entry((x, y, z))
66 .or_insert_with(Vec::new)
67 .push(aabb);
68 }
69 }
70 }
71 Ok(())
72 }
73 pub fn add_v2(
75 &mut self,
76 item: AABBVersion1CheckedItem,
77 corner: &Corners,
78 ) -> anyhow::Result<()> {
79 let item = item.0;
80 let mut position_minimum = corner.position;
81 let x_position_minimum = position_minimum;
82 let mut position_maximum = position_minimum + item.size_cube;
83 let x_position_maximum = position_maximum;
84 position_minimum.divide_all(self.cell_size, 1);
85 position_maximum.divide_all(self.cell_size, 1);
86 let aabb = Vector6::new(
87 x_position_minimum.x,
88 x_position_minimum.y,
89 x_position_minimum.z,
90 x_position_maximum.x,
91 x_position_maximum.y,
92 x_position_maximum.z,
93 );
94 let end_x = position_maximum.x;
95 let end_y = position_maximum.y;
96 let end_z = position_maximum.z;
97 iproduct!(
98 position_minimum.x..=end_x,
100 position_minimum.y..=end_y,
101 position_minimum.z..=end_z
102 )
103 .for_each(|(x, y, z)| {
104 self.grid
105 .entry((x, y, z))
106 .or_insert_with(Vec::new)
107 .push(aabb);
108 });
109 Ok(())
110 }
111 #[must_use]
113 pub fn check_item(&self, item: Item, corner: &Corners) -> Option<AABBVersion1CheckedItem> {
114 let mut position_minimum = corner.position;
115 let mut position_maximum = position_minimum + item.size_cube;
116 let x_position_minimum = position_minimum;
117 let x_position_maximum = position_maximum;
118 position_minimum.divide_all(self.cell_size, 1);
119 position_maximum.divide_all(self.cell_size, 1);
120 let end_x = position_maximum.x;
121 let end_y = position_maximum.y;
122 let end_z = position_maximum.z;
123 for x in position_minimum.x..=end_x {
124 for y in position_minimum.y..=end_y {
125 for z in position_minimum.z..=end_z {
126 if let Some(existing) = self.grid.get(&(x, y, z)) {
127 for existing_vector6 in existing {
128 let overlay_x = x_position_minimum.x < existing_vector6.w
129 && existing_vector6.x < x_position_maximum.x;
130 let overlay_y = x_position_minimum.y < existing_vector6.a
131 && existing_vector6.y < x_position_maximum.y;
132 let overlay_z = x_position_minimum.z < existing_vector6.b
133 && existing_vector6.z < x_position_maximum.z;
134 if overlay_x && overlay_y && overlay_z {
135 return None;
136 }
137 }
138 }
139 }
140 }
141 }
142 Some(AABBVersion1CheckedItem(item))
143 }
144
145 #[must_use]
147 pub fn check_item_v2(&self, item: Item, corner: &Corners) -> Option<AABBVersion1CheckedItem> {
148 let mut position_minimum = corner.position;
149 let mut position_maximum = position_minimum + item.size_cube;
150 let x_position_minimum = position_minimum;
151 let x_position_maximum = position_maximum;
152 position_minimum.divide_all(self.cell_size, 1);
153 position_maximum.divide_all(self.cell_size, 1);
154 let end_x = position_maximum.x;
155 let end_y = position_maximum.y;
156 let end_z = position_maximum.z;
157 let result = iproduct!(
158 position_minimum.x..=end_x,
159 position_minimum.y..=end_y,
160 position_minimum.z..=end_z
161 )
162 .any(|(x, y, z)| {
163 self.grid
164 .get(&(x, y, z))
165 .map(|existing| {
166 existing.iter().any(|existing_vector6| {
167 let overlay_x = x_position_minimum.x < existing_vector6.w
168 && existing_vector6.x < x_position_maximum.x;
169 let overlay_y = x_position_minimum.y < existing_vector6.a
170 && existing_vector6.y < x_position_maximum.y;
171 let overlay_z = x_position_minimum.z < existing_vector6.b
172 && existing_vector6.z < x_position_maximum.z;
173 overlay_x && overlay_y && overlay_z
174 })
175 })
176 .unwrap_or_else(|| false)
177 });
178 if !result {
180 Some(AABBVersion1CheckedItem(item))
181 } else {
182 None
183 }
184 }
185 #[must_use]
187 pub fn point_is_free(&self, p: &Corners) -> bool {
188 let point = p.clone().position;
189 let mut cell = p.position;
190 cell.divide_all(self.cell_size, 1);
191
192 if let Some(existing) = self.grid.get(&(cell.x, cell.y, cell.z)) {
193 for e in existing {
194 let inside = point.x >= e.x
195 && point.x < e.w
196 && point.y >= e.y
197 && point.y < e.a
198 && point.z >= e.z
199 && point.z < e.b;
200 if inside {
201 return false;
202 }
203 }
204 }
205 true
206 }
207}
208#[cfg(test)]
209mod tests {
210 use crate::{
211 aabb::AABBVersion1,
212 corners::Corners,
213 items::Item,
214 vector::Vector3,
215 };
216
217 #[test]
218 fn check_no_collision_and_collision_same_item() {
219 let mut aabb = AABBVersion1::new(10 as usize);
220 let item = Item::new(1, Vector3::new(10, 10, 10), 10, 0);
221 let test = aabb.check_item_v2(item.clone(), &Corners::new(0, 0, 0));
224 assert!(test.is_some());
225 let test = test.unwrap();
226 assert!(aabb.add(test, &Corners::new(0, 0, 0)).is_ok());
227
228 let test = aabb.check_item(item.clone(), &Corners::new(0, 0, 0));
229 assert!(test.is_none());
230 }
231}