gistools/geometry/tools/lines/
intersections.rs1use crate::geometry::orient2d;
2use alloc::fmt::Debug;
3use libm::atan2;
4use s2json::{GetXY, NewXY, Point};
5
6#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct IntersectionOfSegments<Q: NewXY> {
10 pub point: Q,
12 pub u: f64,
14 pub t: f64,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq)]
21pub struct IntersectionOfSegmentsRobust<Q: NewXY> {
22 pub point: Q,
24 pub u: f64,
26 pub t: f64,
28 pub u_vec: Q,
30 pub t_vec: Q,
32 pub u_angle: f64,
34 pub t_angle: f64,
36}
37impl<Q: NewXY> IntersectionOfSegmentsRobust<Q> {
38 #[allow(clippy::too_many_arguments)]
40 pub fn new(
41 x: f64,
42 y: f64,
43 u: f64,
44 t: f64,
45 u_vec: Q,
46 t_vec: Q,
47 u_angle: f64,
48 t_angle: f64,
49 ) -> Self {
50 Self { point: Q::new_xy(x, y), u, t, u_vec, t_vec, u_angle, t_angle }
51 }
52}
53
54pub fn intersection_of_segments<P: GetXY, Q: NewXY>(
65 a: (&P, &P),
66 b: (&P, &P),
67) -> Option<IntersectionOfSegments<Q>> {
68 let (p, p2) = a;
69 let (q, q2) = b;
70
71 let r = Point::new_xy(p2.x() - p.x(), p2.y() - p.y());
72 let s = Point::new_xy(q2.x() - q.x(), q2.y() - q.y());
73
74 let cross = r.x() * s.y() - r.y() * s.x();
75 if cross == 0. {
76 return None;
77 }
78
79 let u = ((q.x() - p.x()) * s.y() - (q.y() - p.y()) * s.x()) / cross;
80 let t = ((q.x() - p.x()) * r.y() - (q.y() - p.y()) * r.x()) / cross;
81
82 if (0. ..=1.).contains(&t) && (0. ..=1.).contains(&u) {
83 Some(IntersectionOfSegments {
84 point: Q::new_xy(p.x() + u * r.x(), p.y() + u * r.y()),
85 u,
86 t,
87 })
88 } else {
89 None
90 }
91}
92
93pub fn intersection_of_segments_robust<P: GetXY + PartialEq, Q: NewXY + Clone>(
114 a: (&P, &P),
115 b: (&P, &P),
116 same_ring: bool,
117) -> Option<IntersectionOfSegmentsRobust<Q>> {
118 let (x1, y1) = a.0.xy();
119 let (x2, y2) = a.1.xy();
120 let (x3, y3) = b.0.xy();
121 let (x4, y4) = b.1.xy();
122 let (dx_a, dy_a) = (x2 - x1, y2 - y1);
123 let (dx_b, dy_b) = (x4 - x3, y4 - y3);
124 let (dx_c, dy_c) = (x1 - x3, y1 - y3);
125
126 if (dx_a == 0. && dy_a == 0.) || (dx_b == 0. && dy_b == 0.) {
128 return None;
129 }
130
131 let u_angle = if dx_a == 0. && dy_a == 0. { 0. } else { atan2(dy_a, dx_a) };
133 let t_angle = if dx_b == 0. && dy_b == 0. { 0. } else { atan2(dy_b, dx_b) };
134
135 if same_ring {
136 if a.1 == b.0 || a.1 == b.1 || a.0 == b.0 || a.0 == b.1 {
137 return None;
138 }
139 } else {
140 let zero = Q::new_xy(0., 0.);
141 if a.1 == b.0 {
142 let u_vec = Q::new_xy(dx_a, dy_a);
143 return Some(IntersectionOfSegmentsRobust::new(
144 x2, y2, 1., 0., u_vec, zero, u_angle, t_angle,
145 ));
146 }
147 if a.1 == b.1 {
148 let u_vec = Q::new_xy(dx_a, dy_a);
149 let t_vec = Q::new_xy(dx_b, dy_b);
150 return Some(IntersectionOfSegmentsRobust::new(
151 x2, y2, 1., 1., u_vec, t_vec, u_angle, t_angle,
152 ));
153 }
154 if a.0 == b.0 {
155 let zero_2 = zero.clone();
156 return Some(IntersectionOfSegmentsRobust::new(
157 x1, y1, 0., 0., zero, zero_2, u_angle, t_angle,
158 ));
159 }
160 if a.0 == b.1 {
161 let t_vec = Q::new_xy(dx_b, dy_b);
162 return Some(IntersectionOfSegmentsRobust::new(
163 x1, y1, 0., 1., zero, t_vec, u_angle, t_angle,
164 ));
165 }
166 }
167
168 let denom = dy_b * dx_a - dx_b * dy_a;
170 if denom == 0. {
171 return None;
172 }
173 let orient1 = orient2d(x1, y1, x2, y2, x3, y3);
174 let orient2 = orient2d(x1, y1, x2, y2, x4, y4);
175 if (orient1 > 0. && orient2 > 0.) || (orient1 < 0. && orient2 < 0.) {
176 return None;
177 }
178
179 let nume_a = dx_b * dy_c - dy_b * dx_c;
181 let nume_b = dx_a * dy_c - dy_a * dx_c;
182 let u_a = nume_a / denom;
183 let u_b = nume_b / denom;
184
185 if (0. ..=1.).contains(&u_a) && (0. ..=1.).contains(&u_b) {
186 let mut x = x1 + u_a * dx_a;
187 let mut y = y1 + u_a * dy_a;
188 let u_vec = Q::new_xy(u_a * dx_a, u_a * dy_a);
189 let t_vec = Q::new_xy(u_b * dx_b, u_b * dy_b);
190 if u_a != 0. && u_a != 1. && u_b != 0. && u_b != 1. {
193 if u_a <= 0.5 && x == x1 && y == y1 {
194 if dx_a != 0. {
195 x = if dx_a > 0. { x.next_up() } else { x.next_down() };
196 }
197 if dy_a != 0. {
198 y = if dy_a > 0. { y.next_up() } else { y.next_down() };
199 }
200 } else if u_a > 0.5 && x == x2 && y == y2 {
201 if dx_a != 0. {
202 x = if dx_a < 0. { x.next_up() } else { x.next_down() };
203 }
204 if dy_a != 0. {
205 y = if dy_a < 0. { y.next_up() } else { y.next_down() };
206 }
207 } else if u_b <= 0.5 && x == x3 && y == y3 {
208 if dx_b != 0. {
209 x = if dx_b > 0. { x.next_up() } else { x.next_down() };
210 }
211 if dy_b != 0. {
212 y = if dy_b > 0. { y.next_up() } else { y.next_down() };
213 }
214 } else if u_b > 0.5 && x == x4 && y == y4 {
215 if dx_b != 0. {
216 x = if dx_b < 0. { x.next_up() } else { x.next_down() };
217 }
218 if dy_b != 0. {
219 y = if dy_b < 0. { y.next_up() } else { y.next_down() };
220 }
221 }
222 }
223 Some(IntersectionOfSegmentsRobust::new(x, y, u_a, u_b, u_vec, t_vec, u_angle, t_angle))
224 } else {
225 None
226 }
227}