Introduce OutlineSegmentsIterator, some refactoring
authorunC0Rr
Fri, 02 Nov 2018 13:17:46 +0100
changeset 14097 e5904ead4864
parent 14096 df0e86b2630f
child 14098 5ade484f3351
Introduce OutlineSegmentsIterator, some refactoring
rust/integral-geometry/src/lib.rs
rust/land2d/src/lib.rs
rust/landgen/src/outline.rs
--- a/rust/integral-geometry/src/lib.rs	Fri Nov 02 14:08:45 2018 +0100
+++ b/rust/integral-geometry/src/lib.rs	Fri Nov 02 13:17:46 2018 +0100
@@ -1,4 +1,3 @@
-use std::cmp;
 use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -40,8 +39,10 @@
 
     #[inline]
     pub fn transform(self, matrix: &[i32; 4]) -> Self {
-        Point::new(matrix[0] * self.x + matrix[1] * self.y,
-                   matrix[2] * self.x + matrix[3] * self.y)
+        Point::new(
+            matrix[0] * self.x + matrix[1] * self.y,
+            matrix[2] * self.x + matrix[3] * self.y,
+        )
     }
 }
 
@@ -59,7 +60,10 @@
 
     #[inline]
     pub fn square(size: usize) -> Self {
-        Size { width: size, height: size }
+        Size {
+            width: size,
+            height: size,
+        }
     }
 
     #[inline]
@@ -81,7 +85,7 @@
     pub fn next_power_of_two(&self) -> Self {
         Self {
             width: self.width.next_power_of_two(),
-            height: self.height.next_power_of_two()
+            height: self.height.next_power_of_two(),
         }
     }
 
@@ -95,7 +99,9 @@
     }
 }
 
-pub struct SizeMask{ size: Size }
+pub struct SizeMask {
+    size: Size,
+}
 
 impl SizeMask {
     #[inline]
@@ -103,7 +109,7 @@
         assert!(size.is_power_of_two());
         let size = Size {
             width: !(size.width - 1),
-            height: !(size.height - 1)
+            height: !(size.height - 1),
         };
         Self { size }
     }
@@ -124,19 +130,22 @@
     }
 }
 
-pub struct GridIndex{ shift: Point }
+pub struct GridIndex {
+    shift: Point,
+}
 
 impl GridIndex {
     pub fn new(size: Size) -> Self {
         assert!(size.is_power_of_two());
-        let shift = Point::new(size.width.trailing_zeros() as i32,
-                               size.height.trailing_zeros() as i32);
+        let shift = Point::new(
+            size.width.trailing_zeros() as i32,
+            size.height.trailing_zeros() as i32,
+        );
         Self { shift }
     }
 
     pub fn map(&self, position: Point) -> Point {
-        Point::new(position.x >> self.shift.x,
-                   position.y >> self.shift.y)
+        Point::new(position.x >> self.shift.x, position.y >> self.shift.y)
     }
 }
 
@@ -185,7 +194,12 @@
 impl Rect {
     #[inline]
     pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
-        Self { x, y, width, height }
+        Self {
+            x,
+            y,
+            width,
+            height,
+        }
     }
 
     #[inline]
