embedded_graphics/primitives/common/
thick_segment.rs

1//! A line segment constructed from two line joints.
2
3use crate::{
4    geometry::Dimensions,
5    primitives::{
6        common::{LineJoin, Scanline},
7        Line, Rectangle,
8    },
9};
10
11#[derive(Debug, Clone, Copy)]
12pub struct ThickSegment {
13    start_join: LineJoin,
14    end_join: LineJoin,
15}
16
17impl ThickSegment {
18    /// Create a new thick segment from two joints.
19    pub const fn new(start_join: LineJoin, end_join: LineJoin) -> Self {
20        Self {
21            start_join,
22            end_join,
23        }
24    }
25
26    /// Check whether the thick segment is thick or not.
27    pub fn is_skeleton(&self) -> bool {
28        self.start_join.first_edge_end.left == self.start_join.first_edge_end.right
29    }
30
31    /// Get the right/left edges of this line segment.
32    const fn edges(&self) -> (Line, Line) {
33        (
34            Line::new(
35                self.start_join.second_edge_start.right,
36                self.end_join.first_edge_end.right,
37            ),
38            Line::new(
39                self.end_join.first_edge_end.left,
40                self.start_join.second_edge_start.left,
41            ),
42        )
43    }
44
45    /// Get the bounding box containing the left/right edges of the segment.
46    ///
47    /// Note that this does not include any bevel/cap lines as returned by `perimeter` which is why
48    /// this is not `impl Dimensions`. These lines don't need to be included as other segments
49    /// in the polyline will expand the bounding box to the right place anyway.
50    pub fn edges_bounding_box(&self) -> Rectangle {
51        let (right, left) = self.edges();
52
53        if self.is_skeleton() {
54            return left.bounding_box();
55        }
56
57        Rectangle::with_corners(
58            right
59                .start
60                .component_min(right.end)
61                .component_min(left.start)
62                .component_min(left.end),
63            right
64                .start
65                .component_max(right.end)
66                .component_max(left.start)
67                .component_max(left.end),
68        )
69    }
70
71    pub fn intersection(&self, scanline_y: i32) -> Scanline {
72        let mut scanline = Scanline::new_empty(scanline_y);
73
74        // Single 1px line
75        if self.is_skeleton() {
76            scanline.bresenham_intersection(&self.edges().0);
77        } else {
78            let (line1, line2) = self.start_join.start_cap_lines();
79            scanline.bresenham_intersection(&line1);
80            if let Some(line2) = line2 {
81                scanline.bresenham_intersection(&line2);
82            }
83
84            let (line1, line2) = self.end_join.end_cap_lines();
85            scanline.bresenham_intersection(&line1);
86            if let Some(line2) = line2 {
87                scanline.bresenham_intersection(&line2);
88            }
89
90            let (line1, line2) = self.edges();
91            scanline.bresenham_intersection(&line1);
92            scanline.bresenham_intersection(&line2);
93        }
94
95        scanline
96    }
97}