geo/algorithm/intersects/line.rs
1use super::{point_in_rect, Intersects};
2use crate::kernels::*;
3use crate::*;
4
5impl<T> Intersects<Coord<T>> for Line<T>
6where
7 T: GeoNum,
8{
9 fn intersects(&self, rhs: &Coord<T>) -> bool {
10 // First we check if the point is collinear with the line.
11 T::Ker::orient2d(self.start, self.end, *rhs) == Orientation::Collinear
12 // In addition, the point must have _both_ coordinates
13 // within the start and end bounds.
14 && point_in_rect(*rhs, self.start, self.end)
15 }
16}
17symmetric_intersects_impl!(Coord<T>, Line<T>);
18symmetric_intersects_impl!(Line<T>, Point<T>);
19
20impl<T> Intersects<Line<T>> for Line<T>
21where
22 T: GeoNum,
23{
24 fn intersects(&self, line: &Line<T>) -> bool {
25 // Special case: self is equiv. to a point.
26 if self.start == self.end {
27 return line.intersects(&self.start);
28 }
29
30 // Precondition: start and end are distinct.
31
32 // Check if orientation of rhs.{start,end} are different
33 // with respect to self.{start,end}.
34 let check_1_1 = T::Ker::orient2d(self.start, self.end, line.start);
35 let check_1_2 = T::Ker::orient2d(self.start, self.end, line.end);
36
37 if check_1_1 != check_1_2 {
38 // Since the checks are different,
39 // rhs.{start,end} are distinct, and rhs is not
40 // collinear with self. Thus, there is exactly
41 // one point on the infinite extensions of rhs,
42 // that is collinear with self.
43
44 // By continuity, this point is not on the
45 // exterior of rhs. Now, check the same with
46 // self, rhs swapped.
47
48 let check_2_1 = T::Ker::orient2d(line.start, line.end, self.start);
49 let check_2_2 = T::Ker::orient2d(line.start, line.end, self.end);
50
51 // By similar argument, there is (exactly) one
52 // point on self, collinear with rhs. Thus,
53 // those two have to be same, and lies (interior
54 // or boundary, but not exterior) on both lines.
55 check_2_1 != check_2_2
56 } else if check_1_1 == Orientation::Collinear {
57 // Special case: collinear line segments.
58
59 // Equivalent to 4 point-line intersection
60 // checks, but removes the calls to the kernel
61 // predicates.
62 point_in_rect(line.start, self.start, self.end)
63 || point_in_rect(line.end, self.start, self.end)
64 || point_in_rect(self.end, line.start, line.end)
65 || point_in_rect(self.end, line.start, line.end)
66 } else {
67 false
68 }
69 }
70}