@@ -199,6 +213,32 @@
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct Line {
+    pub start: Point,
+    pub end: Point,
+}
+
+impl Line {
+    #[inline]
+    pub fn new(start: Point, end: Point) -> Self {
+        Self { start, end }
+    }
+
+    #[inline]
+    pub fn zero() -> Self {
+        Self::new(Point::zero(), Point::zero())
+    }
+}
+
+impl IntoIterator for Line {
+    type Item = Point;
+    type IntoIter = LinePoints;
+
+    fn into_iter(self) -> Self::IntoIter {
+        LinePoints::new(self)
+    }
+}
 
 pub struct LinePoints {
     accumulator: Point,
@@ -210,14 +250,14 @@
 }
 
 impl LinePoints {
-    pub fn new(from: Point, to: Point) -> Self {
-        let dir = to - from;
+    pub fn new(line: Line) -> Self {
+        let dir = line.end - line.start;
 
         Self {
             accumulator: Point::zero(),
             direction: dir.abs(),
             sign: dir.signum(),
-            current: from,
+            current: line.start,
             total_steps: dir.max_norm(),
             step: 0,
         }
@@ -337,7 +377,7 @@
 
     #[test]
     fn line_basic() {
-        let line = LinePoints::new(Point::new(0, 0), Point::new(3, 3));
+        let line = Line::new(Point::new(0, 0), Point::new(3, 3)).into_iter();
         let v = get_points(&[(0, 0), (1, 1), (2, 2), (3, 3), (123, 456)]);
 
         for (&a, b) in v.iter().zip(line) {
@@ -347,7 +387,7 @@
 
     #[test]
     fn line_skewed() {
-        let line = LinePoints::new(Point::new(0, 0), Point::new(5, -7));
+        let line = Line::new(Point::new(0, 0), Point::new(5, -7)).into_iter();
         let v = get_points(&[
             (0, 0),
             (1, -1),
--- a/rust/land2d/src/lib.rs	Fri Nov 02 14:08:45 2018 +0100
+++ b/rust/land2d/src/lib.rs	Fri Nov 02 13:17:46 2018 +0100
@@ -4,8 +4,8 @@
 use std::cmp;
 
 use integral_geometry::{
-    ArcPoints, EquidistantPoints, LinePoints,
-    Point, Size, SizeMask
+    ArcPoints, EquidistantPoints,
+    Point, Size, SizeMask, Line
 };
 
 pub struct Land2D<T> {
@@ -103,8 +103,8 @@
         }).count()
     }
 
-    pub fn draw_line(&mut self, from: Point, to: Point, value: T) -> usize {
-        self.fill_from_iter(LinePoints::new(from, to), value)
+    pub fn draw_line(&mut self, line: Line, value: T) -> usize {
+        self.fill_from_iter(line.into_iter(), value)
     }
 
     pub fn fill(&mut self, start_point: Point, border_value: T, fill_value: T) {
@@ -263,12 +263,12 @@
         }).sum()
     }
 
-    pub fn draw_thick_line(&mut self, from: Point, to: Point, radius: i32, value: T) -> usize {
+    pub fn draw_thick_line(&mut self, line: Line, radius: i32, value: T) -> usize {
         let mut result = 0;
 
         for vector in ArcPoints::new(radius) {
             for delta in EquidistantPoints::new(vector) {
-                for point in LinePoints::new(from, to) {
+                for point in line.into_iter() {
                     self.map_point(point + delta, |p| {
                         if *p != value {
                             *p = value;
@@ -308,13 +308,13 @@
     fn fill() {
         let mut l: Land2D<u8> = Land2D::new(Size::square(128), 0);
 
-        l.draw_line(Point::new(0, 0), Point::new(32, 96), 1);
-        l.draw_line(Point::new(32, 96), Point::new(64, 32), 1);
-        l.draw_line(Point::new(64, 32), Point::new(96, 80), 1);
-        l.draw_line(Point::new(96, 80), Point::new(128, 0), 1);
+        l.draw_line(Line::new(Point::new(0, 0), Point::new(32, 96)), 1);
+        l.draw_line(Line::new(Point::new(32, 96), Point::new(64, 32)), 1);
+        l.draw_line(Line::new(Point::new(64, 32), Point::new(96, 80)), 1);
+        l.draw_line(Line::new(Point::new(96, 80), Point::new(128, 0)), 1);
 
-        l.draw_line(Point::new(0, 128), Point::new(64, 96), 1);
-        l.draw_line(Point::new(128, 128), Point::new(64, 96), 1);
+        l.draw_line(Line::new(Point::new(0, 128), Point::new(64, 96)), 1);
+        l.draw_line(Line::new(Point::new(128, 128), Point::new(64, 96)), 1);
 
         l.fill(Point::new(32, 32), 1, 2);
         l.fill(Point::new(16, 96), 1, 3);
--- a/rust/landgen/src/outline.rs	Fri Nov 02 14:08:45 2018 +0100
+++ b/rust/landgen/src/outline.rs	Fri Nov 02 13:17:46 2018 +0100
@@ -1,6 +1,6 @@
 use itertools::Itertools;
 
-use integral_geometry::{Point, Size};
+use integral_geometry::{Line, Point, Size};
 use land2d::Land2D;
 
 use outline_template::OutlineTemplate;
@@ -48,8 +48,7 @@
 
     fn divide_edge<I: Iterator<Item = u32>>(
         &self,
-        start_point: Point,
-        end_point: Point,
+        segment: Line,
         random_numbers: &mut I,
     ) -> Option<Point> {
         None
@@ -58,25 +57,26 @@
     fn divide_edges<I: Iterator<Item = u32>>(&mut self, random_numbers: &mut I) {
         for is in 0..self.islands.len() {
             let mut i = 0;
-            let mut start_point = Point::zero();
-            let mut end_point = Point::zero();
+            let mut segment;
 
             loop {
                 {
                     let island = &self.islands[is];
+                    let mut end_point;
                     if i < island.len() {
-                        start_point = island[i];
                         end_point = if i + 1 < island.len() {
                             island[i + 1]
                         } else {
                             island[0]
                         };
                     } else {
-                        break
+                        break;
                     }
+
+                    segment = Line::new(island[i], end_point);
                 }
 
-                if let Some(new_point) = self.divide_edge(start_point, end_point, random_numbers) {
+                if let Some(new_point) = self.divide_edge(segment, random_numbers) {
                     self.islands[is].insert(i + 1, new_point);
                     i += 2;
                 } else {
@@ -104,13 +104,47 @@
     }
 
     pub fn draw<T: Copy + PartialEq>(&self, land: &mut Land2D<T>, value: T) {
-        for island in &self.islands {
-            if island.len() > 1 {
-                for i in 0..island.len() - 1 {
-                    land.draw_line(island[i], island[i + 1], value);
-                }
-                land.draw_line(island[island.len() - 1], island[0], value);
-            }
+        for segment in self.segments_iter() {
+            land.draw_line(segment, value);
+        }
+    }
+
+    fn segments_iter(&self) -> OutlineSegmentsIterator {
+        OutlineSegmentsIterator {
+            outline: self,
+            island: 0,
+            index: 0,
         }
     }
 }
+
+struct OutlineSegmentsIterator<'a> {
+    outline: &'a OutlinePoints,
+    island: usize,
+    index: usize,
+}
+
+impl<'a> Iterator for OutlineSegmentsIterator<'a> {
+    type Item = Line;
+
+    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],
+                ))
+            } else {
+                self.island += 1;
+                self.next()
+            }
+        } else {
+            None
+        }
+    }
+}