27 None |
27 None |
28 } |
28 } |
29 } |
29 } |
30 } |
30 } |
31 |
31 |
|
32 #[derive(PartialEq, Eq)] |
|
33 pub struct UsedSpace { |
|
34 used_area: usize, |
|
35 total_area: usize, |
|
36 } |
|
37 |
|
38 impl UsedSpace { |
|
39 const fn new(used_area: usize, total_area: usize) -> Self { |
|
40 Self { |
|
41 used_area, |
|
42 total_area, |
|
43 } |
|
44 } |
|
45 |
|
46 const fn used(&self) -> usize { |
|
47 self.used_area |
|
48 } |
|
49 |
|
50 const fn total(&self) -> usize { |
|
51 self.total_area |
|
52 } |
|
53 } |
|
54 |
|
55 impl std::fmt::Debug for UsedSpace { |
|
56 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { |
|
57 write!( |
|
58 f, |
|
59 "{:.2}%", |
|
60 self.used() as f32 / self.total() as f32 / 100.0 |
|
61 )?; |
|
62 Ok(()) |
|
63 } |
|
64 } |
|
65 |
32 pub struct Atlas { |
66 pub struct Atlas { |
33 size: Size, |
67 size: Size, |
34 free_rects: Vec<Rect>, |
68 free_rects: Vec<Rect>, |
35 used_rects: Vec<Rect>, |
69 used_rects: Vec<Rect>, |
36 } |
70 } |
44 } |
78 } |
45 } |
79 } |
46 |
80 |
47 pub fn size(&self) -> Size { |
81 pub fn size(&self) -> Size { |
48 self.size |
82 self.size |
|
83 } |
|
84 |
|
85 pub fn used_space(&self) -> UsedSpace { |
|
86 let used = self.used_rects.iter().map(|r| r.size().area()).sum(); |
|
87 UsedSpace::new(used, self.size.area()) |
49 } |
88 } |
50 |
89 |
51 fn find_position(&self, size: Size) -> Option<(Rect, Fit)> { |
90 fn find_position(&self, size: Size) -> Option<(Rect, Fit)> { |
52 let mut best_rect = Rect::EMPTY; |
91 let mut best_rect = Rect::EMPTY; |
53 let mut best_fit = Fit::new(); |
92 let mut best_fit = Fit::new(); |
276 fn prop_insert(rects in Vec::<TestRect>::arbitrary()) { |
316 fn prop_insert(rects in Vec::<TestRect>::arbitrary()) { |
277 let container = Rect::at_origin(Size::square(2048)); |
317 let container = Rect::at_origin(Size::square(2048)); |
278 let mut atlas = Atlas::new(container.size()); |
318 let mut atlas = Atlas::new(container.size()); |
279 let inserted: Vec<_> = rects.iter().filter_map(|TestRect(size)| atlas.insert(*size)).collect(); |
319 let inserted: Vec<_> = rects.iter().filter_map(|TestRect(size)| atlas.insert(*size)).collect(); |
280 |
320 |
281 let mut inserted_pairs = inserted.iter().zip(&inserted); |
321 let mut inserted_pairs = inserted.iter().cartesian_product(inserted.iter()); |
282 |
322 |
283 assert!(inserted.iter().all(|r| container.contains_rect(r))); |
323 assert!(inserted.iter().all(|r| container.contains_rect(r))); |
284 assert!(inserted_pairs.all(|(r1, r2)| r1 == r2 || r1 != r2 && r1.intersects(r2))); |
324 assert!(inserted_pairs.all(|(r1, r2)| r1 == r2 || r1 != r2 && !r1.intersects(r2))); |
285 |
325 |
286 assert(inserted.len(), rects.len()); |
326 assert_eq!(inserted.len(), rects.len()); |
287 assert_eq!(sum_area(&inserted), sum_area(&rects)); |
327 assert_eq!(sum_area(&inserted), sum_area(&rects)); |
288 } |
328 } |
289 } |
329 } |
290 } |
330 |
|
331 proptest! { |
|
332 #[test] |
|
333 fn prop_insert_set(rects in Vec::<TestRect>::arbitrary()) { |
|
334 let container = Rect::at_origin(Size::square(2048)); |
|
335 let mut atlas = Atlas::new(container.size()); |
|
336 let mut set_atlas = Atlas::new(container.size()); |
|
337 |
|
338 let inserted: Vec<_> = rects.iter().filter_map(|TestRect(size)| atlas.insert(*size)).collect(); |
|
339 let set_inserted: Vec<_> = set_atlas.insert_set(rects.iter().map(|TestRect(size)| *size)); |
|
340 |
|
341 let mut set_inserted_pairs = set_inserted.iter().cartesian_product(set_inserted.iter()); |
|
342 |
|
343 assert!(set_inserted_pairs.all(|(r1, r2)| r1 == r2 || r1 != r2 && !r1.intersects(r2))); |
|
344 assert!(set_atlas.used_space().used() <= atlas.used_space().used()); |
|
345 |
|
346 assert_eq!(sum_area(&set_inserted), sum_area(&inserted)); |
|
347 } |
|
348 } |
|
349 } |