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