# HG changeset patch # User unC0Rr # Date 1541161066 -3600 # Node ID e5904ead486465da35f4d418ba807ce60d346b7c # Parent df0e86b2630f338509abdd948ca87f8f64cc843b Introduce OutlineSegmentsIterator, some refactoring diff -r df0e86b2630f -r e5904ead4864 rust/integral-geometry/src/lib.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), diff -r df0e86b2630f -r e5904ead4864 rust/land2d/src/lib.rs --- 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 { @@ -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 = 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); diff -r df0e86b2630f -r e5904ead4864 rust/landgen/src/outline.rs --- 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>( &self, - start_point: Point, - end_point: Point, + segment: Line, random_numbers: &mut I, ) -> Option { None @@ -58,25 +57,26 @@ fn divide_edges>(&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(&self, land: &mut Land2D, 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 { + 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 + } + } +}