- Add methods to work with Rect as box
authorunC0Rr
Fri, 02 Nov 2018 14:29:24 +0100
changeset 14099 bf40b5f938b0
parent 14098 5ade484f3351
child 14100 a173557250a3
- Add methods to work with Rect as box - Refactor, tests, fixes
rust/integral-geometry/src/lib.rs
rust/land2d/src/lib.rs
rust/landgen/src/outline.rs
rust/landgen/src/template_based.rs
--- a/rust/integral-geometry/src/lib.rs	Fri Nov 02 13:30:04 2018 +0100
+++ b/rust/integral-geometry/src/lib.rs	Fri Nov 02 14:29:24 2018 +0100
@@ -202,6 +202,17 @@
         }
     }
 
+    pub fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self {
+        assert!(left <= right);
+        assert!(top <= bottom);
+
+        Rect::new(left, top, (right - left) as u32, (bottom - top) as u32)
+    }
+
+    pub fn from_size(top_left: Point, size: Size) -> Self {
+        Rect::new(top_left.x, top_left.y, size.width as u32, size.height as u32)
+    }
+
     #[inline]
     pub fn size(&self) -> Size {
         Size::new(self.width as usize, self.height as usize)
@@ -211,6 +222,41 @@
     pub fn area(&self) -> usize {
         self.size().area()
     }
+
+    #[inline]
+    pub fn left(&self) -> i32 {
+        self.x
+    }
+
+    #[inline]
+    pub fn top(&self) -> i32 {
+        self.y
+    }
+
+    #[inline]
+    pub fn right(&self) -> i32 {
+        self.x + self.width as i32
+    }
+
+    #[inline]
+    pub fn bottom(&self) -> i32 {
+        self.y + self.height as i32
+    }
+
+    #[inline]
+    pub fn top_left(&self) -> Point {
+        Point::new(self.x, self.y)
+    }
+
+    #[inline]
+    pub fn with_margin(&self, margin: i32) -> Self {
+        Rect::from_box(
+            self.left() + margin,
+            self.right() - margin,
+            self.top() + margin,
+            self.bottom() - margin,
+        )
+    }
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -440,4 +486,12 @@
 
         assert_eq!(l.center(), Point::new(3, 3));
     }
+
+    #[test]
+    fn rect() {
+        let r = Rect::from_box(10, 100, 0, 70);
+
+        assert_eq!(r.top_left(), Point::new(10, 0));
+        assert_eq!(r.with_margin(12), Rect::from_box(22, 88, 12, 58));
+    }
 }
--- a/rust/land2d/src/lib.rs	Fri Nov 02 13:30:04 2018 +0100
+++ b/rust/land2d/src/lib.rs	Fri Nov 02 14:29:24 2018 +0100
@@ -3,24 +3,29 @@
 
 use std::cmp;
 
-use integral_geometry::{
-    ArcPoints, EquidistantPoints,
-    Point, Size, SizeMask, Line
-};
+use integral_geometry::{ArcPoints, EquidistantPoints, Line, Point, Rect, Size, SizeMask};
 
 pub struct Land2D<T> {
     pixels: vec2d::Vec2D<T>,
     play_size: Size,
-    mask: SizeMask
+    play_box: Rect,
+
+    mask: SizeMask,
 }
 
 impl<T: Copy + PartialEq> Land2D<T> {
     pub fn new(play_size: Size, fill_value: T) -> Self {
         let real_size = play_size.next_power_of_two();
+        let top_left = Point::new(
+            (real_size.width - play_size.width / 2) as i32,
+            (real_size.height - play_size.height) as i32,
+        );
+        let play_box = Rect::from_size(top_left, play_size);
         Self {
             play_size,
+            play_box,
             pixels: vec2d::Vec2D::new(real_size, fill_value),
-            mask: real_size.to_mask()
+            mask: real_size.to_mask(),
         }
     }
 
@@ -55,6 +60,11 @@
     }
 
     #[inline]
+    pub fn play_box(&self) -> Rect {
+        self.play_box
+    }
+
+    #[inline]
     pub fn is_valid_x(&self, x: i32) -> bool {
         self.mask.contains_x(x as usize)
     }
@@ -245,7 +255,8 @@
             let from_x = cmp::max(0, center.x - offset.x) as usize;
             let to_x = cmp::min(self.width() - 1, (center.x + offset.x) as usize);
             self.pixels[row_index as usize][from_x..=to_x]
