1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! An iterator over all line intersections with a given scanline.

use crate::{
    geometry::Point,
    primitives::common::{LineJoin, Scanline, StrokeOffset, ThickSegment},
};

/// Scanline intersections iterator.
///
/// This iterator returns multiple `Line`s corresponding to the filled in areas of a polyline
/// defined by the `points` parameter.
///
/// The result is one line of a filled polygon.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
pub struct ScanlineIntersections<'a> {
    points: &'a [Point],
    remaining_points: &'a [Point],
    next_start_join: Option<LineJoin>,
    width: u32,
    scanline: Scanline,
}

const EMPTY: &[Point; 3] = &[Point::zero(); 3];

impl<'a> ScanlineIntersections<'a> {
    /// New
    pub fn new(points: &'a [Point], width: u32, scanline_y: i32) -> Self {
        let next_start_join = match points {
            [first, second, ..] => {
                Some(LineJoin::start(*first, *second, width, StrokeOffset::None))
            }
            _ => None,
        };

        Self {
            next_start_join,
            width,
            points,
            remaining_points: points,
            scanline: Scanline::new_empty(scanline_y),
        }
    }

    /// Empty scanline iterator.
    pub(in crate::primitives) const fn empty() -> Self {
        Self {
            next_start_join: None,
            width: 0,
            points: EMPTY,
            remaining_points: EMPTY,
            scanline: Scanline::new_empty(0),
        }
    }

    /// Reset scanline iterator with a new scanline.
    pub(in crate::primitives) fn reset_with_new_scanline(&mut self, scanline_y: i32) {
        *self = Self::new(self.points, self.width, scanline_y);
    }

    fn next_segment(&mut self) -> Option<ThickSegment> {
        let start_join = self.next_start_join?;

        let end_join = match self.remaining_points {
            [start, mid, end, ..] => {
                LineJoin::from_points(*start, *mid, *end, self.width, StrokeOffset::None)
            }
            [start, end] => LineJoin::end(*start, *end, self.width, StrokeOffset::None),
            _ => return None,
        };

        self.remaining_points = self.remaining_points.get(1..)?;

        let segment = ThickSegment::new(start_join, end_join);

        self.next_start_join = Some(end_join);

        Some(segment)
    }
}

/// This iterator loops through all scanline intersections for all segments. If two intersections
/// are adjacent or overlapping, an accumulator line is extended. This repeats until the next
/// intersection does not touch the current accumulator. At this point, the accumulated line
/// segment is returned, and is reset to the next segment.
///
/// This process reduces the number of draw calls for adjacent scanlines, whilst preventing overdraw
/// from overlapping scanline segments.
///
/// ```text
/// # Adjacent - merge
/// A---AB+++B
///     ⇓
/// A--------A
///
/// # Overlapping - merge
/// A---B+++A+++B
///      ⇓
/// A-----------A
///
/// # Separate - leave alone
/// A---A B---B
///      ⇓
/// A---A B---B
/// ```
impl<'a> Iterator for ScanlineIntersections<'a> {
    type Item = Scanline;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(segment) = self.next_segment() {
            let next_scanline = segment.intersection(self.scanline.y);

            if !self.scanline.try_extend(&next_scanline) {
                let ret = self.scanline.clone();
                self.scanline = next_scanline;

                return Some(ret);
            }
        }

        // No more segments - return the final accumulated line.
        self.scanline.try_take()
    }
}