1//! Scanline iterator.
2
3use crate::primitives::{
4 common::{PointType, Scanline, StrokeOffset},
5 triangle::scanline_intersections::ScanlineIntersections,
6 Rectangle, Triangle,
7};
8use 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))]
13pub(in crate::primitives::triangle) struct ScanlineIterator {
14 rows: Range<i32>,
15 scanline_y: i32,
16 intersections: ScanlineIntersections,
17}
18
19impl 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
60impl 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