# HG changeset patch # User unc0rr # Date 1539727191 -7200 # Node ID 9230aed8a32eb865a090433a4596ae2ec476dd75 # Parent 5c9d963492bf1a9c487a6197249ef0222ecc78a2 Implement Land2D::change_round() diff -r 5c9d963492bf -r 9230aed8a32e rust/land2d/src/lib.rs --- a/rust/land2d/src/lib.rs Tue Oct 16 23:59:22 2018 +0200 +++ b/rust/land2d/src/lib.rs Tue Oct 16 23:59:51 2018 +0200 @@ -8,13 +8,13 @@ height_mask: usize, } -impl Land2D { - pub fn new(width: usize, height: usize) -> Self { +impl Land2D { + pub fn new(width: usize, height: usize, fill_value: T) -> Self { assert!(width.is_power_of_two()); assert!(height.is_power_of_two()); Self { - pixels: vec2d::Vec2D::new(width, height, T::default()), + pixels: vec2d::Vec2D::new(width, height, fill_value), width_mask: !(width - 1), height_mask: !(height - 1), } @@ -31,14 +31,26 @@ } #[inline] + pub fn is_valid_x(&self, x: i32) -> bool { + (x as usize & self.width_mask) == 0 + } + + #[inline] + pub fn is_valid_y(&self, y: i32) -> bool { + (y as usize & self.height_mask) == 0 + } + + #[inline] pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool { - (x as usize & self.width_mask) == 0 && (y as usize & self.height_mask) == 0 + self.is_valid_x(x) && self.is_valid_y(y) } #[inline] pub fn map U>(&mut self, y: i32, x: i32, f: F) { if self.is_valid_coordinate(x, y) { - self.pixels.get_mut(y as usize, x as usize).map(f); + unsafe { // hey, I just checked that coordinates are valid! + f(self.pixels.get_unchecked_mut(y as usize, x as usize)); + } } } @@ -96,7 +108,7 @@ debug_assert!(self.is_valid_coordinate(start_x, start_y)); let mut stack: Vec<(usize, usize, usize, isize)> = Vec::new(); - fn push( + fn push( land: &Land2D, stack: &mut Vec<(usize, usize, usize, isize)>, xl: usize, @@ -167,6 +179,74 @@ } } } + + #[inline] + fn fill_circle_line usize>( + &mut self, + y: i32, + x_from: i32, + x_to: i32, + f: &F, + ) -> usize { + let mut result = 0; + + if self.is_valid_y(y) { + for i in cmp::min(x_from, 0) as usize..cmp::max(x_to as usize, self.width() - 1) { + unsafe { // coordinates are valid at this point + result += f(self.pixels.get_unchecked_mut(y as usize, i)); + } + } + } + + result + } + + #[inline] + fn fill_circle_lines usize>( + &mut self, + x: i32, + y: i32, + dx: i32, + dy: i32, + f: &F, + ) -> usize { + self.fill_circle_line(y + dy, x - dx, x + dx, f) + + self.fill_circle_line(y - dy, x - dx, x + dx, f) + + self.fill_circle_line(y + dx, x - dy, x + dy, f) + + self.fill_circle_line(y - dx, x - dy, x + dy, f) + } + + pub fn change_round usize>( + &mut self, + x: i32, + y: i32, + radius: i32, + f: F, + ) -> usize { + let mut dx: i32 = 0; + let mut dy: i32 = radius; + let mut d = 3 - 2 * radius; + let mut result = 0; + + while dx < dy { + result += self.fill_circle_lines(x, y, dx, dy, &f); + + if d < 0 { + d += 4 * dx + 6; + } else { + d += 4 * (dx - dy) + 10; + dy -= 1; + } + + dx += 1; + } + + if dx == dy { + result += self.fill_circle_lines(x, y, dx, dy, &f); + } + + result + } } #[cfg(test)] @@ -175,7 +255,7 @@ #[test] fn basics() { - let l: Land2D = Land2D::new(32, 64); + let l: Land2D = Land2D::new(32, 64, 0); assert!(l.is_valid_coordinate(0, 0)); assert!(!l.is_valid_coordinate(-1, -1)); @@ -187,7 +267,7 @@ #[test] fn fill() { - let mut l: Land2D = Land2D::new(128, 128); + let mut l: Land2D = Land2D::new(128, 128, 0); l.draw_line(0, 0, 32, 96, 1); l.draw_line(32, 96, 64, 32, 1);