-                .iter_mut().for_each(|v| *v = value);
+                .iter_mut()
+                .for_each(|v| *v = value);
             to_x - from_x + 1
         } else {
             0
@@ -253,14 +264,14 @@
     }
 
     pub fn fill_circle(&mut self, center: Point, radius: i32, value: T) -> usize {
-        let transforms =
-            [[0, 1, 1, 0], [0, 1, -1, 0],
-             [1, 0, 0, 1], [1, 0, 0, -1]];
-        ArcPoints::new(radius).map(|vector| {
-            transforms.iter().map(|m|
-                self.fill_row(center, vector.transform(m), value)
-            ).sum::<usize>()
-        }).sum()
+        let transforms = [[0, 1, 1, 0], [0, 1, -1, 0], [1, 0, 0, 1], [1, 0, 0, -1]];
+        ArcPoints::new(radius)
+            .map(|vector| {
+                transforms
+                    .iter()
+                    .map(|m| self.fill_row(center, vector.transform(m), value))
+                    .sum::<usize>()
+            }).sum()
     }
 
     pub fn draw_thick_line(&mut self, line: Line, radius: i32, value: T) -> usize {
--- a/rust/landgen/src/outline.rs	Fri Nov 02 13:30:04 2018 +0100
+++ b/rust/landgen/src/outline.rs	Fri Nov 02 14:29:24 2018 +0100
@@ -1,6 +1,6 @@
 use itertools::Itertools;
 
-use integral_geometry::{Line, Point, Size};
+use integral_geometry::{Line, Point, Rect, Size};
 use land2d::Land2D;
 
 use outline_template::OutlineTemplate;
@@ -9,14 +9,19 @@
     pub islands: Vec<Vec<Point>>,
     pub fill_points: Vec<Point>,
     pub size: Size,
+    pub play_box: Rect,
 }
 
 impl OutlinePoints {
     pub fn from_outline_template<I: Iterator<Item = u32>>(
         outline_template: &OutlineTemplate,
+        play_box: Rect,
+        size: Size,
         random_numbers: &mut I,
     ) -> Self {
         Self {
+            play_box,
+            size,
             islands: outline_template
                 .islands
                 .iter()
@@ -24,14 +29,15 @@
                     i.iter()
                         .zip(random_numbers.tuples())
                         .map(|(rect, (rnd_a, rnd_b))| {
-                            Point::new(
-                                rect.x + (rnd_a % rect.width) as i32,
-                                rect.y + (rnd_b % rect.height) as i32,
-                            )
+                            rect.top_left()
+                                + Point::new(
+                                    (rnd_a % rect.width) as i32,
+                                    (rnd_b % rect.height) as i32,
+                                )
+                                + play_box.top_left()
                         }).collect()
                 }).collect(),
             fill_points: outline_template.fill_points.clone(),
-            size: outline_template.size,
         }
     }
 
@@ -51,7 +57,6 @@
         segment: Line,
         random_numbers: &mut I,
     ) -> Option<Point> {
-
         None
     }
 
@@ -130,18 +135,28 @@
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.island < self.outline.islands.len() {
-            if self.index + 1 < self.outline.islands[self.index].len() {
-                Some(Line::new(
-                    self.outline.islands[self.index][self.index],
-                    self.outline.islands[self.index][self.index + 1],
-                ))
-            } else if self.index + 1 == self.outline.islands[self.index].len() {
-                Some(Line::new(
-                    self.outline.islands[self.index][self.index],
-                    self.outline.islands[self.index][0],
-                ))
+            if self.index + 1 < self.outline.islands[self.island].len() {
+                let result = Some(Line::new(
+                    self.outline.islands[self.island][self.index],
+                    self.outline.islands[self.island][self.index + 1],
+                ));
+
+                self.index += 1;
+
+                result
+            } else if self.index + 1 == self.outline.islands[self.island].len() {
+                let result = Some(Line::new(
+                    self.outline.islands[self.island][self.index],
+                    self.outline.islands[self.island][0],
+                ));
+
+                self.island += 1;
+                self.index = 0;
+
+                result
             } else {
                 self.island += 1;
+                self.index = 0;
                 self.next()
             }
         } else {
@@ -149,3 +164,30 @@
         }
     }
 }
+
+#[test()]
+fn points_test() {
+    let mut points = OutlinePoints {
+        islands: vec![
+            vec![Point::new(0, 0), Point::new(20, 0), Point::new(30, 30)],
+            vec![Point::new(10, 15), Point::new(15, 20), Point::new(20, 15)],
+        ],
+        fill_points: vec![Point::new(1, 1)],
+        play_box: Rect::from_box(0, 100, 0, 100).with_margin(10),
+        size: Size::square(100),
+    };
+
+    let segments: Vec<Line> = points.segments_iter().collect();
+    assert_eq!(
+        segments.first(),
+        Some(&Line::new(Point::new(0, 0), Point::new(20, 0)))
+    );
+    assert_eq!(
+        segments.last(),
+        Some(&Line::new(Point::new(20, 15), Point::new(10, 15)))
+    );
+
+    points.iter_mut().for_each(|p| p.x = 2);
+    assert_eq!(points.fill_points[0].x, 2);
+    assert_eq!(points.islands[0][0].x, 2);
+}
--- a/rust/landgen/src/template_based.rs	Fri Nov 02 13:30:04 2018 +0100
+++ b/rust/landgen/src/template_based.rs	Fri Nov 02 14:29:24 2018 +0100
@@ -23,19 +23,10 @@
         parameters: LandGenerationParameters<T>,
         random_numbers: &mut I,
     ) -> Land2D<T> {
-        let mut points =
-            OutlinePoints::from_outline_template(&self.outline_template, random_numbers);
-
-        let mut land = Land2D::new(points.size, parameters.basic);
+        let mut land = Land2D::new(self.outline_template.size, parameters.basic);
 
-        let top_left = Point::new(
-            (land.width() - land.play_width() / 2) as i32,
-            (land.height() - land.play_height()) as i32,
-        );
-
-        points.size = land.size();
-
-        points.iter_mut().for_each(|p| *p += top_left);
+        let mut points =
+            OutlinePoints::from_outline_template(&self.outline_template, land.play_box(), land.size(), random_numbers);
 
         // mirror
         if self.outline_template.can_mirror {
@@ -72,15 +63,3 @@
         land
     }
 }
-
-#[test()]
-fn points_test() {
-    let mut points = OutlinePoints {
-        islands: vec![vec![]],
-        fill_points: vec![Point::new(1, 1)],
-        size: Size::square(100),
-    };
-
-    points.iter_mut().for_each(|p| p.x = 2);
-    assert_eq!(points.fill_points[0].x, 2);
-}