1use nalgebra::{RealField, SVector, Scalar, Vector2};
22use num_traits::{One, Signed, Zero};
23use rectutils::{Number, Rect};
24
25pub type LineSegment2<T> = LineSegment<T, 2>;
27pub type LineSegment3<T> = LineSegment<T, 3>;
29
30#[derive(Clone, Debug)]
32pub struct LineSegment<T, const D: usize> {
33 pub start: SVector<T, D>,
35 pub end: SVector<T, D>,
37}
38
39impl<T, const D: usize> LineSegment<T, D>
40where
41 T: Zero + One + Scalar + RealField,
42{
43 pub fn new(start: &SVector<T, D>, end: &SVector<T, D>) -> Self {
45 Self {
46 start: start.clone_owned(),
47 end: end.clone_owned(),
48 }
49 }
50 pub fn swapped(&self) -> Self {
52 Self::new(&self.end, &self.start)
53 }
54 pub fn is_degenerate(&self) -> bool {
56 self.start == self.end
57 }
58 pub fn interpolate(&self, t: T) -> SVector<T, D> {
64 self.start.lerp(&self.end, t)
65 }
66 pub fn interpolate_clamped(&self, t: T) -> SVector<T, D> {
70 self.interpolate(t.clamp(<T as Zero>::zero(), <T as One>::one()))
71 }
72 pub fn vector(&self) -> SVector<T, D> {
74 self.end.clone() - self.start.clone()
75 }
76 pub fn length(&self) -> T {
78 self.vector().norm()
79 }
80 pub fn length_squared(&self) -> T {
82 self.vector().norm_squared()
83 }
84 pub fn nearest_t(&self, point: &SVector<T, D>) -> T {
88 let v = self.vector();
89 let u = self.start.clone() - point;
90 let n2 = v.norm_squared();
91 if n2.is_zero() {
92 return T::zero();
93 }
94 -v.dot(&u) / n2
95 }
96 pub fn nearest_point(&self, point: &SVector<T, D>) -> SVector<T, D> {
98 self.interpolate_clamped(self.nearest_t(point))
99 }
100 pub fn distance_squared(&self, point: &SVector<T, D>) -> T {
102 (point - self.nearest_point(point)).norm_squared()
103 }
104 pub fn distance(&self, point: &SVector<T, D>) -> T {
106 (point - self.nearest_point(point)).norm()
107 }
108}
109
110impl<T> LineSegment2<T>
111where
112 T: Zero + One + Scalar + RealField,
113{
114 pub fn bounds(&self) -> Rect<T>
116 where
117 T: Number,
118 {
119 Rect::from_points(self.start, self.end)
120 }
121 pub fn collinearity(&self, point: &Vector2<T>) -> T {
126 let v = self.vector();
127 let u = self.start.clone() - point;
128 v.x.clone() * u.y.clone() - u.x.clone() * v.y.clone()
129 }
130 pub fn intersects(&self, other: &LineSegment2<T>) -> bool {
132 fn pos<T>(t: &T) -> bool
133 where
134 T: Zero + Signed,
135 {
136 t.is_positive() && !t.is_zero()
137 }
138 fn neg<T>(t: &T) -> bool
139 where
140 T: Zero + Signed,
141 {
142 t.is_negative() && !t.is_zero()
143 }
144 let o1 = self.collinearity(&other.start);
145 let o2 = self.collinearity(&other.end);
146 let s1 = other.collinearity(&self.start);
147 let s2 = other.collinearity(&self.end);
148 if neg(&s1) && neg(&s2) || pos(&s1) && pos(&s2) {
150 return false;
151 }
152 if neg(&o1) && neg(&o2) || pos(&o1) && pos(&o2) {
154 return false;
155 }
156 true
157 }
158}
159
160#[cfg(test)]
161mod test {
162 use super::*;
163 use nalgebra::Vector2;
164 #[test]
165 fn nearest_at_start() {
166 let segment = LineSegment2::new(&Vector2::new(0.0, 0.0), &Vector2::new(1.0, 2.0));
167 assert_eq!(segment.nearest_t(&Vector2::new(-1.0, -1.0)).max(0.0), 0.0);
168 assert_eq!(
169 segment.nearest_point(&Vector2::new(-1.0, -1.0)),
170 Vector2::new(0.0, 0.0)
171 );
172 assert_eq!(segment.distance_squared(&Vector2::new(-1.0, -1.0)), 2.0);
173 assert_eq!(segment.distance(&Vector2::new(-1.0, 0.0)), 1.0);
174 }
175 #[test]
176 fn nearest_at_end() {
177 let segment = LineSegment2::new(&Vector2::new(0.0, 0.0), &Vector2::new(1.0, 2.0));
178 assert_eq!(segment.nearest_t(&Vector2::new(2.0, 2.0)).min(1.0), 1.0);
179 assert_eq!(
180 segment.nearest_point(&Vector2::new(2.0, 2.0)),
181 Vector2::new(1.0, 2.0)
182 );
183 assert_eq!(segment.distance_squared(&Vector2::new(3.0, 2.0)), 4.0);
184 assert_eq!(segment.distance(&Vector2::new(3.0, 2.0)), 2.0);
185 }
186 #[test]
187 fn nearest_in_middle() {
188 let segment = LineSegment2::new(&Vector2::new(0.0, 0.0), &Vector2::new(1.0, 2.0));
189 assert_eq!(segment.nearest_t(&Vector2::new(2.5, 0.0)), 0.5);
190 assert_eq!(
191 segment.nearest_point(&Vector2::new(2.5, 0.0)),
192 Vector2::new(0.5, 1.0)
193 );
194 assert_eq!(segment.distance_squared(&Vector2::new(2.5, 0.0)), 5.0);
195 }
196 #[test]
197 fn length() {
198 let segment = LineSegment2::new(&Vector2::new(0.0, 0.0), &Vector2::new(4.0, 3.0));
199 assert_eq!(segment.length_squared(), 25.0);
200 assert_eq!(segment.length(), 5.0);
201 }
202 #[test]
203 fn degenerate() {
204 let segment = LineSegment2::new(&Vector2::new(1.0, 2.0), &Vector2::new(1.0, 2.0));
205 assert!(segment.is_degenerate());
206 assert_eq!(segment.length_squared(), 0.0);
207 assert_eq!(segment.length(), 0.0);
208 }
209 #[test]
210 fn collinear() {
211 let segment = LineSegment2::new(&Vector2::new(0.0, 0.0), &Vector2::new(1.0, 2.0));
212 assert_eq!(segment.collinearity(&Vector2::new(2.0, 4.0)), 0.0);
213 assert_eq!(segment.collinearity(&Vector2::new(0.0, 0.0)), 0.0);
214 assert_eq!(segment.collinearity(&Vector2::new(1.0, 2.0)), 0.0);
215 assert!(
216 segment.collinearity(&Vector2::new(1.0, 5.0)) < 0.0,
217 "{} >= 0.0",
218 segment.collinearity(&Vector2::new(1.0, 5.0))
219 );
220 assert!(
221 segment.collinearity(&Vector2::new(1.0, 3.0)) < 0.0,
222 "{} >= 0.0",
223 segment.collinearity(&Vector2::new(1.0, 3.0))
224 );
225 assert!(
226 segment.collinearity(&Vector2::new(1.0, 1.0)) > 0.0,
227 "{} <= 0.0",
228 segment.collinearity(&Vector2::new(1.0, 1.0))
229 );
230 assert!(
231 segment.collinearity(&Vector2::new(-1.0, -5.0)) > 0.0,
232 "{} <= 0.0",
233 segment.collinearity(&Vector2::new(-1.0, -5.0))
234 );
235 }
236 #[test]
237 fn intersects() {
238 let a = LineSegment::new(&Vector2::new(1.0, 2.0), &Vector2::new(3.0, 1.0));
239 let b = LineSegment::new(&Vector2::new(2.0, 0.0), &Vector2::new(2.5, 3.0));
240 let c = LineSegment::new(&Vector2::new(1.0, 2.0), &Vector2::new(-3.0, 1.0));
241 assert!(a.intersects(&b));
242 assert!(a.intersects(&c));
243 assert!(b.intersects(&a));
244 assert!(c.intersects(&a));
245 assert!(a.swapped().intersects(&b));
246 assert!(a.swapped().intersects(&c));
247 }
248 #[test]
249 fn not_intersects() {
250 let a = LineSegment::new(&Vector2::new(1.0, 2.0), &Vector2::new(3.0, 1.0));
251 let b = LineSegment::new(&Vector2::new(0.0, 0.0), &Vector2::new(-1.0, 6.0));
252 let c = LineSegment::new(&Vector2::new(2.0, 0.0), &Vector2::new(2.0, -1.0));
253 assert!(!a.intersects(&b));
254 assert!(!b.intersects(&c));
255 assert!(!c.intersects(&a));
256 assert!(!b.intersects(&a));
257 assert!(!c.intersects(&b));
258 assert!(!a.intersects(&c));
259 assert!(!a.swapped().intersects(&b));
260 assert!(!b.swapped().intersects(&c));
261 assert!(!c.swapped().intersects(&a));
262 }
263}