rust/land2d/src/lib.rs
changeset 13949 4162ea9ae333
parent 13948 a325ed57ebfe
child 13950 2354264ab0b0
equal deleted inserted replaced
13948:a325ed57ebfe 13949:4162ea9ae333
     2 extern crate vec2d;
     2 extern crate vec2d;
     3 
     3 
     4 use std::cmp;
     4 use std::cmp;
     5 use std::ops;
     5 use std::ops;
     6 
     6 
     7 use integral_geometry::{LinePoints, ArcPoints, Point};
     7 use integral_geometry::{ArcPoints, EquidistantPoints, LinePoints, Point};
     8 
     8 
     9 pub struct Land2D<T> {
     9 pub struct Land2D<T> {
    10     pixels: vec2d::Vec2D<T>,
    10     pixels: vec2d::Vec2D<T>,
    11     width_mask: usize,
    11     width_mask: usize,
    12     height_mask: usize,
    12     height_mask: usize,
    59         } else {
    59         } else {
    60             U::default()
    60             U::default()
    61         }
    61         }
    62     }
    62     }
    63 
    63 
    64     fn apply_along_line<U: Default + ops::AddAssign, F: FnMut(i32, i32) -> U>(
    64     #[inline]
    65         x1: i32,
    65     pub fn map_point<U: Default, F: FnOnce(&mut T) -> U>(&mut self, point: Point, f: F) -> U {
    66         y1: i32,
    66         self.map(point.y, point.x, f)
    67         x2: i32,
       
    68         y2: i32,
       
    69         f: &mut F,
       
    70     ) -> U {
       
    71         let mut result = U::default();
       
    72         let mut e_x: i32 = 0;
       
    73         let mut e_y: i32 = 0;
       
    74         let mut d_x: i32 = x2 - x1;
       
    75         let mut d_y: i32 = y2 - y1;
       
    76 
       
    77         let s_x: i32;
       
    78         let s_y: i32;
       
    79 
       
    80         if d_x > 0 {
       
    81             s_x = 1;
       
    82         } else if d_x < 0 {
       
    83             s_x = -1;
       
    84             d_x = -d_x;
       
    85         } else {
       
    86             s_x = d_x;
       
    87         }
       
    88 
       
    89         if d_y > 0 {
       
    90             s_y = 1;
       
    91         } else if d_y < 0 {
       
    92             s_y = -1;
       
    93             d_y = -d_y;
       
    94         } else {
       
    95             s_y = d_y;
       
    96         }
       
    97 
       
    98         let d = cmp::max(d_x, d_y);
       
    99 
       
   100         let mut x = x1;
       
   101         let mut y = y1;
       
   102 
       
   103         for _i in 0..=d {
       
   104             e_x += d_x;
       
   105             e_y += d_y;
       
   106 
       
   107             if e_x > d {
       
   108                 e_x -= d;
       
   109                 x += s_x;
       
   110             }
       
   111             if e_y > d {
       
   112                 e_y -= d;
       
   113                 y += s_y;
       
   114             }
       
   115 
       
   116             result += f(x, y);
       
   117         }
       
   118 
       
   119         result
       
   120     }
       
   121 
       
   122     fn apply_around_circle<U: Default + ops::AddAssign, F: FnMut(i32, i32) -> U>(
       
   123         radius: i32,
       
   124         f: &mut F,
       
   125     ) -> U {
       
   126         let mut dx: i32 = 0;
       
   127         let mut dy: i32 = radius;
       
   128         let mut d = 3 - 2 * radius;
       
   129         let mut result = U::default();
       
   130 
       
   131         while dx < dy {
       
   132             result += f(dx, dy);
       
   133 
       
   134             if d < 0 {
       
   135                 d += 4 * dx + 6;
       
   136             } else {
       
   137                 d += 4 * (dx - dy) + 10;
       
   138                 dy -= 1;
       
   139             }
       
   140 
       
   141             dx += 1;
       
   142         }
       
   143 
       
   144         if dx == dy {
       
   145             result += f(dx, dy);
       
   146         }
       
   147 
       
   148         result
       
   149     }
    67     }
   150 
    68 
   151     pub fn fill_from_iter<I>(&mut self, i: I, value: T) -> usize
    69     pub fn fill_from_iter<I>(&mut self, i: I, value: T) -> usize
   152     where
    70     where
   153         I: std::iter::Iterator<Item = Point>,
    71         I: std::iter::Iterator<Item = Point>,
   288         ArcPoints::new(radius)
   206         ArcPoints::new(radius)
   289             .map(&mut |p: Point| self.fill_circle_lines(x, y, p.x, p.y, &f))
   207             .map(&mut |p: Point| self.fill_circle_lines(x, y, p.x, p.y, &f))
   290             .sum()
   208             .sum()
   291     }
   209     }
   292 
   210 
   293     #[inline]
   211     pub fn draw_thick_line(&mut self, from: Point, to: Point, radius: i32, value: T) -> usize {
   294     fn change_dots_around<U: Default + ops::AddAssign, F: FnMut(i32, i32) -> U>(
   212         let mut result = 0;
   295         x: i32,
   213 
   296         y: i32,
   214         for point in LinePoints::new(from, to) {
   297         xx: i32,
   215             for vector in ArcPoints::new(radius) {
   298         yy: i32,
   216                 for delta in EquidistantPoints::new(vector) {
   299         f: &mut F,
   217                     self.map_point(point + delta, |p| {
   300     ) -> U {
       
   301         let mut result = U::default();
       
   302         result += f(y + yy, x + xx);
       
   303         result += f(y - yy, x + xx);
       
   304         result += f(y + yy, x - xx);
       
   305         result += f(y - yy, x - xx);
       
   306         result += f(y + xx, x + yy);
       
   307         result += f(y - xx, x + yy);
       
   308         result += f(y + xx, x - yy);
       
   309         result += f(y - xx, x - yy);
       
   310 
       
   311         result
       
   312     }
       
   313 
       
   314     pub fn draw_thick_line(
       
   315         &mut self,
       
   316         from: Point, to: Point,
       
   317         radius: i32,
       
   318         value: T,
       
   319     ) -> usize {
       
   320         for deltas in ArcPoints::new(radius) {
       
   321             for points in LinePoints::new(from, to) {
       
   322 
       
   323             }
       
   324         }
       
   325 
       
   326         <Land2D<T>>::apply_around_circle(radius, &mut |dx, dy| {
       
   327             <Land2D<T>>::apply_along_line(x1, y1, x2, y2, &mut |x, y| {
       
   328                 <Land2D<T>>::change_dots_around(x, y, dx, dy, &mut |x, y| {
       
   329                     self.map(x, y, |p| {
       
   330                         if *p != value {
   218                         if *p != value {
   331                             *p = value;
   219                             *p = value;
   332                             1
   220                             result += 1;
   333                         } else {
       
   334                             0
       
   335                         }
   221                         }
   336                     })
   222                     })
   337                 })
   223                 }
   338             })
   224             }
   339         })
   225         }
       
   226 
       
   227         result
   340     }
   228     }
   341 }
   229 }
   342 
   230 
   343 #[cfg(test)]
   231 #[cfg(test)]
   344 mod tests {
   232 mod tests {