1use crate::data::Cursor;
2use crate::data::EndPoint;
3use crate::data::IndexEdge;
4use crate::data::LineSegmentView;
5use crate::data::Point;
6use crate::data::PointId;
7use crate::data::Polygon;
8use crate::data::{IndexIntersection, IndexIntersectionSet};
9use crate::Intersects;
10use crate::{Error, PolygonScalar, TotalOrd};
11
12use rand::Rng;
13use std::collections::BTreeSet;
14use std::ops::Bound::*;
15
16use crate::Orientation;
17
18pub fn resolve_self_intersections<T, R>(poly: &mut Polygon<T>, rng: &mut R) -> Result<(), Error>
19where
20 T: PolygonScalar,
21 R: Rng + ?Sized,
22{
23 assert_eq!(poly.rings.len(), 1);
24 if poly.iter_boundary().all(|pt| pt.is_colinear()) {
25 return Err(Error::InsufficientVertices);
26 }
27 let mut isects = IndexIntersectionSet::new(poly.iter_boundary().len());
30 for e1 in edges(poly) {
32 for e2 in edges(poly) {
33 if e1 < e2 {
34 if let Some(isect) = intersects(poly, e1, e2) {
35 isects.push(isect)
37 }
38 }
39 }
40 }
41 while let Some(isect) = isects.random(rng) {
44 untangle(poly, &mut isects, isect)
45 }
46 poly.ensure_ccw()?;
47 Ok(())
49}
50
51pub fn two_opt_moves<T, R>(pts: Vec<Point<T>>, rng: &mut R) -> Result<Polygon<T>, Error>
60where
61 T: PolygonScalar,
62 R: Rng + ?Sized,
63{
64 {
65 let mut seen = BTreeSet::new();
66 for pt in pts.iter() {
67 if !seen.insert(pt) {
68 return Err(Error::DuplicatePoints);
69 }
70 }
71 }
72 if pts.len() < 3 {
73 return Err(Error::InsufficientVertices);
74 }
75 let mut poly = Polygon::new_unchecked(pts);
76 resolve_self_intersections(&mut poly, rng)?;
77 Ok(poly)
78}
79
80fn endpoint<T: TotalOrd>(a: PointId, b: PointId, c: PointId, t: T) -> EndPoint<T> {
81 if a == b || a == c {
82 EndPoint::Exclusive(t)
83 } else {
84 EndPoint::Inclusive(t)
85 }
86}
87
88fn intersects<T>(poly: &Polygon<T>, a: IndexEdge, b: IndexEdge) -> Option<IndexIntersection>
89where
90 T: PolygonScalar,
91{
92 let a_min = endpoint(a.min, b.min, b.max, poly.point(a.min));
93 let a_max = endpoint(a.max, b.min, b.max, poly.point(a.max));
94 let b_min = endpoint(b.min, a.min, a.max, poly.point(b.min));
95 let b_max = endpoint(b.max, a.min, a.max, poly.point(b.max));
96 let e1 = LineSegmentView::new(a_min, a_max);
97 let e2 = LineSegmentView::new(b_min, b_max);
98 e1.intersect(e2)?; Some(IndexIntersection::new(a, b))
101}
102
103fn untangle<T: PolygonScalar>(
134 poly: &mut Polygon<T>,
135 set: &mut IndexIntersectionSet,
136 isect: IndexIntersection,
137) {
138 let da = poly.cursor(poly.direct(isect.min).src);
146 let db = poly.cursor(poly.direct(isect.max).src);
147
148 let inserted_edges;
149
150 if parallel_edges(da, db) {
151 let (a_min, a_max) = linear_extremes(da);
152 let (b_min, b_max) = linear_extremes(db);
153
154 let mut kinks = Vec::new();
159 for elt in a_min.to(Included(a_max)).chain(b_min.to(Included(b_max))) {
160 let inner_segment: LineSegmentView<T> = (elt.prev().point()..elt.next().point()).into();
161 if elt.orientation() != Orientation::CoLinear || !inner_segment.contains(elt.point()) {
162 kinks.push(elt);
171 }
172 }
173
174 let mut mergable = None;
175 'outer: for edge in a_min.to(Excluded(a_max)).chain(b_min.to(Excluded(b_max))) {
176 let segment = LineSegmentView::new(
177 EndPoint::Exclusive(edge.point()),
178 EndPoint::Exclusive(edge.next().point()),
179 );
180 for &kink in kinks.iter() {
181 if segment.contains(kink.point()) {
182 mergable = Some((kink, edge));
183 break 'outer;
184 }
185 }
186 }
187 let (kink, edge) = mergable.expect("There must be at least one mergable edge");
202 let del_edge_1 = IndexEdge::new(kink.prev().point_id(), kink.point_id());
206 let del_edge_2 = IndexEdge::new(kink.point_id(), kink.next().point_id());
207 let del_edge_3 = IndexEdge::new(edge.point_id(), edge.next().point_id());
208 set.remove_all(del_edge_1);
213 set.remove_all(del_edge_2);
214 set.remove_all(del_edge_3);
215
216 inserted_edges = vec![
217 IndexEdge::new(kink.prev().point_id(), kink.next().point_id()),
218 IndexEdge::new(edge.point_id(), kink.point_id()),
219 IndexEdge::new(kink.point_id(), edge.next().point_id()),
220 ];
221
222 let p1 = edge.position;
223 let p2 = kink.position;
224 poly.vertices_join(p1, p2);
226 } else {
227 set.remove_all(IndexEdge::new(da.point_id(), da.next().point_id()));
229 set.remove_all(IndexEdge::new(db.point_id(), db.next().point_id()));
230
231 inserted_edges = vec![
232 IndexEdge::new(da.point_id(), db.point_id()),
233 IndexEdge::new(da.next().point_id(), db.next().point_id()),
234 ];
235
236 let p1 = da.next().position;
237 let p2 = db.position;
238 poly.vertices_reverse(p1, p2);
240 }
242 for &edge in inserted_edges.iter() {
245 for e1 in edges(poly) {
246 if e1 != edge {
247 if let Some(isect) = intersects(poly, e1, edge) {
248 set.push(isect)
250 }
251 }
252 }
253 }
254 }
256
257#[allow(dead_code)]
258#[cfg(not(tarpaulin_include))]
259fn sanity_check<T: PolygonScalar>(poly: &Polygon<T>, isects: &IndexIntersectionSet) {
260 let naive_set = naive_intersection_set(poly);
261 let fast_set = isects.iter().collect();
262 let missing: Vec<&IndexIntersection> = naive_set.difference(&fast_set).collect();
263 let extra: Vec<&IndexIntersection> = fast_set.difference(&naive_set).collect();
264 if !missing.is_empty() {
265 panic!("Fast set is too small! {:?}", missing);
266 }
267 if !extra.is_empty() {
268 panic!("Fast set is too large! {:?}", extra);
269 }
270}
271
272#[cfg(not(tarpaulin_include))]
273fn naive_intersection_set<T: PolygonScalar>(poly: &Polygon<T>) -> BTreeSet<IndexIntersection> {
274 let mut set = BTreeSet::new();
275 for e1 in edges(poly) {
276 for e2 in edges(poly) {
277 if e1 < e2 {
278 if let Some(isect) = intersects(poly, e1, e2) {
279 set.insert(isect);
280 }
281 }
282 }
283 }
284 set
285}
286
287fn parallel_edges<T>(a: Cursor<'_, T>, b: Cursor<'_, T>) -> bool
288where
289 T: PolygonScalar,
290{
291 let a1 = a.point();
292 let a2 = a.next().point();
293 let b1 = b.point();
294 let b2 = b.next().point();
295 Point::orient(a1, a2, b1).is_colinear() && Point::orient(a1, a2, b2).is_colinear()
296}
297
298fn linear_extremes<T>(at: Cursor<'_, T>) -> (Cursor<'_, T>, Cursor<'_, T>)
308where
309 T: PolygonScalar,
310{
311 let mut at_min = at;
312 let mut at_max = at;
313 at_max.move_next();
314 while at_min.is_colinear() {
315 at_min.move_prev();
316 }
317 while at_max.is_colinear() {
318 at_max.move_next();
319 }
320 (at_min, at_max)
321}
322
323fn edges<T>(poly: &Polygon<T>) -> impl Iterator<Item = IndexEdge> + '_ {
324 poly
325 .iter_boundary()
326 .map(|cursor| IndexEdge::new(cursor.point_id(), cursor.next().point_id()))
327}
328
329#[cfg(test)]
330#[cfg(not(tarpaulin_include))]
331pub mod tests {
332 use super::*;
333
334 use crate::testing::any_nn;
335 use ordered_float::NotNan;
336 use proptest::collection::vec;
337 use proptest::prelude::*;
338 use rand::prelude::SliceRandom;
339 use rand::rngs::mock::StepRng;
340 use rand::SeedableRng;
341 use test_strategy::proptest;
342
343 #[test]
344 fn unit_1() {
345 let pts: Vec<Point<i8>> = vec![
346 Point { array: [-71, 91] },
347 Point { array: [-17, -117] },
348 Point { array: [-13, 98] },
349 Point { array: [-84, 67] },
350 Point { array: [-12, -92] },
351 Point { array: [-95, 71] },
352 Point { array: [-81, -2] },
353 Point { array: [-91, -9] },
354 Point { array: [-42, -66] },
355 Point { array: [-107, 105] },
356 Point { array: [-49, 9] },
357 Point { array: [-96, 92] },
358 Point { array: [42, 11] },
359 Point { array: [-63, 56] },
360 Point { array: [122, -53] },
361 Point { array: [93, 29] },
362 Point { array: [-93, 89] },
363 Point { array: [40, -63] },
364 Point { array: [-127, -44] },
365 Point { array: [-108, 74] },
366 Point { array: [96, -5] },
367 Point { array: [46, 3] },
368 Point { array: [-103, -94] },
369 Point { array: [125, 73] },
370 Point { array: [104, 60] },
371 Point { array: [-55, -55] },
372 Point { array: [-112, -42] },
373 Point { array: [107, -16] },
374 Point { array: [38, -111] },
375 Point { array: [57, 123] },
376 Point { array: [-107, 108] },
377 Point { array: [46, -61] },
378 Point { array: [0, -35] },
379 Point { array: [35, -115] },
380 Point { array: [-120, 31] },
381 Point { array: [123, -87] },
382 Point { array: [-22, -87] },
383 Point { array: [-91, 27] },
384 Point { array: [101, -6] },
385 Point { array: [43, 6] },
386 Point { array: [-31, -73] },
387 Point {
388 array: [-107, -115],
389 },
390 Point { array: [-60, -98] },
391 Point { array: [-18, -94] },
392 Point { array: [52, -22] },
393 Point { array: [-71, -128] },
394 Point { array: [80, -26] },
395 Point { array: [104, -91] },
396 Point { array: [-91, 45] },
397 Point { array: [-79, -91] },
398 Point { array: [-47, -124] },
399 Point { array: [14, 101] },
400 Point { array: [-21, -69] },
401 Point { array: [16, 55] },
402 Point { array: [105, -76] },
403 Point { array: [-78, 39] },
404 Point { array: [80, -114] },
405 Point { array: [-6, 9] },
406 Point { array: [-65, -104] },
407 Point { array: [16, -1] },
408 Point { array: [122, -67] },
409 Point { array: [-93, -123] },
410 Point {
411 array: [-121, -120],
412 },
413 Point { array: [112, 32] },
414 Point { array: [-87, -126] },
415 Point { array: [-120, -38] },
416 Point { array: [90, -111] },
417 ];
418 let ret = two_opt_moves(pts, &mut rand::rngs::SmallRng::seed_from_u64(0));
419
420 assert_eq!(ret.and_then(|val| val.validate()).err(), None);
421 }
422
423 #[test]
424 fn unit_2() {
425 let pts: Vec<Point<i8>> = vec![
426 Point { array: [-59, -36] },
427 Point { array: [-62, 88] },
428 Point { array: [8, 124] },
429 Point { array: [110, -81] },
430 Point { array: [-93, 27] },
431 Point { array: [96, 98] },
432 Point { array: [66, 87] },
433 Point { array: [-80, 20] },
434 Point { array: [-21, -17] },
435 Point { array: [-8, 21] },
436 Point { array: [0, -4] },
437 Point { array: [-63, 40] },
438 Point { array: [-24, 78] },
439 Point { array: [83, 23] },
440 Point { array: [0, 93] },
441 Point { array: [57, 52] },
442 Point { array: [-87, -17] },
443 Point { array: [38, 6] },
444 Point { array: [0, -118] },
445 Point {
446 array: [-101, -119],
447 },
448 Point { array: [-30, 90] },
449 Point { array: [0, -83] },
450 Point {
451 array: [-103, -112],
452 },
453 Point { array: [6, 75] },
454 Point { array: [65, -18] },
455 Point { array: [-126, 56] },
456 Point { array: [-86, 97] },
457 Point { array: [42, 44] },
458 Point { array: [-128, 23] },
459 Point { array: [-100, -53] },
460 Point { array: [-85, 96] },
461 Point { array: [120, 24] },
462 Point { array: [74, 98] },
463 Point { array: [63, -43] },
464 Point { array: [-42, 45] },
465 Point { array: [-2, 109] },
466 Point { array: [-107, -94] },
467 Point { array: [-12, 73] },
468 Point { array: [99, 86] },
469 Point { array: [62, 91] },
470 Point { array: [-84, 81] },
471 Point { array: [-128, 76] },
472 Point { array: [-27, -45] },
473 Point { array: [-56, 74] },
474 Point { array: [-2, -59] },
475 Point { array: [-65, 57] },
476 Point { array: [-9, 66] },
477 Point { array: [52, 40] },
478 Point { array: [13, -70] },
479 Point { array: [93, -1] },
480 Point { array: [47, 38] },
481 Point { array: [-85, -119] },
482 Point { array: [-91, 52] },
483 Point { array: [-107, 69] },
484 Point { array: [31, -97] },
485 Point { array: [118, 42] },
486 Point { array: [61, -85] },
487 Point { array: [0, 45] },
488 Point { array: [-128, -48] },
489 Point { array: [-94, 28] },
490 Point { array: [-86, -56] },
491 Point { array: [-128, 55] },
492 Point { array: [0, 58] },
493 Point { array: [75, -45] },
494 Point { array: [-76, -21] },
495 Point { array: [-10, -113] },
496 Point { array: [-96, -21] },
497 Point { array: [-84, 72] },
498 Point { array: [100, -26] },
499 Point { array: [-120, -50] },
500 Point { array: [-94, -19] },
501 Point { array: [17, -4] },
502 Point { array: [56, -23] },
503 Point { array: [11, 43] },
504 Point { array: [-14, 57] },
505 Point { array: [-42, -21] },
506 Point { array: [0, -95] },
507 Point { array: [8, 48] },
508 Point { array: [-21, -46] },
509 Point { array: [16, 81] },
510 Point { array: [0, 120] },
511 Point { array: [26, 27] },
512 Point { array: [-69, -44] },
513 Point { array: [97, 42] },
514 ];
515 let mut rng = StepRng::new(0, 0);
516 let ret = two_opt_moves(pts, &mut rng);
518
519 assert_eq!(ret.and_then(|val| val.validate()).err(), None);
520 }
521
522 #[test]
523 fn unit_3() {
524 let pts: Vec<Point<i8>> = vec![
525 Point { array: [0, 0] },
526 Point { array: [2, 0] },
527 Point { array: [1, 0] },
528 Point { array: [3, 0] },
529 Point { array: [3, 1] },
530 Point { array: [0, 1] },
531 ];
532 let mut rng = StepRng::new(0, 0);
533 let ret = two_opt_moves(pts, &mut rng);
534
535 assert_eq!(ret.and_then(|val| val.validate()).err(), None);
536 }
537
538 #[proptest]
539 fn points_to_polygon(#[strategy(vec(any::<Point<i8>>(), 3..100))] mut pts: Vec<Point<i8>>) {
540 let mut set = BTreeSet::new();
541 pts.retain(|pt| set.insert(*pt));
542 if pts.len() >= 3 && !Point::all_colinear(&pts) {
543 let mut rng = StepRng::new(0, 0);
544 let ret = two_opt_moves(pts, &mut rng);
545 prop_assert_eq!(ret.and_then(|val| val.validate()).err(), None);
546 }
547 }
548
549 #[proptest]
550 fn f64_to_polygon(#[strategy(vec(any_nn(), 3..100))] mut pts: Vec<Point<NotNan<f64>>>) {
551 let mut set = BTreeSet::new();
552 pts.retain(|pt| set.insert(*pt));
553 if pts.len() >= 3 && !Point::all_colinear(&pts) {
554 let mut rng = StepRng::new(0, 0);
555 let ret = two_opt_moves(pts, &mut rng);
556 prop_assert_eq!(ret.and_then(|val| val.validate()).err(), None);
557 }
558 }
559
560 #[proptest]
561 fn fuzz_f64(#[strategy(vec(any_nn(), 0..100))] pts: Vec<Point<NotNan<f64>>>) {
562 let mut rng = StepRng::new(0, 0);
563 two_opt_moves(pts, &mut rng).ok();
564 }
565
566 #[proptest]
567 fn fuzz_i8(#[strategy(vec(any::<Point<i8>>(), 0..100))] pts: Vec<Point<i8>>) {
568 let mut rng = StepRng::new(0, 0);
569 two_opt_moves(pts, &mut rng).ok();
570 }
571
572 #[proptest]
573 fn linear_fuzz(#[strategy(2..10_i8)] n: i8, seed: u64) {
574 let mut linear: Vec<i8> = (0..n).collect();
575 let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
576 linear.shuffle(&mut rng);
577 let mut pts: Vec<Point<i8>> = linear.iter().map(|&n| Point::new([n, 0])).collect();
578 pts.push(Point::new([0, 1]));
579
580 let mut rng = StepRng::new(0, 0);
581 let ret = two_opt_moves(pts, &mut rng);
583 prop_assert_eq!(ret.and_then(|val| val.validate()).err(), None);
584 }
585}