rust/land2d/src/lib.rs
changeset 13931 9230aed8a32e
parent 13924 a140f28decc4
child 13934 9c112f2ae02d
equal deleted inserted replaced
13930:5c9d963492bf 13931:9230aed8a32e
     6     pixels: vec2d::Vec2D<T>,
     6     pixels: vec2d::Vec2D<T>,
     7     width_mask: usize,
     7     width_mask: usize,
     8     height_mask: usize,
     8     height_mask: usize,
     9 }
     9 }
    10 
    10 
    11 impl<T: Default + Copy + PartialEq> Land2D<T> {
    11 impl<T: Copy + PartialEq> Land2D<T> {
    12     pub fn new(width: usize, height: usize) -> Self {
    12     pub fn new(width: usize, height: usize, fill_value: T) -> Self {
    13         assert!(width.is_power_of_two());
    13         assert!(width.is_power_of_two());
    14         assert!(height.is_power_of_two());
    14         assert!(height.is_power_of_two());
    15 
    15 
    16         Self {
    16         Self {
    17             pixels: vec2d::Vec2D::new(width, height, T::default()),
    17             pixels: vec2d::Vec2D::new(width, height, fill_value),
    18             width_mask: !(width - 1),
    18             width_mask: !(width - 1),
    19             height_mask: !(height - 1),
    19             height_mask: !(height - 1),
    20         }
    20         }
    21     }
    21     }
    22 
    22 
    29     pub fn height(&self) -> usize {
    29     pub fn height(&self) -> usize {
    30         self.pixels.height()
    30         self.pixels.height()
    31     }
    31     }
    32 
    32 
    33     #[inline]
    33     #[inline]
       
    34     pub fn is_valid_x(&self, x: i32) -> bool {
       
    35         (x as usize & self.width_mask) == 0
       
    36     }
       
    37 
       
    38     #[inline]
       
    39     pub fn is_valid_y(&self, y: i32) -> bool {
       
    40         (y as usize & self.height_mask) == 0
       
    41     }
       
    42 
       
    43     #[inline]
    34     pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool {
    44     pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool {
    35         (x as usize & self.width_mask) == 0 && (y as usize & self.height_mask) == 0
    45         self.is_valid_x(x) && self.is_valid_y(y)
    36     }
    46     }
    37 
    47 
    38     #[inline]
    48     #[inline]
    39     pub fn map<U, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) {
    49     pub fn map<U, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) {
    40         if self.is_valid_coordinate(x, y) {
    50         if self.is_valid_coordinate(x, y) {
    41             self.pixels.get_mut(y as usize, x as usize).map(f);
    51             unsafe { // hey, I just checked that coordinates are valid!
       
    52                 f(self.pixels.get_unchecked_mut(y as usize, x as usize));
       
    53             }
    42         }
    54         }
    43     }
    55     }
    44 
    56 
    45     pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, value: T) {
    57     pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, value: T) {
    46         let mut e_x: i32 = 0;
    58         let mut e_x: i32 = 0;
    94     pub fn fill(&mut self, start_x: i32, start_y: i32, border_value: T, fill_value: T) {
   106     pub fn fill(&mut self, start_x: i32, start_y: i32, border_value: T, fill_value: T) {
    95         debug_assert!(self.is_valid_coordinate(start_x - 1, start_y));
   107         debug_assert!(self.is_valid_coordinate(start_x - 1, start_y));
    96         debug_assert!(self.is_valid_coordinate(start_x, start_y));
   108         debug_assert!(self.is_valid_coordinate(start_x, start_y));
    97 
   109 
    98         let mut stack: Vec<(usize, usize, usize, isize)> = Vec::new();
   110         let mut stack: Vec<(usize, usize, usize, isize)> = Vec::new();
    99         fn push<T: Default + Copy + PartialEq>(
   111         fn push<T: Copy + PartialEq>(
   100             land: &Land2D<T>,
   112             land: &Land2D<T>,
   101             stack: &mut Vec<(usize, usize, usize, isize)>,
   113             stack: &mut Vec<(usize, usize, usize, isize)>,
   102             xl: usize,
   114             xl: usize,
   103             xr: usize,
   115             xr: usize,
   104             y: usize,
   116             y: usize,
   165                     }
   177                     }
   166                 }
   178                 }
   167             }
   179             }
   168         }
   180         }
   169     }
   181     }
       
   182 
       
   183     #[inline]
       
   184     fn fill_circle_line<F: Fn(&mut T) -> usize>(
       
   185         &mut self,
       
   186         y: i32,
       
   187         x_from: i32,
       
   188         x_to: i32,
       
   189         f: &F,
       
   190     ) -> usize {
       
   191         let mut result = 0;
       
   192 
       
   193         if self.is_valid_y(y) {
       
   194             for i in cmp::min(x_from, 0) as usize..cmp::max(x_to as usize, self.width() - 1) {
       
   195                 unsafe { // coordinates are valid at this point
       
   196                     result += f(self.pixels.get_unchecked_mut(y as usize, i));
       
   197                 }
       
   198             }
       
   199         }
       
   200 
       
   201         result
       
   202     }
       
   203 
       
   204     #[inline]
       
   205     fn fill_circle_lines<F: Fn(&mut T) -> usize>(
       
   206         &mut self,
       
   207         x: i32,
       
   208         y: i32,
       
   209         dx: i32,
       
   210         dy: i32,
       
   211         f: &F,
       
   212     ) -> usize {
       
   213         self.fill_circle_line(y + dy, x - dx, x + dx, f)
       
   214             + self.fill_circle_line(y - dy, x - dx, x + dx, f)
       
   215             + self.fill_circle_line(y + dx, x - dy, x + dy, f)
       
   216             + self.fill_circle_line(y - dx, x - dy, x + dy, f)
       
   217     }
       
   218 
       
   219     pub fn change_round<F: Fn(&mut T) -> usize>(
       
   220         &mut self,
       
   221         x: i32,
       
   222         y: i32,
       
   223         radius: i32,
       
   224         f: F,
       
   225     ) -> usize {
       
   226         let mut dx: i32 = 0;
       
   227         let mut dy: i32 = radius;
       
   228         let mut d = 3 - 2 * radius;
       
   229         let mut result = 0;
       
   230 
       
   231         while dx < dy {
       
   232             result += self.fill_circle_lines(x, y, dx, dy, &f);
       
   233 
       
   234             if d < 0 {
       
   235                 d += 4 * dx + 6;
       
   236             } else {
       
   237                 d += 4 * (dx - dy) + 10;
       
   238                 dy -= 1;
       
   239             }
       
   240 
       
   241             dx += 1;
       
   242         }
       
   243 
       
   244         if dx == dy {
       
   245             result += self.fill_circle_lines(x, y, dx, dy, &f);
       
   246         }
       
   247 
       
   248         result
       
   249     }
   170 }
   250 }
   171 
   251 
   172 #[cfg(test)]
   252 #[cfg(test)]
   173 mod tests {
   253 mod tests {
   174     use super::*;
   254     use super::*;
   175 
   255 
   176     #[test]
   256     #[test]
   177     fn basics() {
   257     fn basics() {
   178         let l: Land2D<u8> = Land2D::new(32, 64);
   258         let l: Land2D<u8> = Land2D::new(32, 64, 0);
   179 
   259 
   180         assert!(l.is_valid_coordinate(0, 0));
   260         assert!(l.is_valid_coordinate(0, 0));
   181         assert!(!l.is_valid_coordinate(-1, -1));
   261         assert!(!l.is_valid_coordinate(-1, -1));
   182 
   262 
   183         assert!(l.is_valid_coordinate(31, 63));
   263         assert!(l.is_valid_coordinate(31, 63));
   185         assert!(!l.is_valid_coordinate(31, 64));
   265         assert!(!l.is_valid_coordinate(31, 64));
   186     }
   266     }
   187 
   267 
   188     #[test]
   268     #[test]
   189     fn fill() {
   269     fn fill() {
   190         let mut l: Land2D<u8> = Land2D::new(128, 128);
   270         let mut l: Land2D<u8> = Land2D::new(128, 128, 0);
   191 
   271 
   192         l.draw_line(0, 0, 32, 96, 1);
   272         l.draw_line(0, 0, 32, 96, 1);
   193         l.draw_line(32, 96, 64, 32, 1);
   273         l.draw_line(32, 96, 64, 32, 1);
   194         l.draw_line(64, 32, 96, 80, 1);
   274         l.draw_line(64, 32, 96, 80, 1);
   195         l.draw_line(96, 80, 128, 0, 1);
   275         l.draw_line(96, 80, 128, 0, 1);