gistools/geometry/tools/polys/
intersections.rs1use crate::{
2 data_structures::{BoxIndex, BoxIndexAccessor},
3 geometry::{IntersectionOfSegmentsRobust, intersection_of_segments_robust},
4};
5use alloc::{collections::BTreeMap, rc::Rc, vec, vec::Vec};
6use core::{cell::RefCell, cmp::Ordering};
7use libm::{fmax, fmin};
8use s2json::{BBox, FullXY, GetXY, NewXY, Point};
9
10#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct Segment {
13 pub id: usize,
15 pub poly_index: usize,
17 pub ring_index: usize,
19 pub from: usize,
21 pub to: usize,
23 pub bbox: BBox,
25}
26impl BoxIndexAccessor for Segment {
27 fn bbox(&self) -> BBox {
28 self.bbox
29 }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq)]
34pub struct Intersection {
35 pub segment1: Segment,
37 pub segment2: Segment,
39 pub point: Point,
41 pub u: f64,
43 pub t: f64,
45}
46
47#[derive(Debug, Clone, PartialEq)]
49pub struct RingIntersection {
50 pub from: usize,
52 pub to: usize,
54 pub point: Rc<RefCell<Point>>,
56 pub t: f64,
58 pub t_vec: Point,
60 pub t_angle: f64,
62}
63impl RingIntersection {
64 pub fn new<P: FullXY>(
66 from: usize,
67 to: usize,
68 point: Rc<RefCell<Point>>,
69 t: f64,
70 t_vec: &P,
71 t_angle: f64,
72 ) -> Self {
73 RingIntersection { from, to, point, t, t_vec: t_vec.into(), t_angle }
74 }
75}
76pub type RingIntersectionLookup = BTreeMap<usize, BTreeMap<usize, Vec<RingIntersection>>>;
78
79pub fn polygons_intersections<P: GetXY + PartialEq>(
90 vector_polygons: &[Vec<Vec<P>>],
91 include_self_intersections: bool,
92) -> Vec<Intersection> {
93 let mut res: Vec<Intersection> = vec![];
94 let segments = build_polygon_segments(vector_polygons);
96
97 let box_index = BoxIndex::new(segments.clone(), None);
99
100 for segment1 in segments {
102 let potential_intersections = box_index.search(
103 &segment1.bbox(),
104 Some(|seg: &Segment| {
105 seg.id != segment1.id
106 && seg.id > segment1.id
107 && (if !include_self_intersections {
110 seg.poly_index != segment1.poly_index
111 } else {
112 seg.ring_index != segment1.ring_index
113 || (seg.from != segment1.from
114 && seg.to != segment1.to
115 && seg.to != segment1.from
116 && seg.from != segment1.to)
117 })
118 }),
119 );
120 for segment2 in potential_intersections {
121 if let Some(int_point) =
122 find_polygon_intersection(vector_polygons, &segment1, &segment2)
123 {
124 let IntersectionOfSegmentsRobust { point, u, t, .. } = int_point;
125 res.push(Intersection { segment1, segment2, point, u, t });
126 }
127 }
128 }
129
130 res
131}
132
133pub fn build_polygon_segments<P: GetXY>(vector_polygons: &[Vec<Vec<P>>]) -> Vec<Segment> {
141 let mut segments = vec![];
142
143 for (p, polygon) in vector_polygons.iter().enumerate() {
144 for (r, ring) in polygon.iter().enumerate() {
145 for s in 0..ring.len() - 1 {
146 let from = &ring[s];
147 let to = &ring[s + 1];
148 segments.push(Segment {
149 id: segments.len(),
150 poly_index: p,
151 ring_index: r,
152 from: s,
153 to: s + 1,
154 bbox: BBox::new(
155 fmin(from.x(), to.x()),
156 fmin(from.y(), to.y()),
157 fmax(from.x(), to.x()),
158 fmax(from.y(), to.y()),
159 ),
160 });
161 }
162 }
163 }
164
165 segments
166}
167
168pub fn polygons_intersections_lookup<P: FullXY>(
176 vector_polygons: &[Vec<Vec<P>>],
177 segment_filter: Option<impl Fn(&Segment, &Segment) -> bool>,
178) -> RingIntersectionLookup {
179 let segments = build_polygon_segments(vector_polygons);
180 let mut ring_intersect_lookup: RingIntersectionLookup = BTreeMap::new();
181
182 let box_index = BoxIndex::new(segments.clone(), None);
184 for seg1 in segments {
186 let potential_intersections = box_index.search(
187 &seg1.bbox(),
188 Some(|seg2: &Segment| {
189 segment_filter.as_ref().map(|f| f(&seg1, seg2)).unwrap_or_else(|| {
190 seg2.id != seg1.id &&
192 seg2.id > seg1.id &&
194 seg2.poly_index != seg1.poly_index
196 })
197 }),
198 );
199 for seg2 in potential_intersections {
200 let p_int = find_polygon_intersection::<P, P>(vector_polygons, &seg1, &seg2);
201 if let Some(int) = p_int {
203 let IntersectionOfSegmentsRobust { u, t, point, u_angle, t_angle, u_vec, t_vec } =
204 int;
205 if u == t && (u == 0. || u == 1.) {
207 continue;
208 }
209 let p = Rc::new(RefCell::new((&point).into()));
210 let s1 = ring_intersect_lookup
212 .entry(seg1.poly_index)
213 .or_default()
214 .entry(seg1.ring_index)
215 .or_default();
216 s1.push(RingIntersection::new(seg1.from, seg1.to, p.clone(), u, &u_vec, u_angle));
217 let s2 = ring_intersect_lookup
219 .entry(seg2.poly_index)
220 .or_default()
221 .entry(seg2.ring_index)
222 .or_default();
223 s2.push(RingIntersection::new(seg2.from, seg2.to, p, t, &t_vec, t_angle));
224 }
225 }
226 }
227
228 for (_, polys) in ring_intersect_lookup.iter_mut() {
230 for (_, intersections) in polys.iter_mut() {
231 *intersections = clean_intersections(intersections);
232 }
233 }
234
235 ring_intersect_lookup
236}
237
238pub fn find_polygon_intersection<P: GetXY + PartialEq, Q: NewXY + Clone>(
248 vector_polygons: &[Vec<Vec<P>>],
249 segment1: &Segment,
250 segment2: &Segment,
251) -> Option<IntersectionOfSegmentsRobust<Q>> {
252 let p1 = &vector_polygons[segment1.poly_index][segment1.ring_index][segment1.from];
253 let p2 = &vector_polygons[segment1.poly_index][segment1.ring_index][segment1.to];
254 let q1 = &vector_polygons[segment2.poly_index][segment2.ring_index][segment2.from];
255 let q2 = &vector_polygons[segment2.poly_index][segment2.ring_index][segment2.to];
256 intersection_of_segments_robust(
257 (p1, p2),
258 (q1, q2),
259 segment1.poly_index == segment2.poly_index && segment1.ring_index == segment2.ring_index,
260 )
261}
262
263pub fn polygons_intersections_ref<P: GetXY + PartialEq>(
274 vector_polygons: &[&Vec<Vec<P>>],
275 include_self_intersections: bool,
276) -> Vec<Intersection> {
277 let mut res: Vec<Intersection> = vec![];
278 let segments = build_polygon_segments_ref(vector_polygons);
280
281 let box_index = BoxIndex::new(segments.clone(), None);
283
284 for segment1 in segments {
286 let potential_intersections = box_index.search(
287 &segment1.bbox(),
288 Some(|seg: &Segment| {
289 seg.id != segment1.id
290 && seg.id > segment1.id
291 && (if !include_self_intersections {
294 seg.poly_index != segment1.poly_index
295 } else {
296 seg.ring_index != segment1.ring_index
297 || (seg.from != segment1.from
298 && seg.to != segment1.to
299 && seg.to != segment1.from
300 && seg.from != segment1.to)
301 })
302 }),
303 );
304 for segment2 in potential_intersections {
305 if let Some(int_point) = find_intersection_ref(vector_polygons, &segment1, &segment2) {
306 res.push(Intersection {
307 segment1,
308 segment2,
309 point: int_point.point,
310 u: int_point.u,
311 t: int_point.t,
312 });
313 }
314 }
315 }
316
317 res
318}
319
320pub fn build_polygon_segments_ref<P: GetXY>(vector_polygons: &[&Vec<Vec<P>>]) -> Vec<Segment> {
328 let mut segments = vec![];
329
330 for (p, polygon) in vector_polygons.iter().enumerate() {
331 for (r, ring) in polygon.iter().enumerate() {
332 for s in 0..ring.len() - 1 {
333 let from = &ring[s];
334 let to = &ring[s + 1];
335 segments.push(Segment {
336 id: segments.len(),
337 poly_index: p,
338 ring_index: r,
339 from: s,
340 to: s + 1,
341 bbox: BBox::new(
342 fmin(from.x(), to.x()),
343 fmin(from.y(), to.y()),
344 fmax(from.x(), to.x()),
345 fmax(from.y(), to.y()),
346 ),
347 });
348 }
349 }
350 }
351
352 segments
353}
354
355fn find_intersection_ref<P: GetXY + PartialEq, Q: NewXY + Clone>(
365 vector_polygons: &[&Vec<Vec<P>>],
366 segment1: &Segment,
367 segment2: &Segment,
368) -> Option<IntersectionOfSegmentsRobust<Q>> {
369 let p1 = &vector_polygons[segment1.poly_index][segment1.ring_index][segment1.from];
370 let p2 = &vector_polygons[segment1.poly_index][segment1.ring_index][segment1.to];
371 let q1 = &vector_polygons[segment2.poly_index][segment2.ring_index][segment2.from];
372 let q2 = &vector_polygons[segment2.poly_index][segment2.ring_index][segment2.to];
373 intersection_of_segments_robust(
374 (p1, p2),
375 (q1, q2),
376 segment1.poly_index == segment2.poly_index && segment1.ring_index == segment2.ring_index,
377 )
378}
379
380fn clean_intersections(intersections: &mut [RingIntersection]) -> Vec<RingIntersection> {
388 if intersections.is_empty() {
389 return vec![];
390 }
391 intersections
392 .sort_by(|a, b| a.from.cmp(&b.from).then(a.t.partial_cmp(&b.t).unwrap_or(Ordering::Equal)));
393
394 let mut dedup_ints: Vec<RingIntersection> = vec![];
396 for int in intersections.iter() {
397 if dedup_ints.iter().any(|c| c.from == int.from && c.t == int.t && c.point == int.point) {
398 continue;
399 }
400
401 dedup_ints.push(int.clone());
402 }
403 if dedup_ints.len() == 2 {
405 let first = &dedup_ints[0];
406 let second = &dedup_ints[1];
407 if (first.t == 0. || first.t == 1.)
408 && (second.t == 0. || second.t == 1.)
409 && first.point == second.point
410 {
411 return vec![];
412 }
413 }
414 update_intersection_points(&mut dedup_ints);
418
419 dedup_ints
420}
421
422fn update_intersection_points(intersections: &mut [RingIntersection]) {
439 let mut starts = vec![];
440 let mut ends = vec![];
441 for i in 1..intersections.len() {
442 let int = &intersections[i];
443 let prev = &intersections[i - 1];
444 if int.from != prev.from || int.t == 0. || int.t == 1. || prev.t == 0. || prev.t == 1. {
445 continue;
446 }
447 if i != 0 && int.point == prev.point && int.t != prev.t {
448 if int.t <= 0.5 {
450 starts.push(i);
451 } else {
452 ends.push(i - 1);
453 }
454 }
455 }
456 for (i, start) in starts.into_iter().enumerate() {
458 let RingIntersection { point, t_vec, .. } = &mut intersections[start];
459 let point = &mut point.borrow_mut();
460 if t_vec.0 != 0.0 {
461 (0..=(i + 1)).for_each(|_| {
462 point.0 = if t_vec.0 > 0.0 { point.0.next_up() } else { point.0.next_down() }
463 });
464 }
465 if t_vec.1 != 0.0 {
466 (0..=(i + 1)).for_each(|_| {
467 point.1 = if t_vec.1 > 0.0 { point.1.next_up() } else { point.1.next_down() }
468 });
469 }
470 }
471 for (i, end) in ends.into_iter().enumerate() {
472 let RingIntersection { point, t_vec, .. } = &mut intersections[end];
473 let point = &mut point.borrow_mut();
474 if t_vec.0 != 0.0 {
475 (0..=(i + 1)).for_each(|_| {
476 point.0 = if t_vec.0 < 0.0 { point.0.next_up() } else { point.0.next_down() }
477 });
478 }
479 if t_vec.1 != 0.0 {
480 (0..=(i + 1)).for_each(|_| {
481 point.1 = if t_vec.1 < 0.0 { point.1.next_up() } else { point.1.next_down() }
482 });
483 }
484 }
485}