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); |