1use crate::{Point, Rect};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7#[repr(C)]
8pub struct Segment {
9 pub a: Point,
10 pub b: Point,
11}
12
13impl Segment {
14 #[inline]
15 pub const fn new(a: Point, b: Point) -> Self {
16 Self { a, b }
17 }
18
19 #[inline]
20 pub fn rect(self) -> Rect {
21 let r = unsafe { tg_geom_sys::tg_segment_rect(self.into()) };
22 r.into()
23 }
24
25 #[inline]
26 pub fn intersects_segment(self, other: Segment) -> bool {
27 unsafe { tg_geom_sys::tg_segment_intersects_segment(self.into(), other.into()) }
28 }
29}
30
31impl From<tg_geom_sys::tg_segment> for Segment {
32 #[inline]
33 fn from(s: tg_geom_sys::tg_segment) -> Self {
34 Self {
35 a: s.a.into(),
36 b: s.b.into(),
37 }
38 }
39}
40
41impl From<Segment> for tg_geom_sys::tg_segment {
42 #[inline]
43 fn from(s: Segment) -> Self {
44 Self {
45 a: s.a.into(),
46 b: s.b.into(),
47 }
48 }
49}
50
51impl From<(Point, Point)> for Segment {
52 #[inline]
53 fn from((a, b): (Point, Point)) -> Self {
54 Self { a, b }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 fn p(x: f64, y: f64) -> Point {
63 Point::new(x, y)
64 }
65
66 fn s(ax: f64, ay: f64, bx: f64, by: f64) -> Segment {
67 Segment::new(p(ax, ay), p(bx, by))
68 }
69
70 #[test]
71 fn test_segment_new() {
72 let seg = Segment::new(p(1.0, 2.0), p(3.0, 4.0));
73 assert_eq!(seg.a, p(1.0, 2.0));
74 assert_eq!(seg.b, p(3.0, 4.0));
75 }
76
77 #[test]
78 fn test_segment_rect() {
79 let seg1 = s(1.0, 2.0, 4.0, 6.0);
80 let rect1 = seg1.rect();
81 assert_eq!(rect1.min, p(1.0, 2.0));
82 assert_eq!(rect1.max, p(4.0, 6.0));
83
84 let seg2 = s(4.0, 6.0, 1.0, 2.0);
85 let rect2 = seg2.rect();
86 assert_eq!(rect2.min, p(1.0, 2.0));
87 assert_eq!(rect2.max, p(4.0, 6.0));
88
89 let seg3 = s(5.0, 5.0, 5.0, 5.0);
90 let rect3 = seg3.rect();
91 assert_eq!(rect3.min, rect3.max);
92
93 let seg4 = s(0.0, 5.0, 10.0, 5.0);
94 let rect4 = seg4.rect();
95 assert_eq!(rect4.min.y, rect4.max.y);
96
97 let seg5 = s(5.0, 0.0, 5.0, 10.0);
98 let rect5 = seg5.rect();
99 assert_eq!(rect5.min.x, rect5.max.x);
100 }
101
102 #[test]
103 fn test_segment_intersects_segment_crossing() {
104 let seg1 = s(0.0, 0.0, 1.0, 1.0);
105 let seg2 = s(0.0, 1.0, 1.0, 0.0);
106 assert!(seg1.intersects_segment(seg2));
107 }
108
109 #[test]
110 fn test_segment_intersects_segment_no_intersection() {
111 let seg1 = s(0.0, 0.0, 1.0, 1.0);
112 let seg2 = s(2.0, 2.0, 3.0, 3.0);
113 assert!(!seg1.intersects_segment(seg2));
114 }
115
116 #[test]
117 fn test_segment_intersects_segment_parallel() {
118 let seg1 = s(0.0, 0.0, 1.0, 0.0);
119 let seg2 = s(0.0, 1.0, 1.0, 1.0);
120 assert!(!seg1.intersects_segment(seg2));
121 }
122
123 #[test]
124 fn test_segment_intersects_segment_collinear_overlap() {
125 let seg1 = s(0.0, 0.0, 2.0, 0.0);
126 let seg2 = s(1.0, 0.0, 3.0, 0.0);
127 assert!(seg1.intersects_segment(seg2));
128 }
129
130 #[test]
131 fn test_segment_intersects_segment_endpoint_touch() {
132 let seg1 = s(0.0, 0.0, 1.0, 0.0);
133 let seg2 = s(1.0, 0.0, 2.0, 0.0);
134 assert!(seg1.intersects_segment(seg2));
135 }
136
137 #[test]
138 fn test_segment_intersects_segment_t_intersection() {
139 let seg1 = s(0.0, 0.0, 10.0, 0.0);
140 let seg2 = s(5.0, 0.0, 5.0, 10.0);
141 assert!(seg1.intersects_segment(seg2));
142 }
143
144 #[test]
145 fn test_segment_intersects_segment_self() {
146 let seg = s(0.0, 0.0, 1.0, 1.0);
147 assert!(seg.intersects_segment(seg));
148 }
149
150 #[test]
151 fn test_segment_intersects_segment_vertical() {
152 let seg1 = s(4.0, 4.0, 4.0, 4.0);
153 let seg2 = s(4.0, 4.0, 4.0, 4.0);
154 assert!(seg1.intersects_segment(seg2));
155
156 let seg3 = s(5.0, 0.0, 5.0, 10.0);
157 let seg4 = s(0.0, 5.0, 10.0, 5.0);
158 assert!(seg3.intersects_segment(seg4));
159 }
160
161 #[test]
162 fn test_segment_from_points() {
163 let seg: Segment = (p(1.0, 2.0), p(3.0, 4.0)).into();
164 assert_eq!(seg.a, p(1.0, 2.0));
165 assert_eq!(seg.b, p(3.0, 4.0));
166 }
167
168 #[test]
169 fn test_segment_sys_roundtrip() {
170 let seg = s(1.0, 2.0, 3.0, 4.0);
171 let sys_seg: tg_geom_sys::tg_segment = seg.into();
172 let back: Segment = sys_seg.into();
173 assert_eq!(seg, back);
174 }
175
176 #[test]
177 fn test_segment_eq() {
178 assert_eq!(s(0.0, 0.0, 1.0, 1.0), s(0.0, 0.0, 1.0, 1.0));
179 assert_ne!(s(0.0, 0.0, 1.0, 1.0), s(0.0, 0.0, 2.0, 2.0));
180 }
181
182 #[test]
183 fn test_segment_debug() {
184 let seg = s(1.0, 2.0, 3.0, 4.0);
185 let debug_str = format!("{seg:?}");
186 assert!(debug_str.contains("Segment"));
187 }
188
189 #[test]
190 fn test_segment_negative_coords() {
191 let seg = s(-5.0, -3.0, -1.0, -7.0);
192 let rect = seg.rect();
193 assert_eq!(rect.min.x, -5.0);
194 assert_eq!(rect.min.y, -7.0);
195 assert_eq!(rect.max.x, -1.0);
196 assert_eq!(rect.max.y, -3.0);
197 }
198}