1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
// This module implements a simplified variant of the [Bentley-Ottmann] sweep line algorithm
// for efficiently finding line segment intersections, exposed through the [`Intersections`] iterator.
//
// ## Relationship to Classical Bentley-Ottmann Algorithm
//
// The classical Bentley-Ottmann algorithm uses three key data structures:
// 1. **Event queue**: A priority queue of sweep events (segment start/end points and intersections)
// 2. **Status structure**: A balanced binary search tree tracking active segments sorted by y-coordinate
// 3. **Event handling**: Dynamic insertion of newly discovered intersection events
//
// This implementation simplifies the classical approach in several ways:
//
// ### Simplifications from Classical Algorithm:
//
// 1. **No explicit event queue**: Instead of a priority queue, events are stored in vectors
// and sorted once. This has the same O(n log n) complexity but a simpler implementation.
// This is similar to [Chen & Chan, 2003].
// Further, **Only INSERT (segment start) events are sorted**. We only need the DELETE event
// (segment end) of the "current" event, which is already available to use by being at the
// front of the INSERT events. Rather than sort DELETE events separately, they are instead stored
// alongside their INSERT.
//
// 2. **No binary search tree**: Rather than maintaining a balanced BST of active segments,
// we use pre-sorted iteration with early termination based on x-coordinate bounds.
// **This is a key difference from traditional BO**: In traditional BO, the BST allows
// tracking only the segments "above and below" the active segment - those are the only
// ones which could intersect. Our simplified sweep checks **all x-overlapping segments**
// for intersection, which means we'll find intersections regardless of multiple segment
// intersections at the same point, but affects the runtime complexity.
//
// 3. **No intersection events**: The classical algorithm discovers intersections during the sweep
// and adds them as new events. This implementation instead relies on iteration, and yields
// intersections immediately as they are discovered.
//
// ### Algorithm Flow
//
// 1. **Preprocessing**:
// - Convert line segments to `SweepLineInterval`s with left (INSERT) and right (DELETE) x-coordinates
// - Sort intervals by their left (INSERT) x-coordinate
//
// 2. **Sweep Execution**:
// - Process intervals in sorted order (left to right).
// - For each interval, check all subsequent intervals that start before it ends. These intervals overlap in their x-coordinates and so are candidates for intersection.
// - Apply `line_intersection` test to confirm actual intersections.
//
// 3. **Output**:
// - Yield intersection results as they are discovered during the sweep.
//
// ## Runtime Complexity
//
// This approach changes the runtime complexity from the classical BO algorithm's
// O((n + k) log n) to **O((n + m) log n)**, where:
// - n is the number of line segments
// - k is the number of actual intersections
// - m is the number of x-coordinate overlaps (and m >= k)
//
// ## Tradeoffs
//
// **Advantages**:
// - More robust: finds intersections regardless of multiple segment intersections at the same point
// - Simpler implementation with fewer data structures
// - Speed gains from reduced algorithmic complexity
//
// **Disadvantages**:
// - More susceptible to pathological data: if most lines overlap without intersecting,
// this simplified sweep performs worse than traditional BO
// - Checks more segment pairs than strictly necessary in some cases
//
// [Bentley-Ottmann]: https://en.wikipedia.org/wiki/Bentley%E2%80%93Ottmann_algorithm
// [Chen & Chan, 2003]: https://en.wikipedia.org/wiki/Bentley%E2%80%93Ottmann_algorithm#CITEREFChenChan2003
use crateGeoNum;
use crate;
use Debug;
pub use Cross;
/// Find all intersections within a collection of line segments using a simplified Bentley-Ottmann
/// sweep.
///
/// The input line segments must implement the [`Cross`] trait.
///
/// Yields `(Cross, Cross, LineIntersection)` tuples for each pair of input lines that intersect.
///
/// This is a drop-in replacement for computing [`LineIntersection`] over all pairs of the
/// collection.
///
/// ## Performance Characteristics
///
/// This implementation is most effective when you have many line segments with sparse intersections,
/// but even quite dense intersections are competitive in all but extreme cases.
///
/// As a rule of thumb, if each segment intersects fewer than 10% of the total segments, you can be
/// confident that this algorithm will be competitive with or better than brute force.
/// For a concrete example, given 1,000 line segments, you'd need more than 100,000 intersections
/// between them before brute force would be faster.
///
/// ## Examples
///
/// ```
/// use geo::Line;
/// use geo::algorithm::sweep::Intersections;
/// use std::iter::FromIterator;
/// let input = vec![
/// Line::from([(1., 0.), (0., 1.)]),
/// Line::from([(0., 0.), (1., 1.)]),
/// ];
/// let intersections: Vec<_> = Intersections::from_iter(input).collect();
/// // Check that we get the expected intersection
/// assert_eq!(intersections.len(), 1);
/// ```
///
/// [Bentley-Ottmann]: https://en.wikipedia.org/wiki/Bentley%E2%80%93Ottmann_algorithm
/// A line segment interval for sweep line algorithms.
///
/// Stores the x-bounds of a line segment so the sweep line can uniformly process
/// segments from left to right (-x to +x), regardless of the original segment orientation.
/// The SweepLineIndex tracks events in the sweep line algorithm.
///
/// Events represent the start or end points of line segments.
/// Insert events happen at the left end of a segment, delete events at the right end.
///
/// # Event Relationships
///
/// Each line segment generates two events: an `INSERT` event at its left end and
/// a `DELETE` event at its right end.
///
/// # Implementation Note: Why No Binary Search Tree or Priority Queue?
///
/// The Bentley-Ottmann algorithm as described typically uses three tracking data structures:
///
/// 1. Separate `INSERT` and `DELETE` **events**.
/// 2. A **priority queue** to process these events in coordinate order
/// 3. A **balanced binary search tree** to track active segments sorted by their `y`-coordinate position
///
/// This implementation avoids all three:
///
/// - Instead of a priority queue, **events are stored in a vec and sorted once**, and then the events are processed in order.
/// This has the same asymptotic complexity.
///
/// - Instead of separate `INSERT` and `DELETE` events, we track a single active segment. The access pattern is such that
/// we only ever need the `DELETE` event of that active segment, so it makes sense to store it directly with the INSERT
/// rather than track DELETE events separately.
///
/// - Instead of a binary search tree, to track our active segments, we take advantage of our events being pre-sorted,
/// and leverage iteration, bailing out when we've passed the bounds of our active segment.
/// Helper function to check if two intervals overlap on the `x`-axis
///
/// This determines which segments might geometrically intersect during the sweep.
/// We use `total_cmp` for robust floating-point comparisons to handle edge cases
/// involving very close values.