1 | //! A line segment constructed from two line joints. |
2 | |
3 | use crate::{ |
4 | geometry::Dimensions, |
5 | primitives::{ |
6 | common::{LineJoin, Scanline}, |
7 | Line, Rectangle, |
8 | }, |
9 | }; |
10 | |
11 | #[derive (Debug, Clone, Copy)] |
12 | pub struct ThickSegment { |
13 | start_join: LineJoin, |
14 | end_join: LineJoin, |
15 | } |
16 | |
17 | impl 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 | |