1#[cfg(feature = "serialize")]
2use serde::{Deserialize, Serialize};
3
4use super::ILine;
5use crate::{exclusive_irect, Direction};
6use bevy_math::{ivec2, IRect, IVec2};
7
8pub fn plot_line<F>(x0: i32, y0: i32, x1: i32, y1: i32, mut plot: F)
9where
10 F: FnMut(i32, i32),
11{
12 let dx = (x1 - x0).abs();
13 let dy = (y1 - y0).abs();
14 let mut x = x0;
15 let mut y = y0;
16 let mut xi = 1;
17 let mut yi = 1;
18
19 if x1 < x0 {
20 xi = -1;
21 }
22
23 if y1 < y0 {
24 yi = -1;
25 }
26
27 let mut err = dx - dy;
28 let mut e2: i32;
29
30 while x != x1 || y != y1 {
31 plot(x, y);
32 e2 = err * 2;
33 if e2 > -dy {
34 err -= dy;
35 x += xi;
36 }
37 if e2 < dx {
38 err += dx;
39 y += yi;
40 }
41 }
42
43 plot(x1, y1);
44}
45
46#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
47#[derive(Debug, Clone, PartialEq)]
48pub enum LinePixelIterator {
49 Axis(AxisLineIterator),
50 Angle(AngleLineIterator),
51}
52
53impl LinePixelIterator {
54 #[inline]
55 #[must_use]
56 pub fn new(line: &ILine) -> Self {
57 match AxisLineIterator::new(line) {
58 Some(iter) => LinePixelIterator::Axis(iter),
59 None => LinePixelIterator::Angle(AngleLineIterator::new(line)),
60 }
61 }
62
63 #[inline]
64 #[must_use]
65 pub fn peek(&self) -> Option<IVec2> {
66 match self {
67 LinePixelIterator::Axis(iter) => iter.peek(),
68 LinePixelIterator::Angle(iter) => iter.peek(),
69 }
70 }
71
72 #[inline]
77 pub fn seek_bounds(&mut self, bounds: &IRect) -> Option<IVec2> {
78 match self {
79 LinePixelIterator::Axis(iter) => iter.seek_bounds(bounds),
80 LinePixelIterator::Angle(iter) => iter.seek_bounds(bounds),
81 }
82 }
83}
84
85impl Iterator for LinePixelIterator {
86 type Item = IVec2;
87
88 #[inline]
89 fn next(&mut self) -> Option<Self::Item> {
90 match self {
91 LinePixelIterator::Axis(iter) => iter.next(),
92 LinePixelIterator::Angle(iter) => iter.next(),
93 }
94 }
95}
96
97#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
98#[derive(Debug, Clone, PartialEq)]
99pub struct AxisLineIterator {
100 point: IVec2,
101 direction: Direction,
102 end: IVec2,
103 finished: bool,
104}
105
106impl AxisLineIterator {
107 #[inline]
108 #[must_use]
109 pub fn new(line: &ILine) -> Option<Self> {
110 let direction = line.axis_alignment()?;
111 Some(Self {
112 point: line.start(),
113 direction,
114 end: line.end(),
115 finished: false,
116 })
117 }
118
119 #[inline]
120 #[must_use]
121 pub fn peek(&self) -> Option<IVec2> {
122 if self.finished {
123 return None;
124 }
125 Some(self.point)
126 }
127
128 pub fn seek_bounds(&mut self, bounds: &IRect) -> Option<IVec2> {
129 let point = self.next()?;
130
131 let top = bounds.max.y - 1;
132 let left = bounds.min.x;
133 let right = bounds.max.x - 1;
134 let bottom = bounds.min.y;
135
136 let result = match self.direction {
137 Direction::North => Some(IVec2::new(point.x, self.end.y.min(top))),
138 Direction::East => Some(IVec2::new(self.end.x.min(right), point.y)),
139 Direction::South => Some(IVec2::new(point.x, self.end.y.max(bottom))),
140 Direction::West => Some(IVec2::new(self.end.x.max(left), point.y)),
141 _ => None,
142 };
143
144 match result {
145 Some(point) => {
146 self.point = point;
148
149 self.next()
151 }
152 None => None,
153 }
154 }
155}
156
157impl Iterator for AxisLineIterator {
158 type Item = IVec2;
159
160 #[inline]
161 fn next(&mut self) -> Option<Self::Item> {
162 if self.finished {
163 None
164 } else {
165 let result = self.point;
166 if self.point == self.end {
167 self.finished = true;
168 } else {
169 self.point += self.direction.unit();
170 }
171 Some(result)
172 }
173 }
174}
175
176#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
177#[derive(Debug, Clone, PartialEq)]
178pub struct AngleLineIterator {
179 end: IVec2,
180 dist: IVec2,
181 point: IVec2,
182 xi: i32,
183 yi: i32,
184 err: i32,
185 e2: i32,
186 finished: bool,
187}
188
189impl AngleLineIterator {
190 #[inline]
191 #[must_use]
192 pub fn new(line: &ILine) -> Self {
193 let x0 = line.start().x;
194 let y0 = line.start().y;
195 let x1 = line.end().x;
196 let y1 = line.end().y;
197 let dist = ivec2((x1 - x0).abs(), (y1 - y0).abs());
198 let xi = if x1 < x0 { -1 } else { 1 };
199 let yi = if y1 < y0 { -1 } else { 1 };
200 AngleLineIterator {
201 end: line.end(),
202 dist,
203 point: line.start(),
204 xi,
205 yi,
206 err: dist.x - dist.y,
207 e2: 0,
208 finished: false,
209 }
210 }
211
212 #[inline]
213 #[must_use]
214 pub fn peek(&self) -> Option<IVec2> {
215 if self.finished {
216 return None;
217 }
218 Some(self.point)
219 }
220
221 #[inline]
222 pub fn seek_bounds(&mut self, bounds: &IRect) -> Option<IVec2> {
223 let bounds = exclusive_irect(bounds);
224 while let Some(point) = self.next() {
225 if let Some(next) = self.peek() {
226 if !bounds.contains(next) {
227 return Some(point);
228 }
229 } else {
230 return Some(point);
231 }
232 }
233 None
234 }
235}
236
237impl Iterator for AngleLineIterator {
238 type Item = IVec2;
239
240 fn next(&mut self) -> Option<Self::Item> {
241 if self.finished {
242 None
243 } else {
244 let result = self.point;
245 if self.point == self.end {
246 self.finished = true;
247 } else {
248 self.e2 = self.err * 2;
249 if self.e2 > -self.dist.y {
250 self.err -= self.dist.y;
251 self.point += ivec2(self.xi, 0);
252 }
253 if self.e2 < self.dist.x {
254 self.err += self.dist.x;
255 self.point += ivec2(0, self.yi);
256 }
257 }
258 Some(result)
259 }
260 }
261}
262
263#[cfg(test)]
264mod test {
265 use super::*;
266 use crate::iline;
267 use bevy_math::IVec2;
268
269 #[test]
270 fn test_plot_line_north() {
271 let mut points = Vec::new();
272 plot_line(0, 0, 0, 10, |x, y| points.push((x, y)));
273 assert_eq!(points.len(), 11);
274 assert_eq!(points[0], (0, 0));
275 assert_eq!(points[1], (0, 1));
276 assert_eq!(points[2], (0, 2));
277 assert_eq!(points[3], (0, 3));
278 assert_eq!(points[4], (0, 4));
279 assert_eq!(points[5], (0, 5));
280 assert_eq!(points[6], (0, 6));
281 assert_eq!(points[7], (0, 7));
282 assert_eq!(points[8], (0, 8));
283 assert_eq!(points[9], (0, 9));
284 assert_eq!(points[10], (0, 10));
285 }
286
287 #[test]
288 fn test_plot_line_nw() {
289 let mut points = Vec::new();
290 plot_line(0, 0, 10, 10, |x, y| points.push((x, y)));
291 assert_eq!(points.len(), 11);
292 assert_eq!(points[0], (0, 0));
293 assert_eq!(points[1], (1, 1));
294 assert_eq!(points[2], (2, 2));
295 assert_eq!(points[3], (3, 3));
296 assert_eq!(points[4], (4, 4));
297 assert_eq!(points[5], (5, 5));
298 assert_eq!(points[6], (6, 6));
299 assert_eq!(points[7], (7, 7));
300 assert_eq!(points[8], (8, 8));
301 assert_eq!(points[9], (9, 9));
302 assert_eq!(points[10], (10, 10));
303 }
304
305 #[test]
306 fn test_plot_line_ne() {
307 let mut points = Vec::new();
308 plot_line(10, 0, 0, 10, |x, y| points.push((x, y)));
309 assert_eq!(points.len(), 11);
310 assert_eq!(points[0], (10, 0));
311 assert_eq!(points[1], (9, 1));
312 assert_eq!(points[2], (8, 2));
313 assert_eq!(points[3], (7, 3));
314 assert_eq!(points[4], (6, 4));
315 assert_eq!(points[5], (5, 5));
316 assert_eq!(points[6], (4, 6));
317 assert_eq!(points[7], (3, 7));
318 assert_eq!(points[8], (2, 8));
319 assert_eq!(points[9], (1, 9));
320 assert_eq!(points[10], (0, 10));
321 }
322
323 #[test]
324 fn test_plot_line_west() {
325 let mut points = Vec::new();
326 plot_line(10, 0, 0, 0, |x, y| points.push((x, y)));
327 assert_eq!(points.len(), 11);
328 assert_eq!(points[0], (10, 0));
329 assert_eq!(points[1], (9, 0));
330 assert_eq!(points[2], (8, 0));
331 assert_eq!(points[3], (7, 0));
332 assert_eq!(points[4], (6, 0));
333 assert_eq!(points[5], (5, 0));
334 assert_eq!(points[6], (4, 0));
335 assert_eq!(points[7], (3, 0));
336 assert_eq!(points[8], (2, 0));
337 assert_eq!(points[9], (1, 0));
338 assert_eq!(points[10], (0, 0));
339 }
340
341 #[test]
342 fn test_plot_line_east() {
343 let mut points = Vec::new();
344 plot_line(0, 0, 10, 0, |x, y| points.push((x, y)));
345 assert_eq!(points.len(), 11);
346 assert_eq!(points[0], (0, 0));
347 assert_eq!(points[1], (1, 0));
348 assert_eq!(points[2], (2, 0));
349 assert_eq!(points[3], (3, 0));
350 assert_eq!(points[4], (4, 0));
351 assert_eq!(points[5], (5, 0));
352 assert_eq!(points[6], (6, 0));
353 assert_eq!(points[7], (7, 0));
354 assert_eq!(points[8], (8, 0));
355 assert_eq!(points[9], (9, 0));
356 assert_eq!(points[10], (10, 0));
357 }
358
359 #[test]
360 fn test_plot_line_sw() {
361 let mut points = Vec::new();
362 plot_line(0, 10, 10, 0, |x, y| points.push((x, y)));
363 assert_eq!(points.len(), 11);
364 assert_eq!(points[0], (0, 10));
365 assert_eq!(points[1], (1, 9));
366 assert_eq!(points[2], (2, 8));
367 assert_eq!(points[3], (3, 7));
368 assert_eq!(points[4], (4, 6));
369 assert_eq!(points[5], (5, 5));
370 assert_eq!(points[6], (6, 4));
371 assert_eq!(points[7], (7, 3));
372 assert_eq!(points[8], (8, 2));
373 assert_eq!(points[9], (9, 1));
374 assert_eq!(points[10], (10, 0));
375 }
376
377 #[test]
378 fn test_plot_line_se() {
379 let mut points = Vec::new();
380 plot_line(10, 10, 0, 0, |x, y| points.push((x, y)));
381 assert_eq!(points.len(), 11);
382 assert_eq!(points[0], (10, 10));
383 assert_eq!(points[1], (9, 9));
384 assert_eq!(points[2], (8, 8));
385 assert_eq!(points[3], (7, 7));
386 assert_eq!(points[4], (6, 6));
387 assert_eq!(points[5], (5, 5));
388 assert_eq!(points[6], (4, 4));
389 assert_eq!(points[7], (3, 3));
390 assert_eq!(points[8], (2, 2));
391 assert_eq!(points[9], (1, 1));
392 assert_eq!(points[10], (0, 0));
393 }
394
395 #[test]
396 fn test_plot_line_south() {
397 let mut points = Vec::new();
398 plot_line(0, 10, 0, 0, |x, y| points.push((x, y)));
399 assert_eq!(points.len(), 11);
400 assert_eq!(points[0], (0, 10));
401 assert_eq!(points[1], (0, 9));
402 assert_eq!(points[2], (0, 8));
403 assert_eq!(points[3], (0, 7));
404 assert_eq!(points[4], (0, 6));
405 assert_eq!(points[5], (0, 5));
406 assert_eq!(points[6], (0, 4));
407 assert_eq!(points[7], (0, 3));
408 assert_eq!(points[8], (0, 2));
409 assert_eq!(points[9], (0, 1));
410 assert_eq!(points[10], (0, 0));
411 }
412
413 fn iters_for_line(line: &ILine) -> Vec<LinePixelIterator> {
414 let mut iters = vec![LinePixelIterator::Angle(AngleLineIterator::new(line))];
415 if let Some(axis_line_iter) = AxisLineIterator::new(line) {
416 iters.push(LinePixelIterator::Axis(axis_line_iter));
417 }
418 iters
419 }
420
421 #[test]
422 fn test_iterate_line() {
423 #[derive(Debug)]
424 struct TestCase {
425 line: ILine,
426 unit: IVec2,
427 }
428
429 let test_cases = vec![
430 TestCase {
431 line: iline((0, 0), (0, 10)), unit: (0, 1).into(),
433 },
434 TestCase {
435 line: iline((0, 0), (10, 10)), unit: (1, 1).into(),
437 },
438 TestCase {
439 line: iline((0, 0), (10, 0)), unit: (1, 0).into(),
441 },
442 TestCase {
443 line: iline((0, 0), (10, -10)), unit: (1, -1).into(),
445 },
446 TestCase {
447 line: iline((0, 0), (0, -10)), unit: (0, -1).into(),
449 },
450 TestCase {
451 line: iline((0, 0), (-10, -10)), unit: (-1, -1).into(),
453 },
454 TestCase {
455 line: iline((0, 0), (-10, 0)), unit: (-1, 0).into(),
457 },
458 TestCase {
459 line: iline((0, 0), (-10, 10)), unit: (-1, 1).into(),
461 },
462 ];
463
464 for test_case in test_cases {
465 let iters = iters_for_line(&test_case.line);
466 for mut iter in iters {
467 let mut current = IVec2::default();
468 while let Some(p) = iter.peek() {
469 assert_eq!(p, current, "{:?}, Iter: {:?}", test_case, iter);
470 let n = iter.next().unwrap();
471 assert_eq!(n, current, "{:?}, Iter: {:?}", test_case, iter);
472
473 current += test_case.unit;
474 }
475 assert_eq!(iter.peek(), None, "{:?}, Iter: {:?}", test_case, iter);
476 assert_eq!(iter.peek(), None, "{:?}, Iter: {:?}", test_case, iter);
477 assert_eq!(iter.next(), None, "{:?}, Iter: {:?}", test_case, iter);
478 assert_eq!(iter.next(), None, "{:?}, Iter: {:?}", test_case, iter);
479 }
480 }
481 }
482
483 #[test]
484 fn test_seek_bounds() {
485 #[derive(Debug)]
486 struct TestCase {
487 name: String,
488 line: ILine,
489 seek_bounds_ops: Vec<SeekBoundsOp>,
490 }
491
492 #[derive(Debug)]
493 struct SeekBoundsOp {
494 bounds: IRect,
495 expected_result: Option<IVec2>,
496 expected_next: Option<IVec2>,
497 }
498
499 let test_cases = vec![
500 TestCase {
501 name: "N".to_string(),
502 line: iline((0, 0), (0, 10)),
503 seek_bounds_ops: vec![
504 SeekBoundsOp {
505 bounds: IRect::new(0, 0, 2, 2),
506 expected_result: Some((0, 1).into()),
507 expected_next: Some((0, 2).into()),
508 },
509 SeekBoundsOp {
510 bounds: IRect::new(0, 2, 4, 6),
511 expected_result: Some((0, 5).into()),
512 expected_next: Some((0, 6).into()),
513 },
514 SeekBoundsOp {
515 bounds: IRect::new(0, 6, 6, 12),
516 expected_result: Some((0, 10).into()),
517 expected_next: None,
518 },
519 ],
520 },
521 TestCase {
522 name: "E".to_string(),
523 line: iline((0, 0), (10, 0)),
524 seek_bounds_ops: vec![
525 SeekBoundsOp {
526 bounds: IRect::new(0, 0, 2, 2),
527 expected_result: Some((1, 0).into()),
528 expected_next: Some((2, 0).into()),
529 },
530 SeekBoundsOp {
531 bounds: IRect::new(2, 0, 6, 4),
532 expected_result: Some((5, 0).into()),
533 expected_next: Some((6, 0).into()),
534 },
535 SeekBoundsOp {
536 bounds: IRect::new(6, 0, 12, 6),
537 expected_result: Some((10, 0).into()),
538 expected_next: None,
539 },
540 ],
541 },
542 TestCase {
543 name: "S".to_string(),
544 line: iline((0, 0), (0, -10)),
545 seek_bounds_ops: vec![
546 SeekBoundsOp {
547 bounds: IRect::new(0, -2, 2, 0),
548 expected_result: Some((0, -2).into()),
549 expected_next: Some((0, -3).into()),
550 },
551 SeekBoundsOp {
552 bounds: IRect::new(0, -6, 4, -2),
553 expected_result: Some((0, -6).into()),
554 expected_next: Some((0, -7).into()),
555 },
556 SeekBoundsOp {
557 bounds: IRect::new(0, -12, 6, -6),
558 expected_result: Some((0, -10).into()),
559 expected_next: None,
560 },
561 ],
562 },
563 TestCase {
564 name: "W".to_string(),
565 line: iline((0, 0), (-10, 0)),
566 seek_bounds_ops: vec![
567 SeekBoundsOp {
568 bounds: IRect::new(-2, 0, 0, 2),
569 expected_result: Some((-2, 0).into()),
570 expected_next: Some((-3, 0).into()),
571 },
572 SeekBoundsOp {
573 bounds: IRect::new(-6, 0, -2, 4),
574 expected_result: Some((-6, 0).into()),
575 expected_next: Some((-7, 0).into()),
576 },
577 SeekBoundsOp {
578 bounds: IRect::new(-12, 0, -6, 6),
579 expected_result: Some((-10, 0).into()),
580 expected_next: None,
581 },
582 ],
583 },
584 TestCase {
585 name: "NE".to_string(),
586 line: iline((0, 0), (10, 10)),
587 seek_bounds_ops: vec![
588 SeekBoundsOp {
589 bounds: IRect::new(0, 0, 2, 2),
590 expected_result: Some((1, 1).into()),
591 expected_next: Some((2, 2).into()),
592 },
593 SeekBoundsOp {
594 bounds: IRect::new(2, 2, 6, 6),
595 expected_result: Some((5, 5).into()),
596 expected_next: Some((6, 6).into()),
597 },
598 SeekBoundsOp {
599 bounds: IRect::new(6, 6, 12, 12),
600 expected_result: Some((10, 10).into()),
601 expected_next: None,
602 },
603 ],
604 },
605 TestCase {
606 name: "NW".to_string(),
607 line: iline((10, 0), (0, 10)),
608 seek_bounds_ops: vec![
609 SeekBoundsOp {
610 bounds: IRect::new(8, 0, 10, 2),
611 expected_result: Some((9, 1).into()),
612 expected_next: Some((8, 2).into()),
613 },
614 SeekBoundsOp {
615 bounds: IRect::new(4, 2, 8, 6),
616 expected_result: Some((5, 5).into()),
617 expected_next: Some((4, 6).into()),
618 },
619 SeekBoundsOp {
620 bounds: IRect::new(-2, 6, 4, 12),
621 expected_result: Some((0, 10).into()),
622 expected_next: None,
623 },
624 ],
625 },
626 TestCase {
627 name: "SW".to_string(),
628 line: iline((0, 0), (-10, -10)),
629 seek_bounds_ops: vec![
630 SeekBoundsOp {
631 bounds: IRect::new(-2, -2, 0, 0),
632 expected_result: Some((-2, -2).into()),
633 expected_next: Some((-3, -3).into()),
634 },
635 SeekBoundsOp {
636 bounds: IRect::new(-6, -6, -2, -2),
637 expected_result: Some((-6, -6).into()),
638 expected_next: Some((-7, -7).into()),
639 },
640 SeekBoundsOp {
641 bounds: IRect::new(-12, -12, -6, -6),
642 expected_result: Some((-10, -10).into()),
643 expected_next: None,
644 },
645 ],
646 },
647 TestCase {
648 name: "SE".to_string(),
649 line: iline((0, 0), (10, -10)),
650 seek_bounds_ops: vec![
651 SeekBoundsOp {
652 bounds: IRect::new(0, -2, 2, 0),
653 expected_result: Some((1, -1).into()),
654 expected_next: Some((2, -2).into()),
655 },
656 SeekBoundsOp {
657 bounds: IRect::new(2, -6, 6, -2),
658 expected_result: Some((5, -5).into()),
659 expected_next: Some((6, -6).into()),
660 },
661 SeekBoundsOp {
662 bounds: IRect::new(6, -12, 12, -6),
663 expected_result: Some((10, -10).into()),
664 expected_next: None,
665 },
666 ],
667 },
668 ];
669
670 for test_case in test_cases {
671 let iters = iters_for_line(&test_case.line);
672 for mut iter in iters {
673 for op in &test_case.seek_bounds_ops {
674 let p = iter.seek_bounds(&op.bounds);
675 assert_eq!(
676 p, op.expected_result,
677 "{}: Iter: {:?} Result: Line: {:?}, op: {:?}",
678 &test_case.name, &iter, &test_case.line, op
679 );
680 assert_eq!(
681 iter.next(),
682 op.expected_next,
683 "{}: Iter: {:?} Next: Line: {:?}, op: {:?}",
684 &test_case.name,
685 &iter,
686 &test_case.line,
687 op
688 );
689 }
690 }
691 }
692 }
693
694 #[test]
695 fn test_angle_line_iterator() {
696 let test_cases = vec![
697 (0, 10, 0, 0),
698 (10, 0, 0, 0),
699 (0, 0, 10, 0),
700 (10, 10, 0, 0),
701 (0, 10, 0, 0),
702 (5, 5, 20, 10),
703 (10, 5, 5, 20),
704 (0, 0, 0, 0),
705 (0, 0, 10, 10),
706 (0, 0, -10, 10),
707 (0, 0, -10, -10),
708 (0, 0, 10, -10),
709 ];
710 for test_case in test_cases {
711 let line = iline(
712 IVec2::new(test_case.0, test_case.1),
713 IVec2::new(test_case.2, test_case.3),
714 );
715 let mut it = AngleLineIterator::new(&line);
716 plot_line(
717 test_case.0,
718 test_case.1,
719 test_case.2,
720 test_case.3,
721 |x, y| assert_eq!(it.next(), Some((x, y).into())),
722 );
723 assert_eq!(it.next(), None);
724 assert_eq!(it.next(), None);
725 }
726 }
727}