1//! Scanline iterator.
2
3use core::ops::Range;
4
5use crate::{
6 pixelcolor::PixelColor,
7 primitives::{
8 common::Scanline,
9 polyline::{
10 scanline_intersections::ScanlineIntersections, styled::untranslated_bounding_box,
11 },
12 Polyline, PrimitiveStyle,
13 },
14};
15
16/// Iterate over every scanline in the polyline's bounding box.
17///
18/// Each scanline produces multiple actual `Line`s for each intersection of the thick polyline.
19#[derive(Clone, Debug)]
20#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
21pub struct ScanlineIterator<'a> {
22 rows: Range<i32>,
23 scanline_y: i32,
24 intersections: ScanlineIntersections<'a>,
25}
26
27impl<'a> ScanlineIterator<'a> {
28 /// New.
29 pub fn new<C: PixelColor>(primitive: &Polyline<'a>, style: &PrimitiveStyle<C>) -> Self {
30 debug_assert!(
31 style.stroke_width > 1,
32 "Polyline ScanlineIterator should only be used for stroke widths greater than 1"
33 );
34
35 let mut rows = untranslated_bounding_box(primitive, style).rows();
36
37 if let Some(scanline_y) = rows.next() {
38 let intersections =
39 ScanlineIntersections::new(primitive.vertices, style.stroke_width, scanline_y);
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<'a> Iterator for ScanlineIterator<'a> {
61 type Item = Scanline;
62
63 fn next(&mut self) -> Option<Self::Item> {
64 loop {
65 if let Some(next: Scanline) = self.intersections.next() {
66 if !next.is_empty() {
67 break Some(next);
68 }
69 } else {
70 self.scanline_y = self.rows.next()?;
71
72 self.intersections.reset_with_new_scanline(self.scanline_y);
73 }
74 }
75 }
76}
77