Skip to main content

axiolid_overlay/
segment_sweep.rs

1//! Every intersection among many segments: a Bentley–Ottmann sweep (#146).
2//!
3//! [`segment_intersections`] reports each point where two or more input
4//! segments meet, with every segment through it, and each collinear piece
5//! that two or more segments share, in `O((n + k) log n)` time for `n`
6//! segments and `k` reported incidences (segment–point pairs; `k` is twice
7//! the number of crossings when segments are in general position). The
8//! pairwise alternative, calling a segment/segment test on every pair, is
9//! `O(n^2)`.
10//!
11//! # Exactness
12//!
13//! Every decision is an exact sign: the order of two event points, which
14//! side of a segment a point lies on, whether two segments cross, and the
15//! order of two directions. Each is asked of an outward-rounded interval
16//! first and of exact dyadic arithmetic (`axiolid-exact`) only when the
17//! interval cannot decide, so no tolerance enters and the answer does not
18//! depend on drawing units. A crossing point is a rational number, kept
19//! exactly as homogeneous dyadic coordinates ([`ExactPoint2`]) and rounded
20//! once, correctly (nearest double, ties to even), when a caller asks for
21//! [`ExactPoint2::rounded`]. A rounded value never feeds a decision.
22//!
23//! # Sweep order and degeneracies
24//!
25//! Points are swept in lexicographic order, `x` first and `y` breaking ties,
26//! which is a sweep line turned by an infinitesimal angle. A vertical
27//! segment is then an ordinary segment that the line crosses from its lower
28//! end to its upper end, and needs no special case. Along the line,
29//! segments through the current point are ordered by direction, and
30//! segments with the same direction through the same point lie on one line
31//! and form a bundle; a bundle of two or more is an overlap.
32//!
33//! - Shared endpoints, T-junctions and many segments through one point are
34//!   found by locating the event point in the sweep status: all active
35//!   segments through it form one contiguous run, whatever their number.
36//! - Only proper crossings (interior to both segments) are scheduled as new
37//!   events; every endpoint is an event from the start, so a crossing at an
38//!   endpoint is already one.
39//! - A zero-length segment is a point. It is reported where it lies on
40//!   another segment or on another zero-length segment, with
41//!   [`SegmentLocation::Degenerate`], and it takes no part in overlaps.
42//! - Non-finite coordinates are refused with the segment's index.
43//!
44//! # What is reported
45//!
46//! A point is reported when at least two segments contain it and it is an
47//! endpoint of one of them or a proper crossing of two. Equivalently: every
48//! point on two or more segments, except those inside an overlap where all
49//! segments through the point are collinear and pass through it, which say
50//! nothing the overlap does not.
51//! Overlaps are maximal collinear pieces covered by a constant set of at
52//! least two segments; a new set starts only where a segment of the line
53//! starts or ends, so both ends of an overlap are input endpoints and are
54//! also reported as points.
55//!
56//! The model is CGAL's `Surface_sweep_2` (`compute_intersection_points`,
57//! `compute_subcurves`), restricted to segments and kept exact.
58
59use std::cmp::Ordering;
60use std::collections::BTreeMap;
61use std::sync::{Arc, OnceLock};
62
63use axiolid_core::Point2;
64use axiolid_exact::{certify, Arith, Dyadic, Interval, SignExpr};
65use axiolid_guarantees::Sign;
66
67use crate::exact_arc::{orient_doubles, round_ratio};
68
69/// Why the sweep refused its input.
70#[non_exhaustive]
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum SegmentSweepError {
73    /// A coordinate of the segment at this index was NaN or infinite.
74    NonFinite {
75        /// Index of the segment in the input slice.
76        segment: usize,
77    },
78}
79
80impl core::fmt::Display for SegmentSweepError {
81    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82        match self {
83            Self::NonFinite { segment } => {
84                write!(f, "segment {segment} has a non-finite coordinate")
85            }
86        }
87    }
88}
89
90impl std::error::Error for SegmentSweepError {}
91
92/// A planar point with exact rational coordinates.
93///
94/// Either an input endpoint, which is a pair of doubles, or a crossing of
95/// two segments, `(x / w, y / w)` with dyadic `x`, `y` and `w > 0`.
96/// Equality and order are exact; the order is lexicographic (`x`, then
97/// `y`), which is the sweep order.
98#[derive(Debug, Clone)]
99pub struct ExactPoint2 {
100    repr: Repr,
101}
102
103#[derive(Debug, Clone)]
104enum Repr {
105    Input(Point2),
106    Rational(Arc<Rational>),
107}
108
109#[derive(Debug)]
110struct Rational {
111    x: Dyadic,
112    y: Dyadic,
113    w: Dyadic,
114    /// Sound enclosures of `x / w` and `y / w`: the fast tier.
115    bx: Interval,
116    by: Interval,
117    rounded: OnceLock<Point2>,
118}
119
120impl ExactPoint2 {
121    /// The point `(x / w, y / w)`, or `None` when `w` is zero.
122    #[must_use]
123    pub fn from_homogeneous(x: Dyadic, y: Dyadic, w: Dyadic) -> Option<Self> {
124        let flip = match w.sign()? {
125            Sign::Positive => false,
126            Sign::Negative => true,
127            _ => return None,
128        };
129        let (x, y, w) = if flip {
130            (x.neg(), y.neg(), w.neg())
131        } else {
132            (x, y, w)
133        };
134        let we = w.enclosure();
135        Some(Self {
136            repr: Repr::Rational(Arc::new(Rational {
137                bx: x.enclosure().quotient(we),
138                by: y.enclosure().quotient(we),
139                x,
140                y,
141                w,
142                rounded: OnceLock::new(),
143            })),
144        })
145    }
146
147    fn input(point: Point2) -> Self {
148        Self {
149            repr: Repr::Input(point),
150        }
151    }
152
153    /// The input endpoint this point is, when it is one.
154    ///
155    /// Every point the sweep reports that is not a proper crossing is an
156    /// input endpoint, and then these are exactly its doubles.
157    #[must_use]
158    pub fn as_input(&self) -> Option<Point2> {
159        match &self.repr {
160            Repr::Input(p) => Some(*p),
161            Repr::Rational(_) => None,
162        }
163    }
164
165    /// Exact homogeneous coordinates `(x, y, w)` with `w > 0`.
166    #[must_use]
167    pub fn homogeneous(&self) -> (Dyadic, Dyadic, Dyadic) {
168        match &self.repr {
169            Repr::Input(p) => (dy(p.x), dy(p.y), dy(1.0)),
170            Repr::Rational(r) => (r.x.clone(), r.y.clone(), r.w.clone()),
171        }
172    }
173
174    /// Each coordinate correctly rounded to the nearest double, ties to
175    /// even. An input endpoint comes back bit for bit.
176    ///
177    /// For output only: rounding moves the point, so a rounded crossing
178    /// may lie off both segments it is on.
179    #[must_use]
180    pub fn rounded(&self) -> Point2 {
181        match &self.repr {
182            Repr::Input(p) => *p,
183            Repr::Rational(r) => *r.rounded.get_or_init(|| {
184                let guess = |n: &Dyadic| {
185                    let (mn, en) = n.approx_parts();
186                    let (mw, ew) = r.w.approx_parts();
187                    scale2(mn / mw, en - ew)
188                };
189                Point2::new(
190                    round_ratio(&r.x, &r.w, guess(&r.x)),
191                    round_ratio(&r.y, &r.w, guess(&r.y)),
192                )
193            }),
194        }
195    }
196
197    fn bound(&self, axis: Axis) -> Interval {
198        match (&self.repr, axis) {
199            (Repr::Input(p), Axis::X) => Interval::point(p.x),
200            (Repr::Input(p), Axis::Y) => Interval::point(p.y),
201            (Repr::Rational(r), Axis::X) => r.bx,
202            (Repr::Rational(r), Axis::Y) => r.by,
203        }
204    }
205
206    fn exact(&self, axis: Axis) -> (Dyadic, Dyadic) {
207        match (&self.repr, axis) {
208            (Repr::Input(p), Axis::X) => (dy(p.x), dy(1.0)),
209            (Repr::Input(p), Axis::Y) => (dy(p.y), dy(1.0)),
210            (Repr::Rational(r), Axis::X) => (r.x.clone(), r.w.clone()),
211            (Repr::Rational(r), Axis::Y) => (r.y.clone(), r.w.clone()),
212        }
213    }
214}
215
216impl PartialEq for ExactPoint2 {
217    fn eq(&self, other: &Self) -> bool {
218        self.cmp(other) == Ordering::Equal
219    }
220}
221
222impl Eq for ExactPoint2 {}
223
224impl PartialOrd for ExactPoint2 {
225    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
226        Some(self.cmp(other))
227    }
228}
229
230impl Ord for ExactPoint2 {
231    fn cmp(&self, other: &Self) -> Ordering {
232        if let (Repr::Input(a), Repr::Input(b)) = (&self.repr, &other.repr) {
233            // Finite doubles: `total_cmp` would order -0 before +0, which
234            // are the same point, so compare as reals.
235            return cmp_f64(a.x, b.x).then_with(|| cmp_f64(a.y, b.y));
236        }
237        cmp_axis(self, other, Axis::X).then_with(|| cmp_axis(self, other, Axis::Y))
238    }
239}
240
241/// Where on a segment an incidence lies, in the segment's own direction
242/// (`Start` is the segment's first point as given).
243#[non_exhaustive]
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
245pub enum SegmentLocation {
246    /// The segment's first point.
247    Start,
248    /// The segment's second point.
249    End,
250    /// Strictly between its endpoints.
251    Interior,
252    /// The segment has zero length and this is its only point.
253    Degenerate,
254}
255
256/// One segment through a reported point.
257#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
258pub struct Incidence {
259    /// Index of the segment in the input slice.
260    pub segment: usize,
261    /// Where on that segment the point lies.
262    pub location: SegmentLocation,
263}
264
265/// A point where two or more segments meet.
266#[non_exhaustive]
267#[derive(Debug, Clone, PartialEq)]
268pub struct IntersectionPoint {
269    /// The exact point.
270    pub point: ExactPoint2,
271    /// [`ExactPoint2::rounded`]: correctly rounded, for output.
272    pub rounded: Point2,
273    /// Every segment containing the point, by increasing index.
274    pub incidences: Vec<Incidence>,
275}
276
277/// A collinear piece shared by two or more segments.
278#[non_exhaustive]
279#[derive(Debug, Clone, PartialEq)]
280pub struct SegmentOverlap {
281    /// The lexicographically smaller end. Always an input endpoint, so it
282    /// is exact.
283    pub from: Point2,
284    /// The lexicographically larger end, also an input endpoint.
285    pub to: Point2,
286    /// The segments covering the whole piece, by increasing index. The set
287    /// changes at both ends (or the piece ends there).
288    pub segments: Vec<usize>,
289}
290
291/// What the sweep did, for measurement.
292#[non_exhaustive]
293#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
294pub struct SweepEvidence {
295    /// Input segments.
296    pub segments: usize,
297    /// Distinct event points swept: endpoints and proper crossings.
298    pub events: usize,
299    /// Proper crossings found between neighbouring segments.
300    pub crossings: usize,
301}
302
303/// The result of [`segment_intersections`].
304#[non_exhaustive]
305#[derive(Debug, Clone, PartialEq)]
306pub struct SegmentIntersections {
307    /// Every reported point, in lexicographic order (`x`, then `y`).
308    pub points: Vec<IntersectionPoint>,
309    /// Every overlap, ordered by its lexicographically smaller end, then
310    /// by where the sweep first met it.
311    pub overlaps: Vec<SegmentOverlap>,
312    /// Counters.
313    pub evidence: SweepEvidence,
314}
315
316/// Every intersection among `segments`, exactly, by a Bentley–Ottmann
317/// sweep in `O((n + k) log n)` time for `k` reported incidences.
318///
319/// A point is reported when at least two segments contain it and it is an
320/// endpoint of one of them or a proper crossing of two, with every segment
321/// through it. Each maximal collinear piece covered by a constant set of
322/// two or more segments is reported as a [`SegmentOverlap`]; its ends are
323/// input endpoints and are reported as points too. A zero-length segment is
324/// a point ([`SegmentLocation::Degenerate`]) and takes no part in overlaps.
325///
326/// Every decision is an exact sign, so no tolerance enters. Crossings are
327/// [`ExactPoint2`] rationals; [`IntersectionPoint::rounded`] is their
328/// correctly rounded value, and an input endpoint comes back bit for bit.
329/// Output order is deterministic: points in lexicographic order (`x`, then
330/// `y`), incidences by segment index.
331///
332/// # Errors
333///
334/// [`SegmentSweepError::NonFinite`] when a coordinate is NaN or infinite.
335pub fn segment_intersections(
336    segments: &[[Point2; 2]],
337) -> Result<SegmentIntersections, SegmentSweepError> {
338    let segs = prepare(segments)?;
339    Ok(Sweep::new(segs).run())
340}
341
342// ------------------------------------------------------------ arithmetic
343
344#[derive(Debug, Clone, Copy)]
345enum Axis {
346    X,
347    Y,
348}
349
350fn dy(value: f64) -> Dyadic {
351    Dyadic::from_f64(value)
352}
353
354fn to_i8(sign: Sign) -> i8 {
355    match sign {
356        Sign::Positive => 1,
357        Sign::Negative => -1,
358        _ => 0,
359    }
360}
361
362fn exact_sign(value: &Dyadic) -> i8 {
363    to_i8(value.sign().expect("dyadic signs are always decided"))
364}
365
366fn cmp_f64(a: f64, b: f64) -> Ordering {
367    a.partial_cmp(&b)
368        .expect("coordinates were validated finite")
369}
370
371/// `x * 2^n` without intermediate overflow; for a rounding guess only.
372fn scale2(mut x: f64, mut n: i64) -> f64 {
373    while n > 1000 && x.is_finite() && x != 0.0 {
374        x *= 2f64.powi(1000);
375        n -= 1000;
376    }
377    while n < -1000 && x != 0.0 {
378        x *= 2f64.powi(-1000);
379        n += 1000;
380    }
381    x * 2f64.powi(n as i32)
382}
383
384/// Exact order of one coordinate: disjoint enclosures first, then
385/// `a / wa - b / wb` with the denominators cleared.
386fn cmp_axis(p: &ExactPoint2, q: &ExactPoint2, axis: Axis) -> Ordering {
387    let (pb, qb) = (p.bound(axis), q.bound(axis));
388    if pb.hi() < qb.lo() {
389        return Ordering::Less;
390    }
391    if qb.hi() < pb.lo() {
392        return Ordering::Greater;
393    }
394    let (pn, pw) = p.exact(axis);
395    let (qn, qw) = q.exact(axis);
396    exact_sign(&pn.mul(&qw).sub(&qn.mul(&pw))).cmp(&0)
397}
398
399/// Which side of the line `a -> b` the point lies on: positive for left.
400fn orient_point(a: Point2, b: Point2, p: &ExactPoint2) -> i8 {
401    match &p.repr {
402        Repr::Input(c) => {
403            if *c == a || *c == b {
404                return 0;
405            }
406            to_i8(orient_doubles(a, b, *c))
407        }
408        Repr::Rational(r) => {
409            let (ax, ay) = (Interval::point(a.x), Interval::point(a.y));
410            let bax = Interval::point(b.x).sub(&ax);
411            let bay = Interval::point(b.y).sub(&ay);
412            let value = bax.mul(&r.by.sub(&ay)).sub(&bay.mul(&r.bx.sub(&ax)));
413            if let Some(sign) = value.sign() {
414                return to_i8(sign);
415            }
416            // (b - a) x (p - a) * w, and w > 0.
417            let (ax, ay) = (dy(a.x), dy(a.y));
418            let bax = dy(b.x).sub(&ax);
419            let bay = dy(b.y).sub(&ay);
420            let value = bax
421                .mul(&r.y.sub(&ay.mul(&r.w)))
422                .sub(&bay.mul(&r.x.sub(&ax.mul(&r.w))));
423            exact_sign(&value)
424        }
425    }
426}
427
428/// `cross(u1 - u0, v1 - v0)`: positive when `v` turns left of `u`.
429struct CrossDirections([Point2; 4]);
430
431impl SignExpr for CrossDirections {
432    fn sign_in<T: Arith>(&self) -> Option<Sign> {
433        let [u0, u1, v0, v1] = self.0;
434        let ux = T::from_f64(u1.x).sub(&T::from_f64(u0.x));
435        let uy = T::from_f64(u1.y).sub(&T::from_f64(u0.y));
436        let vx = T::from_f64(v1.x).sub(&T::from_f64(v0.x));
437        let vy = T::from_f64(v1.y).sub(&T::from_f64(v0.y));
438        ux.mul(&vy).sub(&uy.mul(&vx)).sign()
439    }
440}
441
442// ------------------------------------------------------------- segments
443
444/// An input segment with its ends in sweep order.
445#[derive(Debug, Clone, Copy)]
446struct Seg {
447    lo: Point2,
448    hi: Point2,
449    /// `lo` is the input's second point.
450    reversed: bool,
451    degenerate: bool,
452}
453
454impl Seg {
455    fn lo_location(&self) -> SegmentLocation {
456        if self.degenerate {
457            SegmentLocation::Degenerate
458        } else if self.reversed {
459            SegmentLocation::End
460        } else {
461            SegmentLocation::Start
462        }
463    }
464
465    fn hi_location(&self) -> SegmentLocation {
466        if self.reversed {
467            SegmentLocation::Start
468        } else {
469            SegmentLocation::End
470        }
471    }
472}
473
474fn prepare(segments: &[[Point2; 2]]) -> Result<Vec<Seg>, SegmentSweepError> {
475    segments
476        .iter()
477        .enumerate()
478        .map(|(index, [a, b])| {
479            if ![a.x, a.y, b.x, b.y].iter().all(|v| v.is_finite()) {
480                return Err(SegmentSweepError::NonFinite { segment: index });
481            }
482            let reversed = cmp_f64(a.x, b.x).then_with(|| cmp_f64(a.y, b.y)) == Ordering::Greater;
483            let (lo, hi) = if reversed { (*b, *a) } else { (*a, *b) };
484            Ok(Seg {
485                lo,
486                hi,
487                reversed,
488                degenerate: lo == hi,
489            })
490        })
491        .collect()
492}
493
494/// The order of two directions through one point, along the sweep line:
495/// positive when `t` lies above `s` just after the point.
496fn cross_sign(s: &Seg, t: &Seg) -> i8 {
497    let expr = CrossDirections([s.lo, s.hi, t.lo, t.hi]);
498    to_i8(certify(&expr).expect("inputs were validated finite"))
499}
500
501fn boxes_meet(s: &Seg, t: &Seg) -> bool {
502    let (sy0, sy1) = (s.lo.y.min(s.hi.y), s.lo.y.max(s.hi.y));
503    let (ty0, ty1) = (t.lo.y.min(t.hi.y), t.lo.y.max(t.hi.y));
504    s.lo.x <= t.hi.x && t.lo.x <= s.hi.x && sy0 <= ty1 && ty0 <= sy1
505}
506
507/// Whether the segments cross at one point interior to both.
508fn proper_crossing(s: &Seg, t: &Seg) -> bool {
509    if !boxes_meet(s, t) {
510        return false;
511    }
512    let o = |a: Point2, b: Point2, c: Point2| to_i8(orient_doubles(a, b, c));
513    let (o1, o2) = (o(s.lo, s.hi, t.lo), o(s.lo, s.hi, t.hi));
514    if o1 == 0 || o2 == 0 || o1 == o2 {
515        return false;
516    }
517    let (o3, o4) = (o(t.lo, t.hi, s.lo), o(t.lo, t.hi, s.hi));
518    o3 != 0 && o4 != 0 && o3 != o4
519}
520
521/// The crossing of the lines through `s` and `t`, which are not parallel:
522/// `s.lo + (num / den) * (s.hi - s.lo)` with the denominator cleared.
523fn crossing_point(s: &Seg, t: &Seg) -> ExactPoint2 {
524    line_crossing(s.lo, s.hi, t.lo, t.hi).expect("proper crossings are not parallel")
525}
526
527/// The crossing of the lines through `a`-`b` and `c`-`d`, exactly, or
528/// `None` when they are parallel.
529fn line_crossing(a: Point2, b: Point2, c: Point2, d: Point2) -> Option<ExactPoint2> {
530    let (ax, ay) = (dy(a.x), dy(a.y));
531    let (ux, uy) = (dy(b.x).sub(&ax), dy(b.y).sub(&ay));
532    let (cx, cy) = (dy(c.x), dy(c.y));
533    let (vx, vy) = (dy(d.x).sub(&cx), dy(d.y).sub(&cy));
534    let den = ux.mul(&vy).sub(&uy.mul(&vx));
535    let (acx, acy) = (cx.sub(&ax), cy.sub(&ay));
536    let num = acx.mul(&vy).sub(&acy.mul(&vx));
537    let x = ax.mul(&den).add(&num.mul(&ux));
538    let y = ay.mul(&den).add(&num.mul(&uy));
539    ExactPoint2::from_homogeneous(x, y, den)
540}
541
542/// The double nearest to where the lines through `a`-`b` and `c`-`d`
543/// cross, or `None` when they are parallel. Settling puts a proper
544/// crossing of two edges here (#272).
545pub(crate) fn rounded_crossing(a: Point2, b: Point2, c: Point2, d: Point2) -> Option<Point2> {
546    line_crossing(a, b, c, d).map(|p| p.rounded())
547}
548
549// ---------------------------------------------------------------- status
550
551const NIL: u32 = u32::MAX;
552
553#[derive(Debug, Clone, Copy)]
554struct Node {
555    left: u32,
556    right: u32,
557    parent: u32,
558    priority: u64,
559}
560
561/// The sweep status: a treap over segment indices, in order along the
562/// sweep line from below. A node's index is its segment's, so a segment is
563/// removed by handle and never needs comparing to be found.
564///
565/// Priorities come from a fixed-seed generator: expected depth
566/// `O(log n)`, and a reproducible shape.
567struct Status {
568    nodes: Vec<Node>,
569    root: u32,
570    state: u64,
571}
572
573impl Status {
574    fn new(count: usize) -> Self {
575        let empty = Node {
576            left: NIL,
577            right: NIL,
578            parent: NIL,
579            priority: 0,
580        };
581        Self {
582            nodes: vec![empty; count],
583            root: NIL,
584            state: 0x9E37_79B9_7F4A_7C15,
585        }
586    }
587
588    fn random(&mut self) -> u64 {
589        // xorshift64*
590        self.state ^= self.state >> 12;
591        self.state ^= self.state << 25;
592        self.state ^= self.state >> 27;
593        self.state.wrapping_mul(0x2545_F491_4F6C_DD1D)
594    }
595
596    fn node(&self, id: u32) -> &Node {
597        &self.nodes[id as usize]
598    }
599
600    fn node_mut(&mut self, id: u32) -> &mut Node {
601        &mut self.nodes[id as usize]
602    }
603
604    /// The first node, in order, for which `pred` holds; `pred` must be
605    /// false on a prefix and true on the rest.
606    fn first_where(&self, mut pred: impl FnMut(u32) -> bool) -> u32 {
607        let (mut current, mut found) = (self.root, NIL);
608        while current != NIL {
609            if pred(current) {
610                found = current;
611                current = self.node(current).left;
612            } else {
613                current = self.node(current).right;
614            }
615        }
616        found
617    }
618
619    fn min_from(&self, mut id: u32) -> u32 {
620        while self.node(id).left != NIL {
621            id = self.node(id).left;
622        }
623        id
624    }
625
626    fn max_from(&self, mut id: u32) -> u32 {
627        while self.node(id).right != NIL {
628            id = self.node(id).right;
629        }
630        id
631    }
632
633    fn last(&self) -> u32 {
634        if self.root == NIL {
635            NIL
636        } else {
637            self.max_from(self.root)
638        }
639    }
640
641    fn next(&self, mut id: u32) -> u32 {
642        if self.node(id).right != NIL {
643            return self.min_from(self.node(id).right);
644        }
645        loop {
646            let parent = self.node(id).parent;
647            if parent == NIL || self.node(parent).left == id {
648                return parent;
649            }
650            id = parent;
651        }
652    }
653
654    fn prev(&self, mut id: u32) -> u32 {
655        if self.node(id).left != NIL {
656            return self.max_from(self.node(id).left);
657        }
658        loop {
659            let parent = self.node(id).parent;
660            if parent == NIL || self.node(parent).right == id {
661                return parent;
662            }
663            id = parent;
664        }
665    }
666
667    /// Replace `old` by `new` as a child of `parent` (or as the root).
668    fn relink(&mut self, parent: u32, old: u32, new: u32) {
669        if parent == NIL {
670            self.root = new;
671        } else if self.node(parent).left == old {
672            self.node_mut(parent).left = new;
673        } else {
674            self.node_mut(parent).right = new;
675        }
676        if new != NIL {
677            self.node_mut(new).parent = parent;
678        }
679    }
680
681    /// Rotate `id` above its parent, keeping the in-order sequence.
682    fn rotate_up(&mut self, id: u32) {
683        let parent = self.node(id).parent;
684        let grand = self.node(parent).parent;
685        if self.node(parent).left == id {
686            let middle = self.node(id).right;
687            self.node_mut(parent).left = middle;
688            if middle != NIL {
689                self.node_mut(middle).parent = parent;
690            }
691            self.node_mut(id).right = parent;
692        } else {
693            let middle = self.node(id).left;
694            self.node_mut(parent).right = middle;
695            if middle != NIL {
696                self.node_mut(middle).parent = parent;
697            }
698            self.node_mut(id).left = parent;
699        }
700        self.node_mut(parent).parent = id;
701        self.relink(grand, parent, id);
702    }
703
704    /// Insert `id` immediately before `before`, or last when `before` is
705    /// [`NIL`].
706    fn insert_before(&mut self, id: u32, before: u32) {
707        let priority = self.random();
708        *self.node_mut(id) = Node {
709            left: NIL,
710            right: NIL,
711            parent: NIL,
712            priority,
713        };
714        if self.root == NIL {
715            self.root = id;
716            return;
717        }
718        if before == NIL {
719            let last = self.max_from(self.root);
720            self.node_mut(last).right = id;
721            self.node_mut(id).parent = last;
722        } else if self.node(before).left == NIL {
723            self.node_mut(before).left = id;
724            self.node_mut(id).parent = before;
725        } else {
726            let last = self.max_from(self.node(before).left);
727            self.node_mut(last).right = id;
728            self.node_mut(id).parent = last;
729        }
730        while self.node(id).parent != NIL
731            && self.node(self.node(id).parent).priority < self.node(id).priority
732        {
733            self.rotate_up(id);
734        }
735    }
736
737    fn remove(&mut self, id: u32) {
738        loop {
739            let Node { left, right, .. } = *self.node(id);
740            if left == NIL || right == NIL {
741                let child = if left == NIL { right } else { left };
742                let parent = self.node(id).parent;
743                self.relink(parent, id, child);
744                return;
745            }
746            let up = if self.node(left).priority > self.node(right).priority {
747                left
748            } else {
749                right
750            };
751            self.rotate_up(up);
752        }
753    }
754}
755
756// ----------------------------------------------------------------- sweep
757
758struct Piece {
759    from: ExactPoint2,
760    to: Option<ExactPoint2>,
761    segments: Vec<usize>,
762}
763
764struct Sweep {
765    segs: Vec<Seg>,
766    /// Event points, each with the segments that start there.
767    queue: BTreeMap<ExactPoint2, Vec<u32>>,
768    status: Status,
769    /// The open overlap each segment is part of.
770    open: Vec<Option<usize>>,
771    pieces: Vec<Piece>,
772    /// Pieces that ended at the current event, which may continue.
773    closed_here: Vec<usize>,
774    points: Vec<IntersectionPoint>,
775    evidence: SweepEvidence,
776}
777
778impl Sweep {
779    // The only interior mutability in a point is its cached rounding,
780    // which order and equality never read.
781    #[allow(clippy::mutable_key_type)]
782    fn new(segs: Vec<Seg>) -> Self {
783        let mut queue: BTreeMap<ExactPoint2, Vec<u32>> = BTreeMap::new();
784        for (index, seg) in segs.iter().enumerate() {
785            queue
786                .entry(ExactPoint2::input(seg.lo))
787                .or_default()
788                .push(index as u32);
789            if !seg.degenerate {
790                queue.entry(ExactPoint2::input(seg.hi)).or_default();
791            }
792        }
793        let count = segs.len();
794        Self {
795            status: Status::new(count),
796            open: vec![None; count],
797            pieces: Vec::new(),
798            closed_here: Vec::new(),
799            points: Vec::new(),
800            evidence: SweepEvidence {
801                segments: count,
802                ..SweepEvidence::default()
803            },
804            queue,
805            segs,
806        }
807    }
808
809    fn run(mut self) -> SegmentIntersections {
810        while let Some((p, starts)) = self.queue.pop_first() {
811            self.evidence.events += 1;
812            self.event(&p, &starts);
813        }
814        let mut overlaps: Vec<SegmentOverlap> = self
815            .pieces
816            .into_iter()
817            .map(|piece| {
818                let to = piece.to.expect("every overlap ends at an event");
819                SegmentOverlap {
820                    from: endpoint(&piece.from),
821                    to: endpoint(&to),
822                    segments: piece.segments,
823                }
824            })
825            .collect();
826        overlaps
827            .sort_by(|a, b| cmp_f64(a.from.x, b.from.x).then_with(|| cmp_f64(a.from.y, b.from.y)));
828        SegmentIntersections {
829            points: self.points,
830            overlaps,
831            evidence: self.evidence,
832        }
833    }
834
835    fn event(&mut self, p: &ExactPoint2, starts: &[u32]) {
836        // The active segments through `p` are one contiguous run: the
837        // status is ordered along the sweep line just before `p`.
838        let segs = &self.segs;
839        let side = |id: u32| {
840            let seg = &segs[id as usize];
841            orient_point(seg.lo, seg.hi, p)
842        };
843        let first = self.status.first_where(|id| side(id) <= 0);
844        let mut block = Vec::new();
845        let mut above = first;
846        while above != NIL && side(above) == 0 {
847            block.push(above);
848            above = self.status.next(above);
849        }
850        let below = if first == NIL {
851            self.status.last()
852        } else {
853            self.status.prev(first)
854        };
855
856        // A crossing event is never an input endpoint (endpoints are
857        // queued from the start and deduplicate it), so only an input
858        // event can end a segment.
859        let at = p.as_input();
860        let ended: Vec<bool> = block
861            .iter()
862            .map(|&id| at.is_some_and(|q| segs[id as usize].hi == q))
863            .collect();
864
865        self.report(p, starts, &block, &ended);
866        self.close_overlaps(p, &block);
867
868        for &id in &block {
869            self.status.remove(id);
870        }
871        let mut through: Vec<u32> = starts
872            .iter()
873            .copied()
874            .filter(|&id| !self.segs[id as usize].degenerate)
875            .chain(
876                block
877                    .iter()
878                    .zip(&ended)
879                    .filter(|(_, &ended)| !ended)
880                    .map(|(&id, _)| id),
881            )
882            .collect();
883        let segs = &self.segs;
884        through.sort_by(
885            |&s, &t| match cross_sign(&segs[s as usize], &segs[t as usize]) {
886                1 => Ordering::Less,
887                -1 => Ordering::Greater,
888                _ => s.cmp(&t),
889            },
890        );
891        for &id in &through {
892            self.status.insert_before(id, above);
893        }
894        self.open_overlaps(p, &through);
895
896        match (through.first(), through.last()) {
897            (Some(&low), Some(&high)) => {
898                self.check(below, low, p);
899                self.check(high, above, p);
900            }
901            _ => self.check(below, above, p),
902        }
903    }
904
905    fn report(&mut self, p: &ExactPoint2, starts: &[u32], block: &[u32], ended: &[bool]) {
906        if starts.len() + block.len() < 2 {
907            return;
908        }
909        let mut incidences = Vec::with_capacity(starts.len() + block.len());
910        for &id in starts {
911            incidences.push(Incidence {
912                segment: id as usize,
913                location: self.segs[id as usize].lo_location(),
914            });
915        }
916        for (&id, &ends) in block.iter().zip(ended) {
917            let location = if ends {
918                self.segs[id as usize].hi_location()
919            } else {
920                SegmentLocation::Interior
921            };
922            incidences.push(Incidence {
923                segment: id as usize,
924                location,
925            });
926        }
927        // Every event is an endpoint (a segment starts or ends here) or a
928        // proper crossing of two segments that are not collinear, so the
929        // interior of an overlap is never an event and needs no filter.
930        incidences.sort_unstable();
931        self.points.push(IntersectionPoint {
932            rounded: p.rounded(),
933            point: p.clone(),
934            incidences,
935        });
936    }
937
938    fn close_overlaps(&mut self, p: &ExactPoint2, block: &[u32]) {
939        self.closed_here.clear();
940        for &id in block {
941            if let Some(index) = self.open[id as usize].take() {
942                let piece = &mut self.pieces[index];
943                if piece.to.is_none() {
944                    piece.to = Some(p.clone());
945                    self.closed_here.push(index);
946                }
947            }
948        }
949    }
950
951    /// Runs of equal direction in `through` share a line from `p` on; each
952    /// run of two or more is an overlap. A run with the same segments as a
953    /// piece that just ended here continues that piece.
954    fn open_overlaps(&mut self, p: &ExactPoint2, through: &[u32]) {
955        let mut start = 0;
956        while start < through.len() {
957            let head = &self.segs[through[start] as usize];
958            let mut end = start + 1;
959            while end < through.len() && cross_sign(head, &self.segs[through[end] as usize]) == 0 {
960                end += 1;
961            }
962            if end - start >= 2 {
963                let mut members: Vec<usize> =
964                    through[start..end].iter().map(|&id| id as usize).collect();
965                members.sort_unstable();
966                let resumed = self
967                    .closed_here
968                    .iter()
969                    .copied()
970                    .find(|&index| self.pieces[index].segments == members);
971                let index = if let Some(index) = resumed {
972                    self.pieces[index].to = None;
973                    index
974                } else {
975                    self.pieces.push(Piece {
976                        from: p.clone(),
977                        to: None,
978                        segments: members.clone(),
979                    });
980                    self.pieces.len() - 1
981                };
982                for &member in &members {
983                    self.open[member] = Some(index);
984                }
985            }
986            start = end;
987        }
988    }
989
990    /// Schedule the crossing of two neighbours if it lies ahead.
991    fn check(&mut self, low: u32, high: u32, p: &ExactPoint2) {
992        if low == NIL || high == NIL {
993            return;
994        }
995        let (s, t) = (&self.segs[low as usize], &self.segs[high as usize]);
996        if !proper_crossing(s, t) {
997            return;
998        }
999        let q = crossing_point(s, t);
1000        if q > *p {
1001            if !self.queue.contains_key(&q) {
1002                self.evidence.crossings += 1;
1003            }
1004            self.queue.entry(q).or_default();
1005        }
1006    }
1007}
1008
1009/// An overlap end, which is always an input endpoint (see the module
1010/// documentation).
1011fn endpoint(point: &ExactPoint2) -> Point2 {
1012    debug_assert!(point.as_input().is_some(), "overlap ends are input points");
1013    point.as_input().unwrap_or_else(|| point.rounded())
1014}