rust/lib-hedgewars-engine/src/render/atlas.rs
changeset 14726 75ff5c643004
parent 14725 19d30d96d7d6
child 14727 2cc36cb1c258
--- a/rust/lib-hedgewars-engine/src/render/atlas.rs	Wed Mar 27 22:10:46 2019 +0300
+++ b/rust/lib-hedgewars-engine/src/render/atlas.rs	Wed Mar 27 23:26:58 2019 +0300
@@ -29,6 +29,40 @@
     }
 }
 
+#[derive(PartialEq, Eq)]
+pub struct UsedSpace {
+    used_area: usize,
+    total_area: usize,
+}
+
+impl UsedSpace {
+    const fn new(used_area: usize, total_area: usize) -> Self {
+        Self {
+            used_area,
+            total_area,
+        }
+    }
+
+    const fn used(&self) -> usize {
+        self.used_area
+    }
+
+    const fn total(&self) -> usize {
+        self.total_area
+    }
+}
+
+impl std::fmt::Debug for UsedSpace {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+        write!(
+            f,
+            "{:.2}%",
+            self.used() as f32 / self.total() as f32 / 100.0
+        )?;
+        Ok(())
+    }
+}
+
 pub struct Atlas {
     size: Size,
     free_rects: Vec<Rect>,
@@ -48,6 +82,11 @@
         self.size
     }
 
+    pub fn used_space(&self) -> UsedSpace {
+        let used = self.used_rects.iter().map(|r| r.size().area()).sum();
+        UsedSpace::new(used, self.size.area())
+    }
+
     fn find_position(&self, size: Size) -> Option<(Rect, Fit)> {
         let mut best_rect = Rect::EMPTY;
         let mut best_fit = Fit::new();
@@ -213,6 +252,7 @@
 mod tests {
     use super::Atlas;
     use integral_geometry::{Rect, Size};
+    use itertools::Itertools as _;
     use proptest::prelude::*;
 
     #[test]
@@ -278,13 +318,32 @@
             let mut atlas = Atlas::new(container.size());
             let inserted: Vec<_> = rects.iter().filter_map(|TestRect(size)| atlas.insert(*size)).collect();
 
-            let mut inserted_pairs = inserted.iter().zip(&inserted);
+            let mut inserted_pairs = inserted.iter().cartesian_product(inserted.iter());
 
             assert!(inserted.iter().all(|r| container.contains_rect(r)));
-            assert!(inserted_pairs.all(|(r1, r2)| r1 == r2 || r1 != r2 && r1.intersects(r2)));
+            assert!(inserted_pairs.all(|(r1, r2)| r1 == r2 || r1 != r2 && !r1.intersects(r2)));
 
-            assert(inserted.len(), rects.len());
+            assert_eq!(inserted.len(), rects.len());
             assert_eq!(sum_area(&inserted), sum_area(&rects));
         }
     }
+
+    proptest! {
+        #[test]
+        fn prop_insert_set(rects in Vec::<TestRect>::arbitrary()) {
+            let container = Rect::at_origin(Size::square(2048));
+            let mut atlas = Atlas::new(container.size());
+            let mut set_atlas = Atlas::new(container.size());
+
+            let inserted: Vec<_> = rects.iter().filter_map(|TestRect(size)| atlas.insert(*size)).collect();
+            let set_inserted: Vec<_> = set_atlas.insert_set(rects.iter().map(|TestRect(size)| *size));
+
+            let mut set_inserted_pairs = set_inserted.iter().cartesian_product(set_inserted.iter());
+
+            assert!(set_inserted_pairs.all(|(r1, r2)| r1 == r2 || r1 != r2 && !r1.intersects(r2)));
+            assert!(set_atlas.used_space().used() <= atlas.used_space().used());
+
+            assert_eq!(sum_area(&set_inserted), sum_area(&inserted));
+        }
+    }
 }