44 pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool { |
45 pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool { |
45 self.is_valid_x(x) && self.is_valid_y(y) |
46 self.is_valid_x(x) && self.is_valid_y(y) |
46 } |
47 } |
47 |
48 |
48 #[inline] |
49 #[inline] |
49 pub fn map<U, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) { |
50 pub fn map<U: Default, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) -> U { |
50 if self.is_valid_coordinate(x, y) { |
51 if self.is_valid_coordinate(x, y) { |
51 unsafe { // hey, I just checked that coordinates are valid! |
52 unsafe { |
52 f(self.pixels.get_unchecked_mut(y as usize, x as usize)); |
53 // hey, I just checked that coordinates are valid! |
53 } |
54 f(self.pixels.get_unchecked_mut(y as usize, x as usize)) |
54 } |
55 } |
55 } |
56 } else { |
56 |
57 U::default() |
57 pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, value: T) { |
58 } |
|
59 } |
|
60 |
|
61 fn apply_along_line<U: Default + ops::AddAssign, F: FnMut(i32, i32) -> U>( |
|
62 x1: i32, |
|
63 y1: i32, |
|
64 x2: i32, |
|
65 y2: i32, |
|
66 f: &mut F, |
|
67 ) -> U { |
|
68 let mut result = U::default(); |
58 let mut e_x: i32 = 0; |
69 let mut e_x: i32 = 0; |
59 let mut e_y: i32 = 0; |
70 let mut e_y: i32 = 0; |
60 let mut d_x: i32 = x2 - x1; |
71 let mut d_x: i32 = x2 - x1; |
61 let mut d_y: i32 = y2 - y1; |
72 let mut d_y: i32 = y2 - y1; |
62 |
73 |
97 if e_y > d { |
108 if e_y > d { |
98 e_y -= d; |
109 e_y -= d; |
99 y += s_y; |
110 y += s_y; |
100 } |
111 } |
101 |
112 |
|
113 result += f(x, y); |
|
114 } |
|
115 |
|
116 result |
|
117 } |
|
118 |
|
119 fn apply_around_circle<U: Default + ops::AddAssign, F: FnMut(i32, i32) -> U>( |
|
120 radius: i32, |
|
121 f: &mut F, |
|
122 ) -> U { |
|
123 let mut dx: i32 = 0; |
|
124 let mut dy: i32 = radius; |
|
125 let mut d = 3 - 2 * radius; |
|
126 let mut result = U::default(); |
|
127 |
|
128 while dx < dy { |
|
129 result += f(dx, dy); |
|
130 |
|
131 if d < 0 { |
|
132 d += 4 * dx + 6; |
|
133 } else { |
|
134 d += 4 * (dx - dy) + 10; |
|
135 dy -= 1; |
|
136 } |
|
137 |
|
138 dx += 1; |
|
139 } |
|
140 |
|
141 if dx == dy { |
|
142 result += f(dx, dy); |
|
143 } |
|
144 |
|
145 result |
|
146 } |
|
147 |
|
148 pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, value: T) -> usize { |
|
149 <Land2D<T>>::apply_along_line(x1, y1, x2, y2, &mut |x, y| { |
102 self.map(y, x, |p| *p = value); |
150 self.map(y, x, |p| *p = value); |
103 } |
151 1 |
|
152 }) |
104 } |
153 } |
105 |
154 |
106 pub fn fill(&mut self, start_x: i32, start_y: i32, border_value: T, fill_value: T) { |
155 pub fn fill(&mut self, start_x: i32, start_y: i32, border_value: T, fill_value: T) { |
107 debug_assert!(self.is_valid_coordinate(start_x - 1, start_y)); |
156 debug_assert!(self.is_valid_coordinate(start_x - 1, start_y)); |
108 debug_assert!(self.is_valid_coordinate(start_x, start_y)); |
157 debug_assert!(self.is_valid_coordinate(start_x, start_y)); |
190 ) -> usize { |
239 ) -> usize { |
191 let mut result = 0; |
240 let mut result = 0; |
192 |
241 |
193 if self.is_valid_y(y) { |
242 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) { |
243 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 |
244 unsafe { |
|
245 // coordinates are valid at this point |
196 result += f(self.pixels.get_unchecked_mut(y as usize, i)); |
246 result += f(self.pixels.get_unchecked_mut(y as usize, i)); |
197 } |
247 } |
198 } |
248 } |
199 } |
249 } |
200 |
250 |
221 x: i32, |
271 x: i32, |
222 y: i32, |
272 y: i32, |
223 radius: i32, |
273 radius: i32, |
224 f: F, |
274 f: F, |
225 ) -> usize { |
275 ) -> usize { |
226 let mut dx: i32 = 0; |
276 <Land2D<T>>::apply_around_circle(radius, &mut |dx, dy| { |
227 let mut dy: i32 = radius; |
277 self.fill_circle_lines(x, y, dx, dy, &f) |
228 let mut d = 3 - 2 * radius; |
278 }) |
229 let mut result = 0; |
279 } |
230 |
280 |
231 while dx < dy { |
281 #[inline] |
232 result += self.fill_circle_lines(x, y, dx, dy, &f); |
282 fn change_dots_around<U: Default + ops::AddAssign, F: FnMut(i32, i32) -> U>( |
233 |
283 x: i32, |
234 if d < 0 { |
284 y: i32, |
235 d += 4 * dx + 6; |
285 xx: i32, |
236 } else { |
286 yy: i32, |
237 d += 4 * (dx - dy) + 10; |
287 f: &mut F, |
238 dy -= 1; |
288 ) -> U { |
239 } |
289 let mut result = U::default(); |
240 |
290 result += f(y + yy, x + xx); |
241 dx += 1; |
291 result += f(y - yy, x + xx); |
242 } |
292 result += f(y + yy, x - xx); |
243 |
293 result += f(y - yy, x - xx); |
244 if dx == dy { |
294 result += f(y + xx, x + yy); |
245 result += self.fill_circle_lines(x, y, dx, dy, &f); |
295 result += f(y - xx, x + yy); |
246 } |
296 result += f(y + xx, x - yy); |
|
297 result += f(y - xx, x - yy); |
247 |
298 |
248 result |
299 result |
|
300 } |
|
301 |
|
302 pub fn draw_thick_line( |
|
303 &mut self, |
|
304 x1: i32, |
|
305 y1: i32, |
|
306 x2: i32, |
|
307 y2: i32, |
|
308 radius: i32, |
|
309 value: T, |
|
310 ) -> usize { |
|
311 <Land2D<T>>::apply_around_circle(radius, &mut |dx, dy| { |
|
312 <Land2D<T>>::apply_along_line(x1, y1, x2, y2, &mut |x, y| { |
|
313 <Land2D<T>>::change_dots_around(x, y, dx, dy, &mut |x, y| { |
|
314 self.map(x, y, |p| { |
|
315 if *p != value { |
|
316 *p = value; |
|
317 1 |
|
318 } else { |
|
319 0 |
|
320 } |
|
321 }) |
|
322 }) |
|
323 }) |
|
324 }) |
249 } |
325 } |
250 } |
326 } |
251 |
327 |
252 #[cfg(test)] |
328 #[cfg(test)] |
253 mod tests { |
329 mod tests { |