1use std::cmp::Eq;
2use std::cmp::Ord;
3use std::cmp::Ordering;
4use std::cmp::PartialEq;
5use std::ops::Range;
6use std::ops::RangeInclusive;
7
8use super::Point;
9
10use crate::data::point::PointSoS;
11use crate::Intersects;
12use crate::{Orientation, PolygonScalar, TotalOrd};
13use Orientation::*;
14
15#[derive(Debug, Clone, Copy, Eq, PartialEq)]
19pub enum EndPoint<T: TotalOrd> {
20 Exclusive(T),
21 Inclusive(T),
22}
23
24use EndPoint::*;
25
26impl<T: TotalOrd> EndPoint<T> {
27 pub fn inner(&self) -> &T {
28 match self {
29 Exclusive(t) => t,
30 Inclusive(t) => t,
31 }
32 }
33
34 pub fn take(self) -> T {
35 match self {
36 Exclusive(t) => t,
37 Inclusive(t) => t,
38 }
39 }
40
41 pub fn as_ref(&self) -> EndPoint<&T> {
42 match self {
43 Exclusive(t) => Exclusive(t),
44 Inclusive(t) => Inclusive(t),
45 }
46 }
47
48 pub fn is_exclusive(&self) -> bool {
49 match self {
50 Exclusive(_) => true,
51 Inclusive(_) => false,
52 }
53 }
54
55 pub fn is_inclusive(&self) -> bool {
56 !self.is_exclusive()
57 }
58
59 #[must_use]
60 pub fn leftmost(self, other: EndPoint<T>) -> EndPoint<T>
61 where
62 T: Ord,
63 {
64 match self.inner().cmp(other.inner()) {
65 Ordering::Equal => {
66 if self.is_exclusive() {
67 self
68 } else {
69 other
70 }
71 }
72 Ordering::Less => self,
73 Ordering::Greater => other,
74 }
75 }
76
77 #[must_use]
78 pub fn rightmost(self, other: EndPoint<T>) -> EndPoint<T>
79 where
80 T: Ord,
81 {
82 match self.inner().cmp(other.inner()) {
83 Ordering::Equal => {
84 if self.is_exclusive() || other.is_exclusive() {
85 Exclusive(self.take())
86 } else {
87 other
88 }
89 }
90 Ordering::Less => other,
91 Ordering::Greater => self,
92 }
93 }
94}
95
96fn inner_between<T: TotalOrd>(inner: &T, a: EndPoint<&T>, b: EndPoint<&T>) -> bool {
97 let left;
98 let right;
99 if a.inner().total_cmp(b.inner()).is_lt() {
100 left = a;
101 right = b;
102 } else {
103 left = b;
104 right = a;
105 }
106 let lhs = match left {
107 Exclusive(l) => l.total_cmp(inner).is_lt(),
108 Inclusive(l) => l.total_cmp(inner).is_le(),
109 };
110 let rhs = match right {
111 Exclusive(r) => inner.total_cmp(r).is_lt(),
112 Inclusive(r) => inner.total_cmp(r).is_le(),
113 };
114 lhs && rhs
115}
116
117#[derive(Debug, Clone, Copy)]
121pub struct LineSegment<T: TotalOrd, const N: usize = 2> {
122 pub min: EndPoint<Point<T, N>>,
123 pub max: EndPoint<Point<T, N>>,
124}
125
126impl<T: TotalOrd, const N: usize> LineSegment<T, N> {
127 pub fn new(a: EndPoint<Point<T, N>>, b: EndPoint<Point<T, N>>) -> LineSegment<T, N>
128 where
129 T: TotalOrd,
130 {
131 if a.inner() < b.inner() {
132 LineSegment { min: a, max: b }
133 } else {
134 LineSegment { min: b, max: a }
135 }
136 }
137
138 pub fn as_ref(&self) -> LineSegmentView<'_, T, N> {
139 LineSegmentView {
140 min: self.min.as_ref(),
141 max: self.max.as_ref(),
142 }
143 }
144}
145impl<T: TotalOrd> LineSegment<T> {
146 pub fn contains(&self, pt: &Point<T>) -> bool
147 where
148 T: PolygonScalar,
149 {
150 self.as_ref().contains(pt)
151 }
152}
153
154impl<T: TotalOrd, const N: usize> From<Range<Point<T, N>>> for LineSegment<T, N> {
155 fn from(range: Range<Point<T, N>>) -> LineSegment<T, N> {
156 LineSegment::new(
157 EndPoint::Inclusive(range.start),
158 EndPoint::Exclusive(range.end),
159 )
160 }
161}
162
163impl<T: TotalOrd> From<Range<(T, T)>> for LineSegment<T> {
164 fn from(range: Range<(T, T)>) -> LineSegment<T> {
165 LineSegment::new(
166 EndPoint::Inclusive(range.start.into()),
167 EndPoint::Exclusive(range.end.into()),
168 )
169 }
170}
171
172impl<T: TotalOrd, const N: usize> From<RangeInclusive<Point<T, N>>> for LineSegment<T, N> {
173 fn from(range: RangeInclusive<Point<T, N>>) -> LineSegment<T, N> {
174 let (start, end) = range.into_inner();
175 LineSegment::new(EndPoint::Inclusive(start), EndPoint::Inclusive(end))
176 }
177}
178
179#[derive(Debug, PartialEq, Eq)]
183pub struct LineSegmentView<'a, T: TotalOrd, const N: usize = 2> {
184 pub min: EndPoint<&'a Point<T, N>>,
185 pub max: EndPoint<&'a Point<T, N>>,
186}
187
188#[derive(Debug, PartialEq, Eq)]
189pub struct LineSegmentSoS<'a, T: TotalOrd, const N: usize> {
190 pub min: EndPoint<PointSoS<'a, T, N>>,
191 pub max: EndPoint<PointSoS<'a, T, N>>,
192}
193
194impl<T: TotalOrd, const N: usize> Clone for LineSegmentView<'_, T, N> {
195 fn clone(&self) -> Self {
196 *self
197 }
198}
199impl<T: TotalOrd, const N: usize> Copy for LineSegmentView<'_, T, N> {}
200
201impl<'a, T: TotalOrd, const N: usize> LineSegmentView<'a, T, N> {
202 pub fn new(
203 a: EndPoint<&'a Point<T, N>>,
204 b: EndPoint<&'a Point<T, N>>,
205 ) -> LineSegmentView<'a, T, N>
206 where
207 T: TotalOrd,
208 {
209 if a.inner() < b.inner() {
210 LineSegmentView { min: a, max: b }
211 } else {
212 LineSegmentView { min: b, max: a }
213 }
214 }
215}
216
217impl<T: TotalOrd> LineSegmentView<'_, T> {
218 pub fn contains(&self, pt: &Point<T>) -> bool
219 where
220 T: PolygonScalar,
221 {
222 Point::orient(self.min.inner(), self.max.inner(), pt).is_colinear()
223 && inner_between(pt, self.min, self.max)
224 }
225}
226
227impl<'a, T: TotalOrd, const N: usize> From<&'a Range<Point<T, N>>> for LineSegmentView<'a, T, N> {
228 fn from(range: &'a Range<Point<T, N>>) -> LineSegmentView<'a, T, N> {
229 LineSegmentView::new(
230 EndPoint::Inclusive(&range.start),
231 EndPoint::Exclusive(&range.end),
232 )
233 }
234}
235
236impl<'a, T: TotalOrd, const N: usize> From<Range<&'a Point<T, N>>> for LineSegmentView<'a, T, N> {
237 fn from(range: Range<&'a Point<T, N>>) -> LineSegmentView<'a, T, N> {
238 LineSegmentView::new(
239 EndPoint::Inclusive(range.start),
240 EndPoint::Exclusive(range.end),
241 )
242 }
243}
244
245impl<'a, T: TotalOrd, const N: usize> From<&'a RangeInclusive<Point<T, N>>>
246 for LineSegmentView<'a, T, N>
247{
248 fn from(range: &'a RangeInclusive<Point<T, N>>) -> LineSegmentView<'a, T, N> {
249 LineSegmentView::new(
250 EndPoint::Inclusive(range.start()),
251 EndPoint::Inclusive(range.end()),
252 )
253 }
254}
255
256impl<'a, T: TotalOrd, const N: usize> From<&'a LineSegment<T, N>> for LineSegmentView<'a, T, N> {
257 fn from(line: &'a LineSegment<T, N>) -> LineSegmentView<'a, T, N> {
258 line.as_ref()
259 }
260}
261
262#[derive(Debug, Eq, PartialEq)]
266pub enum ILineSegment<'a, T: TotalOrd> {
267 Crossing, Overlap(LineSegmentView<'a, T>), }
270
271impl<'a, T> Intersects for LineSegmentView<'a, T>
275where
276 T: PolygonScalar,
277{
278 type Result = ILineSegment<'a, T>;
279 fn intersect(self, other: LineSegmentView<'a, T>) -> Option<Self::Result> {
280 let a1 = self.min.inner();
281 let a2 = self.max.inner();
282 let b1 = other.min.inner();
283 let b2 = other.max.inner();
284 let l1_to_b1 = Point::orient(a1, a2, b1);
285 let l1_to_b2 = Point::orient(a1, a2, b2);
286 let l2_to_a1 = Point::orient(b1, b2, a1);
287 let l2_to_a2 = Point::orient(b1, b2, a2);
288 if l1_to_b1 == CoLinear && l1_to_b2 == CoLinear {
303 let c_min = self.min.rightmost(other.min);
304 let c_max = self.max.leftmost(other.max);
305 let order = c_min.inner().cmp(c_max.inner());
306 if order == Ordering::Less
307 || (order == Ordering::Equal && c_max.is_inclusive() && c_min.is_inclusive())
308 {
309 Some(ILineSegment::Overlap(LineSegmentView {
310 min: c_min,
311 max: c_max,
312 }))
313 } else {
314 None
315 }
316 } else if l1_to_b1 == CoLinear {
317 if other.min.is_inclusive()
319 && inner_between(other.min.inner(), self.min.as_ref(), self.max.as_ref())
320 {
321 Some(ILineSegment::Crossing)
322 } else {
323 None
324 }
325 } else if l1_to_b2 == CoLinear {
326 if other.max.is_inclusive()
327 && inner_between(other.max.inner(), self.min.as_ref(), self.max.as_ref())
328 {
329 Some(ILineSegment::Crossing)
330 } else {
331 None
332 }
333 } else if l2_to_a1 == CoLinear {
334 if self.min.is_inclusive()
335 && inner_between(self.min.inner(), other.min.as_ref(), other.max.as_ref())
336 {
337 Some(ILineSegment::Crossing)
338 } else {
339 None
340 }
341 } else if l2_to_a2 == CoLinear {
342 if self.max.is_inclusive()
343 && inner_between(self.max.inner(), other.min.as_ref(), other.max.as_ref())
344 {
345 Some(ILineSegment::Crossing)
346 } else {
347 None
348 }
349 } else if l1_to_b1 == l1_to_b2.reverse() && l2_to_a1 == l2_to_a2.reverse() {
350 Some(ILineSegment::Crossing)
351 } else {
352 None
353 }
354 }
355}
356
357impl<'a, T> Intersects for &'a LineSegment<T>
358where
359 T: PolygonScalar,
360{
361 type Result = ILineSegment<'a, T>;
362 fn intersect(self, other: &'a LineSegment<T>) -> Option<Self::Result> {
363 self.as_ref().intersect(other.as_ref())
364 }
365}
366
367impl<'a, T> Intersects for &'a Range<Point<T>>
368where
369 T: PolygonScalar,
370{
371 type Result = ILineSegment<'a, T>;
372 fn intersect(self, other: &'a Range<Point<T>>) -> Option<Self::Result> {
373 LineSegmentView::from(self).intersect(LineSegmentView::from(other))
374 }
375}
376
377impl<'a, T> Intersects for &'a RangeInclusive<Point<T>>
378where
379 T: PolygonScalar,
380{
381 type Result = ILineSegment<'a, T>;
382 fn intersect(self, other: &'a RangeInclusive<Point<T>>) -> Option<Self::Result> {
383 LineSegmentView::from(self).intersect(LineSegmentView::from(other))
384 }
385}
386
387#[cfg(test)]
391#[cfg(not(tarpaulin_include))]
392mod tests {
393 use super::*;
394 use crate::data::*;
395 use crate::Intersects;
396 use ILineSegment::*;
397
398 use test_strategy::proptest;
399
400 #[proptest]
401 fn flip_intersects_prop(pts: [i8; 8]) {
402 let [a, b, c, d, e, f, g, h] = pts;
403 let l1 = LineSegment::from((a, b)..(c, d));
404 let l2 = LineSegment::from((e, f)..(g, h));
405 assert_eq!(l1.intersect(&l2), l2.intersect(&l1));
406 }
407
408 static P1: Point<i32> = Point::new([0, 0]);
417 static P2: Point<i32> = Point::new([1, 1]);
418 static P3: Point<i32> = Point::new([1, 0]);
419 static P4: Point<i32> = Point::new([0, 1]);
420 static P5: Point<i32> = Point::new([2, 2]);
421 static P6: Point<i32> = Point::new([3, 3]);
422 static P7: Point<i32> = Point::new([0, 2]);
423
424 #[test]
425 fn line_crossing() {
426 assert_eq!((P1..P2).intersect(&(P3..P4)), Some(Crossing))
427 }
428
429 #[test]
430 fn line_not_crossing() {
431 assert_eq!((P1..P3).intersect(&(P2..P4)), None)
432 }
433
434 #[test]
435 fn endpoints_no_overlap() {
436 assert_eq!((P1..P2).intersect(&(P2..P3)), None)
437 }
438
439 #[test]
440 fn endpoints_overlap_1() {
441 assert_eq!((P2..P1).intersect(&(P2..P3)), Some(Crossing))
442 }
443
444 #[test]
445 fn endpoints_overlap_2() {
446 assert_eq!((P1..P2).intersect(&(P1..P3)), Some(Crossing))
447 }
448
449 #[test]
450 fn endpoints_overlap_3() {
451 assert_eq!(
452 (P1..=P2).intersect(&(P2..=P5)),
453 Some(Overlap(LineSegmentView::from(&(P2..=P2))))
454 )
455 }
456
457 #[test]
458 fn edges_overlap_1() {
459 assert_eq!(
460 (P1..P5).intersect(&(P2..P6)),
461 Some(Overlap(LineSegmentView::from(&(P2..P5))))
462 )
463 }
464
465 #[test]
466 fn edges_overlap_2() {
467 assert_eq!(
468 (P1..P6).intersect(&(P2..P6)),
469 Some(Overlap(LineSegmentView::from(&(P2..P6))))
470 )
471 }
472
473 #[test]
474 fn edges_overlap_3() {
475 assert_eq!(
476 (P6..P1).intersect(&(P6..P2)),
477 Some(Overlap(LineSegmentView::from(&(P6..P2))))
478 )
479 }
480
481 #[test]
482 fn edges_overlap_4() {
483 let l1 = LineSegment::new(Inclusive(P1), Exclusive(P5));
484 let l2 = LineSegment::new(Exclusive(P2), Inclusive(P6));
485 let l3 = LineSegment::new(Exclusive(P2), Exclusive(P5));
486 assert_eq!(l1.intersect(&l2), Some(Overlap(l3.as_ref())))
487 }
488
489 #[test]
490 fn edges_overlap_5() {
491 let l1 = LineSegment::new(Inclusive(P1), Inclusive(P5));
492 let l2 = LineSegment::new(Exclusive(P2), Inclusive(P6));
493 let l3 = LineSegment::new(Exclusive(P2), Inclusive(P5));
494 assert_eq!(l1.intersect(&l2), Some(Overlap(l3.as_ref())))
495 }
496
497 #[test]
498 fn edge_touch() {
499 assert_eq!((P1..P7).intersect(&(P4..P2)), Some(Crossing))
500 }
501
502 #[test]
503 fn edge_no_touch() {
504 assert_eq!((P1..P7).intersect(&(P2..P4)), None)
505 }
506
507 #[test]
508 fn subset_1() {
509 let l1 = LineSegment::new(Inclusive(P1), Inclusive(P2));
510 let l2 = LineSegment::new(Exclusive(P1), Exclusive(P2));
511 assert_eq!(l1.intersect(&l2), Some(Overlap(l2.as_ref())))
512 }
513
514 #[test]
515 fn subset_2() {
516 let l1 = LineSegment::new(Inclusive(P1), Exclusive(P2));
517 let l2 = LineSegment::new(Exclusive(P1), Inclusive(P2));
518 let l3 = LineSegment::new(Exclusive(P1), Exclusive(P2));
519 assert_eq!(l1.intersect(&l2), Some(Overlap(l3.as_ref())))
520 }
521
522 #[test]
523 fn unit_1() {
524 let a1 = Point::new([1, 0]);
525 let a2 = Point::new([1, 1]);
526 let b1 = Point::new([0, 1]);
527 let b2 = Point::new([2, 3]);
528 let l1 = LineSegment::from(a1..a2);
529 let l2 = LineSegment::from(b1..b2);
530 assert_eq!(l1.intersect(&l2), None)
531 }
532
533 #[test]
534 fn unit_2() {
535 let a1 = Point::new([1, 0]);
536 let a2 = Point::new([1, 1]);
537 let b1 = Point::new([0, 0]);
538 let b2 = Point::new([2, 3]);
539 let l1 = LineSegment::from(b2..b1);
540 let l2 = LineSegment::from(a1..a2);
541 assert_eq!(l1.intersect(&l2), None)
542 }
543
544 #[test]
545 fn unit_3() {
546 let l1 = LineSegment::from((0, 0)..(1, 0));
547 let l2 = LineSegment::from((1, 0)..(2, 0));
548 assert_eq!(l1.intersect(&l2), None)
549 }
550
551 #[test]
552 fn unit_4() {
553 let l1 = &LineSegment::from((0, 0)..(1, 0));
554 let l2 = &LineSegment::from((1, 0)..(2, 0));
555 assert_eq!(l2.intersect(l1), None);
556 assert_eq!(l1.intersect(l2), None);
557 }
558
559 #[test]
560 fn unit_5() {
561 let l1 = LineSegment::new(Inclusive((0, 0).into()), Inclusive((1, 0).into()));
562 let l2 = LineSegment::new(Inclusive((1, 0).into()), Inclusive((2, 0).into()));
563 let l3 = LineSegment::new(Inclusive((1, 0).into()), Inclusive((1, 0).into()));
564 assert_eq!(l2.intersect(&l1), Some(Overlap(l3.as_ref())))
565 }
566
567 #[test]
568 fn unit_6() {
569 let l1 = LineSegment::from((4, 0)..(3, 0));
570 let l2 = LineSegment::from((3, 0)..(1, 0));
571 assert_eq!(l1.intersect(&l2), None)
572 }
573
574 #[test]
575 fn unit_7() {
576 let l1 = LineSegment::from((0, 0)..(0, 1));
577 let l2 = LineSegment::from((1, 2)..(2, 1));
578 assert_eq!(l1.intersect(&l2), None)
579 }
580
581 #[test]
582 fn unit_8() {
583 let l1 = LineSegment::from((-106, 0)..(54, -128));
584 let l2 = LineSegment::from((-71, -28)..(31, -8));
585 assert_eq!(l1.intersect(&l2), l2.intersect(&l1));
586 }
587}