rust/land2d/src/lib.rs
changeset 14052 9c817b2eedae
parent 14050 4b40bdd214df
parent 14032 2869c2ccb1b8
child 14076 e5904ead4864
equal deleted inserted replaced
14051:8a0d69c16cad 14052:9c817b2eedae
     1 extern crate integral_geometry;
     1 extern crate integral_geometry;
     2 extern crate vec2d;
     2 extern crate vec2d;
     3 
     3 
     4 use std::cmp;
     4 use std::cmp;
     5 
     5 
     6 use integral_geometry::{ArcPoints, EquidistantPoints, LinePoints, Point};
     6 use integral_geometry::{
       
     7     ArcPoints, EquidistantPoints, LinePoints,
       
     8     Point, Size, SizeMask
       
     9 };
     7 
    10 
     8 pub struct Land2D<T> {
    11 pub struct Land2D<T> {
     9     pixels: vec2d::Vec2D<T>,
    12     pixels: vec2d::Vec2D<T>,
    10     play_width: usize,
    13     play_size: Size,
    11     play_height: usize,
    14     mask: SizeMask
    12     width_mask: usize,
       
    13     height_mask: usize,
       
    14 }
    15 }
    15 
    16 
    16 impl<T: Copy + PartialEq> Land2D<T> {
    17 impl<T: Copy + PartialEq> Land2D<T> {
    17     pub fn new(play_width: usize, play_height: usize, fill_value: T) -> Self {
    18     pub fn new(play_size: Size, fill_value: T) -> Self {
    18         let real_width = play_width.next_power_of_two();
    19         let real_size = play_size.next_power_of_two();
    19         let real_height = play_height.next_power_of_two();
       
    20 
       
    21         assert!(real_width > 0);
       
    22         assert!(real_height > 0);
       
    23 
       
    24         Self {
    20         Self {
    25             pixels: vec2d::Vec2D::new(real_width, real_height, fill_value),
    21             play_size,
    26             play_width,
    22             pixels: vec2d::Vec2D::new(real_size, fill_value),
    27             play_height,
    23             mask: real_size.to_mask()
    28             width_mask: !(real_width - 1),
       
    29             height_mask: !(real_height - 1),
       
    30         }
    24         }
    31     }
    25     }
    32 
    26 
    33     #[inline]
    27     #[inline]
    34     pub fn width(&self) -> usize {
    28     pub fn width(&self) -> usize {
    39     pub fn height(&self) -> usize {
    33     pub fn height(&self) -> usize {
    40         self.pixels.height()
    34         self.pixels.height()
    41     }
    35     }
    42 
    36 
    43     #[inline]
    37     #[inline]
       
    38     pub fn size(&self) -> Size {
       
    39         self.pixels.size()
       
    40     }
       
    41 
       
    42     #[inline]
    44     pub fn play_width(&self) -> usize {
    43     pub fn play_width(&self) -> usize {
    45         self.play_width
    44         self.play_size.width
    46     }
    45     }
    47 
    46 
    48     #[inline]
    47     #[inline]
    49     pub fn play_height(&self) -> usize {
    48     pub fn play_height(&self) -> usize {
    50         self.play_height
    49         self.play_size.height
       
    50     }
       
    51 
       
    52     #[inline]
       
    53     pub fn play_size(&self) -> Size {
       
    54         self.play_size
    51     }
    55     }
    52 
    56 
    53     #[inline]
    57     #[inline]
    54     pub fn is_valid_x(&self, x: i32) -> bool {
    58     pub fn is_valid_x(&self, x: i32) -> bool {
    55         (x as usize & self.width_mask) == 0
    59         self.mask.contains_x(x as usize)
    56     }
    60     }
    57 
    61 
    58     #[inline]
    62     #[inline]
    59     pub fn is_valid_y(&self, y: i32) -> bool {
    63     pub fn is_valid_y(&self, y: i32) -> bool {
    60         (y as usize & self.height_mask) == 0
    64         self.mask.contains_y(y as usize)
    61     }
    65     }
    62 
    66 
    63     #[inline]
    67     #[inline]
    64     pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool {
    68     pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool {
    65         self.is_valid_x(x) && self.is_valid_y(y)
    69         self.is_valid_x(x) && self.is_valid_y(y)
       
    70     }
       
    71 
       
    72     #[inline]
       
    73     pub fn rows(&self) -> impl Iterator<Item = &[T]> {
       
    74         self.pixels.rows()
    66     }
    75     }
    67 
    76 
    68     #[inline]
    77     #[inline]
    69     pub fn map<U: Default, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) -> U {
    78     pub fn map<U: Default, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) -> U {
    70         if self.is_valid_coordinate(x, y) {
    79         if self.is_valid_coordinate(x, y) {
   228         ArcPoints::new(radius)
   237         ArcPoints::new(radius)
   229             .map(&mut |p: Point| self.fill_circle_lines(x, y, p.x, p.y, &f))
   238             .map(&mut |p: Point| self.fill_circle_lines(x, y, p.x, p.y, &f))
   230             .sum()
   239             .sum()
   231     }
   240     }
   232 
   241 
       
   242     fn fill_row(&mut self, center: Point, offset: Point, value: T) -> usize {
       
   243         let row_index = center.y + offset.y;
       
   244         if self.is_valid_y(row_index) {
       
   245             let from_x = cmp::max(0, center.x - offset.x) as usize;
       
   246             let to_x = cmp::min(self.width() - 1, (center.x + offset.x) as usize);
       
   247             self.pixels[row_index as usize][from_x..=to_x]
       
   248                 .iter_mut().for_each(|v| *v = value);
       
   249             to_x - from_x + 1
       
   250         } else {
       
   251             0
       
   252         }
       
   253     }
       
   254 
       
   255     pub fn fill_circle(&mut self, center: Point, radius: i32, value: T) -> usize {
       
   256         let transforms =
       
   257             [[0, 1, 1, 0], [0, 1, -1, 0],
       
   258              [1, 0, 0, 1], [1, 0, 0, -1]];
       
   259         ArcPoints::new(radius).map(|vector| {
       
   260             transforms.iter().map(|m|
       
   261                 self.fill_row(center, vector.transform(m), value)
       
   262             ).sum::<usize>()
       
   263         }).sum()
       
   264     }
       
   265 
   233     pub fn draw_thick_line(&mut self, from: Point, to: Point, radius: i32, value: T) -> usize {
   266     pub fn draw_thick_line(&mut self, from: Point, to: Point, radius: i32, value: T) -> usize {
   234         let mut result = 0;
   267         let mut result = 0;
   235 
   268 
   236         for vector in ArcPoints::new(radius) {
   269         for vector in ArcPoints::new(radius) {
   237             for delta in EquidistantPoints::new(vector) {
   270             for delta in EquidistantPoints::new(vector) {
   254 mod tests {
   287 mod tests {
   255     use super::*;
   288     use super::*;
   256 
   289 
   257     #[test]
   290     #[test]
   258     fn basics() {
   291     fn basics() {
   259         let l: Land2D<u8> = Land2D::new(30, 50, 0);
   292         let l: Land2D<u8> = Land2D::new(Size::new(30, 50), 0);
   260 
   293 
   261         assert_eq!(l.play_width(), 30);
   294         assert_eq!(l.play_width(), 30);
   262         assert_eq!(l.play_height(), 50);
   295         assert_eq!(l.play_height(), 50);
   263         assert_eq!(l.width(), 32);
   296         assert_eq!(l.width(), 32);
   264         assert_eq!(l.height(), 64);
   297         assert_eq!(l.height(), 64);
   271         assert!(!l.is_valid_coordinate(31, 64));
   304         assert!(!l.is_valid_coordinate(31, 64));
   272     }
   305     }
   273 
   306 
   274     #[test]
   307     #[test]
   275     fn fill() {
   308     fn fill() {
   276         let mut l: Land2D<u8> = Land2D::new(128, 128, 0);
   309         let mut l: Land2D<u8> = Land2D::new(Size::square(128), 0);
   277 
   310 
   278         l.draw_line(Point::new(0, 0), Point::new(32, 96), 1);
   311         l.draw_line(Point::new(0, 0), Point::new(32, 96), 1);
   279         l.draw_line(Point::new(32, 96), Point::new(64, 32), 1);
   312         l.draw_line(Point::new(32, 96), Point::new(64, 32), 1);
   280         l.draw_line(Point::new(64, 32), Point::new(96, 80), 1);
   313         l.draw_line(Point::new(64, 32), Point::new(96, 80), 1);
   281         l.draw_line(Point::new(96, 80), Point::new(128, 0), 1);
   314         l.draw_line(Point::new(96, 80), Point::new(128, 0), 1);