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}
98