1 | //! Scanline iterator. |
2 | |
3 | use crate::primitives::{ |
4 | common::{PointType, Scanline, StrokeOffset}, |
5 | triangle::scanline_intersections::ScanlineIntersections, |
6 | Rectangle, Triangle, |
7 | }; |
8 | use core::ops::Range; |
9 | |
10 | /// Iterate over every scanline in the triangle's bounding box. |
11 | #[derive (Clone, Eq, PartialEq, Hash, Debug)] |
12 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
13 | pub(in crate::primitives::triangle) struct ScanlineIterator { |
14 | rows: Range<i32>, |
15 | scanline_y: i32, |
16 | intersections: ScanlineIntersections, |
17 | } |
18 | |
19 | impl ScanlineIterator { |
20 | /// New. |
21 | pub fn new( |
22 | triangle: &Triangle, |
23 | stroke_width: u32, |
24 | stroke_offset: StrokeOffset, |
25 | has_fill: bool, |
26 | bounding_box: &Rectangle, |
27 | ) -> Self { |
28 | let triangle = triangle.sorted_clockwise(); |
29 | |
30 | let mut rows = bounding_box.rows(); |
31 | |
32 | if let Some(scanline_y) = rows.next() { |
33 | let intersections = ScanlineIntersections::new( |
34 | &triangle, |
35 | stroke_width, |
36 | stroke_offset, |
37 | has_fill, |
38 | scanline_y, |
39 | ); |
40 | |
41 | Self { |
42 | rows, |
43 | scanline_y, |
44 | intersections, |
45 | } |
46 | } else { |
47 | Self::empty() |
48 | } |
49 | } |
50 | |
51 | const fn empty() -> Self { |
52 | Self { |
53 | rows: 0i32..0, |
54 | scanline_y: 0, |
55 | intersections: ScanlineIntersections::empty(), |
56 | } |
57 | } |
58 | } |
59 | |
60 | impl Iterator for ScanlineIterator { |
61 | type Item = (Scanline, PointType); |
62 | |
63 | fn next(&mut self) -> Option<Self::Item> { |
64 | self.intersections.next().or_else(|| { |
65 | self.scanline_y = self.rows.next()?; |
66 | |
67 | self.intersections.reset_with_new_scanline(self.scanline_y); |
68 | |
69 | self.intersections.next() |
70 | }) |
71 | } |
72 | } |
73 | |