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 pub fn new(
40 x: f64,
41 y: f64,
42 u: f64,
43 t: f64,
44 u_vec: Q,
45 t_vec: Q,
46 u_angle: f64,
47 t_angle: f64,
48 ) -> Self {
49 Self { point: Q::new_xy(x, y), u, t, u_vec, t_vec, u_angle, t_angle }
50 }
51}
52
53pub fn intersection_of_segments<P: GetXY, Q: NewXY>(
64 a: (&P, &P),
65 b: (&P, &P),
66) -> Option<IntersectionOfSegments<Q>> {
67 let (p, p2) = a;
68 let (q, q2) = b;
69
70 let r = Point::new_xy(p2.x() - p.x(), p2.y() - p.y());
71 let s = Point::new_xy(q2.x() - q.x(), q2.y() - q.y());
72
73 let cross = r.x() * s.y() - r.y() * s.x();
74 if cross == 0. {
75 return None;
76 }
77
78 let u = ((q.x() - p.x()) * s.y() - (q.y() - p.y()) * s.x()) / cross;
79 let t = ((q.x() - p.x()) * r.y() - (q.y() - p.y()) * r.x()) / cross;
80
81 if (0. ..=1.).contains(&t) && (0. ..=1.).contains(&u) {
82 Some(IntersectionOfSegments {
83 point: Q::new_xy(p.x() + u * r.x(), p.y() + u * r.y()),
84 u,
85 t,
86 })
87 } else {
88 None
89 }
90}
91
92pub fn intersection_of_segments_robust<P: GetXY + PartialEq, Q: NewXY + Clone>(
113 a: (&P, &P),
114 b: (&P, &P),
115 same_ring: bool,
116) -> Option<IntersectionOfSegmentsRobust<Q>> {
117 let (x1, y1) = a.0.xy();
118 let (x2, y2) = a.1.xy();
119 let (x3, y3) = b.0.xy();
120 let (x4, y4) = b.1.xy();
121 let (dx_a, dy_a) = (x2 - x1, y2 - y1);
122 let (dx_b, dy_b) = (x4 - x3, y4 - y3);
123 let (dx_c, dy_c) = (x1 - x3, y1 - y3);
124
125 if (dx_a == 0. && dy_a == 0.) || (dx_b == 0. && dy_b == 0.) {
127 return None;
128 }
129
130 let u_angle = if dx_a == 0. && dy_a == 0. { 0. } else { atan2(dy_a, dx_a) };
132 let t_angle = if dx_b == 0. && dy_b == 0. { 0. } else { atan2(dy_b, dx_b) };
133
134 if same_ring {
135 if a.1 == b.0 || a.1 == b.1 || a.0 == b.0 || a.0 == b.1 {
136 return None;
137 }
138 } else {
139 let zero = Q::new_xy(0., 0.);
140 if a.1 == b.0 {
141 let u_vec = Q::new_xy(dx_a, dy_a);
142 return Some(IntersectionOfSegmentsRobust::new(
143 x2, y2, 1., 0., u_vec, zero, u_angle, t_angle,
144 ));
145 }
146 if a.1 == b.1 {
147 let u_vec = Q::new_xy(dx_a, dy_a);
148 let t_vec = Q::new_xy(dx_b, dy_b);
149 return Some(IntersectionOfSegmentsRobust::new(
150 x2, y2, 1., 1., u_vec, t_vec, u_angle, t_angle,
151 ));
152 }
153 if a.0 == b.0 {
154 let zero_2 = zero.clone();
155 return Some(IntersectionOfSegmentsRobust::new(
156 x1, y1, 0., 0., zero, zero_2, u_angle, t_angle,
157 ));
158 }
159 if a.0 == b.1 {
160 let t_vec = Q::new_xy(dx_b, dy_b);
161 return Some(IntersectionOfSegmentsRobust::new(
162 x1, y1, 0., 1., zero, t_vec, u_angle, t_angle,
163 ));
164 }
165 }
166
167 let denom = dy_b * dx_a - dx_b * dy_a;
169 if denom == 0. {
170 return None;
171 }
172 let orient1 = orient2d(x1, y1, x2, y2, x3, y3);
173 let orient2 = orient2d(x1, y1, x2, y2, x4, y4);
174 if (orient1 > 0. && orient2 > 0.) || (orient1 < 0. && orient2 < 0.) {
175 return None;
176 }
177
178 let nume_a = dx_b * dy_c - dy_b * dx_c;
180 let nume_b = dx_a * dy_c - dy_a * dx_c;
181 let u_a = nume_a / denom;
182 let u_b = nume_b / denom;
183
184 if (0. ..=1.).contains(&u_a) && (0. ..=1.).contains(&u_b) {
185 let mut x = x1 + u_a * dx_a;
186 let mut y = y1 + u_a * dy_a;
187 let u_vec = Q::new_xy(u_a * dx_a, u_a * dy_a);
188 let t_vec = Q::new_xy(u_b * dx_b, u_b * dy_b);
189 if u_a != 0. && u_a != 1. && u_b != 0. && u_b != 1. {
192 if u_a <= 0.5 && x == x1 && y == y1 {
193 if dx_a != 0. {
194 x = if dx_a > 0. { x.next_up() } else { x.next_down() };
195 }
196 if dy_a != 0. {
197 y = if dy_a > 0. { y.next_up() } else { y.next_down() };
198 }
199 } else if u_a > 0.5 && x == x2 && y == y2 {
200 if dx_a != 0. {
201 x = if dx_a < 0. { x.next_up() } else { x.next_down() };
202 }
203 if dy_a != 0. {
204 y = if dy_a < 0. { y.next_up() } else { y.next_down() };
205 }
206 } else if u_b <= 0.5 && x == x3 && y == y3 {
207 if dx_b != 0. {
208 x = if dx_b > 0. { x.next_up() } else { x.next_down() };
209 }
210 if dy_b != 0. {
211 y = if dy_b > 0. { y.next_up() } else { y.next_down() };
212 }
213 } else if u_b > 0.5 && x == x4 && y == y4 {
214 if dx_b != 0. {
215 x = if dx_b < 0. { x.next_up() } else { x.next_down() };
216 }
217 if dy_b != 0. {
218 y = if dy_b < 0. { y.next_up() } else { y.next_down() };
219 }
220 }
221 }
222 Some(IntersectionOfSegmentsRobust::new(x, y, u_a, u_b, u_vec, t_vec, u_angle, t_angle))
223 } else {
224 None
225 }
226}