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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
// src/orient2d.rs
//! The `orient2d` geometric predicate.
//!
//! This module implements Shewchuk's three-stage adaptive `orient2d` predicate,
//! which determines the signed orientation (winding order) of three points in
//! the plane.
use crate;
use crate;
use crate;
use crate;
use crate::;
use ;
/// Counts entries to Stage 3. Present only in this crate's own unit-test
/// builds, so the unit tests can check that near-degenerate input reaches the
/// exact expansion; the public `stage-counters` feature is the supported way
/// to observe stages from outside.
pub static ORIENT2D_EXACT_COUNT: AtomicUsize = new;
/// Certifies `Sign::Zero` for the two kinds of degenerate triple that can be
/// recognized exactly, without any arithmetic beyond comparisons.
///
/// Returns `true` only when the exact determinant is zero.
///
/// # Which triples it catches
///
/// - **A repeated point.** Two equal points make two rows of the orientation
/// determinant equal, so the determinant is zero whatever the third point
/// is. The second clause catches `pa == pb`; the first catches `pa == pc`
/// and `pb == pc`, whose differences against `pc` are zero.
/// - **An axis-aligned triple.** If all three points share an x coordinate,
/// both x differences are zero; if they share a y coordinate, both y
/// differences are. Either way each of the two products in the determinant
/// has a factor that is exactly zero.
///
/// # Why it is exact
///
/// With gradual underflow, `fl(x - y) == 0.0` if and only if `x == y`: every
/// finite `f64` is a multiple of `2^-1074`, so a non-zero difference has
/// magnitude at least `2^-1074`, which is representable, and rounding is
/// monotone. (Rust never enables flush-to-zero, under which this would fail.)
/// An overflowing difference is infinite, not zero, so it cannot trigger the
/// filter either. So a zero difference here means the two coordinates are
/// equal, and the corresponding product is zero as a real number and not only
/// as a floating-point value.
///
/// Comparing coordinates with `==` is likewise exact. `-0.0 == 0.0` is true,
/// which is correct: they are the same real number.
///
/// # Why the form is symmetric
///
/// The two clauses together catch the same triples whatever order the three
/// arguments arrive in, so the filter's answer does not depend on the
/// caller's argument order or on the cyclic rotation below. The first clause
/// alone looks only at differences against `pc`, so it cannot see `pa == pb`;
/// on real workloads, where degenerate triples arrive in every order, that
/// would miss about half of them.
///
/// # Why it is worth having
///
/// Without it every exactly degenerate call runs the whole adaptive ladder
/// and then the exact integer stage, roughly two orders of magnitude slower
/// than the fast path. Exact degeneracy is common in real geometry, and most
/// of it is a repeated vertex or an axis-aligned edge, which this filter
/// certifies by comparisons alone. What it leaves is collinearity in a
/// general direction, which no comparison can certify.
///
/// Reference: Bartels, Fisikopoulos & Weiser 2023, Definition 6 (zero-filter)
/// and Example 7, which derives this condition for the 2D orientation
/// predicate.
///
/// `clippy::float_cmp` is allowed here, and only here, because the exactness
/// argument above is the whole point of the filter: these comparisons ask
/// whether two values are the same real number, which `==` answers exactly,
/// and a tolerance would turn an exact certificate into a guess.
/// The fast filter, in the underflow-protected form of Bartels et al. 2023,
/// Theorem 1(2).
///
/// Returns `Some(sign)` when the sign of the floating-point determinant is
/// certified to be the sign of the exact determinant, and `None` when it is
/// not. **The certificate holds for every finite input**, with no assumption
/// that the evaluation is free of underflow or overflow.
///
/// # Why Shewchuk's form is not enough
///
/// Shewchuk's filter compares `|det|` with `A · (|detleft| + |detright|)`.
/// Its derivation gives every operation a small *relative* error, which is
/// what rounding in the normal range does. A product that lands among the
/// subnormals instead carries an *absolute* error of up to `2^-1075`, which
/// that bound does not cover; and when the two products are small enough, the
/// bound itself underflows to zero, at which point the comparison accepts any
/// non-zero `det`, including one whose sign is wrong. Bartels et al. 2023
/// give this as their Example 1, and the same failure is reachable in all
/// four predicates.
///
/// # The remedy
///
/// Add `U_N` after every product in the magnitude, and `U_S` to the final
/// bound; compare with a strict `>`. Each `U_N` dominates the absolute error
/// of the product it follows, and the `U_S` makes the bound non-zero no
/// matter how small the input, so a zero determinant can never be certified.
/// The cost is three additions and one comparison.
///
/// The magnitude is summed in the association order of the determinant, as
/// the paper's rules require: the error bound of a sum is derived from the
/// bounds of the two operands it is formed from.
///
/// # Overflow
///
/// If any intermediate overflows, the magnitude overflows with it: every term
/// of the magnitude is non-negative, so no cancellation can bring it back
/// into range. The bound is then infinite and both comparisons fail, so an
/// overflowing input is passed on rather than certified. (`det` itself cannot
/// be finite while the magnitude is infinite, since the magnitude dominates
/// it term for term.)
///
/// # Constants
///
/// Shewchuk's `CCW_ERR_BOUND_A`, `(3 + 16ε)ε`, satisfies the paper's
/// requirement for this expression tree, which is anything above
/// `(3 + 12ε)ε`. A constant as small as `(3 + 8ε)ε` would not.
/// Tests the orientation of the triangle formed by `pa`, `pb`, and `pc`.
///
/// Returns [`Sign::Positive`] if the triangle is oriented counterclockwise,
/// [`Sign::Negative`] if clockwise, and [`Sign::Zero`] if the three points
/// are collinear.
///
/// # Mathematical definition
///
/// The predicate evaluates the sign of the 3×3 determinant:
///
/// ```text
/// | pa.x pa.y 1 |
/// | pb.x pb.y 1 |
/// | pc.x pc.y 1 |
/// ```
///
/// which equals `(pa.x − pc.x) · (pb.y − pc.y) − (pa.y − pc.y) · (pb.x − pc.x)`.
///
/// The sign encodes the winding order of the triangle: a positive value means
/// the triangle `pa → pb → pc` winds counterclockwise as viewed in the standard
/// orientation (y-axis up, x-axis right). This is the fundamental question for
/// point-in-triangle tests, convex-hull construction, and polygon orientation
/// checks: all of these reduce to knowing which side of a directed line a point
/// lies on.
///
/// # Robustness: four stages
///
/// 1. **The zero filter**, `orient2d_is_certainly_zero`: a repeated point
/// or an axis-aligned triple is certified `Zero` by comparisons alone.
/// 2. **The fast filter**, `orient2d_filter_raw`: the determinant in native
/// `f64`, with the underflow-protected error bound of Bartels et al. 2023.
/// Valid for every finite input, so a certificate here is final.
/// 3. **The adaptive expansion stages**, `orient2d_adapt`: exact products,
/// then the full exact expansion, guarded by Shewchuk's Stage B and C
/// bounds. These run only on input inside the exactness window of
/// `crate::range`, where binary64 arithmetic provably behaves as
/// Shewchuk's unbounded-exponent model does, so his bounds hold.
/// 4. **The exact integer stage**, `orient2d_exact_integer`: fixed-width
/// integer arithmetic on the original coordinates. It answers every input
/// the earlier stages leave undecided, and every input that cannot be
/// brought into the window at all.
///
/// Each stage either certifies a sign or passes the input on; no stage
/// returns an uncertified answer. Stage 4 costs about two orders of magnitude
/// more than the fast filter, and input that is neither exactly degenerate
/// nor spread over more bits than the window never reaches it.
///
/// # Non-finite inputs
///
/// If any input coordinate is NaN or infinite, the predicate returns
/// [`Err(NonFinite)`](NonFinite): a non-finite coordinate has no geometric
/// meaning, so there is no correct [`Sign`] to return. For *finite* inputs the
/// function always returns `Ok` with the exact sign.
///
/// # References
///
/// Shewchuk (1997), `orient2d` and `orient2dadapt`, predicates.c.
///
/// Bartels, Fisikopoulos & Weiser (2023), Theorem 1(2) and Definition 6.
///
/// # Errors
///
/// Returns [`NonFinite`] when any input coordinate is not finite. This is
/// the only error case: a NaN or infinite coordinate has no geometric
/// meaning, and it is rejected before the adaptive stages so that it can
/// never masquerade as a degenerate [`Sign::Zero`] result. A non-finite
/// *intermediate* is not an error; it is a recoverable artifact of finite
/// input, resolved by the exact integer stage.
/// Shewchuk's Stage A on in-window coordinates, then Stages 2 and 3.
///
/// The caller guarantees that the coordinates are inside
/// [`Window::ORIENT2D`], as given or after an exact rescale. Inside the
/// window no operation of these stages can underflow inexactly or overflow,
/// so Shewchuk's analysis applies to the binary64 execution and his
/// opposite-sign early returns and error bounds are valid as written. Outside
/// it they are not: an inexact underflow inside an expansion would make it
/// sum to the wrong value, with nothing to show for it.
///
/// This Stage A is Shewchuk's rather than the Bartels form: the raw filter
/// has already run, and inside the window the two agree about which inputs
/// they certify, so the cheaper one is used. Its purpose here is to catch the
/// input that the raw filter could not certify only because the rescale had
/// not happened yet.
///
/// A `Sign::Zero` return means no stage could certify a sign; the caller
/// resolves it exactly.
/// Stages 2 and 3 of the adaptive `orient2d` predicate.
///
/// Ports `orient2dadapt` from Shewchuk's `predicates.c` (1997).
///
/// ## Expansion sizes (from Shewchuk's analysis)
///
/// | Variable | Max components | Meaning |
/// |---|---|---|
/// | `B` | 4 | Exact two-product expansion of the main determinant terms |
/// | `u` | 4 | Correction term (each is a `two_two_diff` result) |
/// | `C1` | 8 | `B + u1` |
/// | `C2` | 12 | `C1 + u2` |
/// | `D` | 16 | `C2 + u3` — the full exact expansion |
///
/// ## Stage 2
///
/// Uses `two_product` to compute `B = acx*bcy - acy*bcx` without rounding
/// error in the multiplications. The estimate of B is the sum of all four
/// expansion components (Shewchuk's `estimate()` function), NOT just `B[3]`.
/// Using only `B[3]` fails when `two_two_diff` produces an expansion like
/// `[0, -8.665e178, 0, 0]` where `B[3]=0` but the true B is large and
/// non-zero. Tests the sum against `CCW_ERR_BOUND_B * detsum`. If the bound
/// is satisfied, the sign of the sum is returned without entering Stage 3.
///
/// ## Stage 3 (exact path)
///
/// Fires only when Stage 2 is also insufficient. Adds three correction
/// expansions to `B`, one for each pair of subtraction-error tails:
///
/// - `u1 = acxtail*bcy − acytail*bcx`
/// - `u2 = acx*bcytail − acy*bcxtail`
/// - `u3 = acxtail*bcytail − acytail*bcxtail`
///
/// Each correction is computed with `two_product` + `two_two_diff` and merged
/// with `expansion_sum`. The sign of the last non-zero component of the final
/// 16-term expansion `D` is the sign of the exact determinant. The
/// non-overlapping property guarantees this component determines the sign.
///
/// The `#[cfg(test)] ORIENT2D_EXACT_COUNT` atomic counter is incremented at
/// the entry to Stage 3 so tests can verify the exact path fires on
/// near-degenerate input.
///
/// ## Difference from predicates.c
///
/// `fast_expansion_sum_zeroelim` (C) is `expansion_sum` here throughout.
/// Both produce the exact sum of two expansions. The fast variant
/// (Shewchuk 1997, Theorem 13) requires its inputs to be *strongly*
/// nonoverlapping and relies on round-to-even; `expansion_sum` (Theorem 12)
/// needs only nonoverlapping inputs, the weaker property and the one the
/// other expansion operations here produce, at a small cost in speed.
// ===========================================================================
// Stage 4: Exact integer fallback
// ===========================================================================
/// Stage 4: exact integer arithmetic in `WideInt<66>`, 4,224 bits.
///
/// Reached in two cases: the input spans more bits than the exactness window
/// allows, so the expansion stages cannot run on it; or the expansion stages
/// returned `Zero`, which is not a certificate. In practice the second case is
/// almost always an exact zero, and this stage confirms it.
///
/// Each coordinate is converted to an integer scaled by `2^1074` using
/// [`crate::exact_int::f64_to_orient_int`], which is exact for every finite
/// `f64`, and the determinant is evaluated with no rounding.
///
/// Bit-width argument: every finite `f64` is below `2^1024` in magnitude, so a
/// scaled coordinate is below `2^2098`; a difference is below `2^2099`, a
/// product of two differences below `2^4198`, and the two-term determinant
/// below `2^4199`, which fits in 4,224 bits with a sign.
///
/// It is called with the caller's coordinates, before any rotation or
/// rescaling, so that what it decides is exactly the caller's question.
// ===========================================================================
// Tests
// ===========================================================================
// test-lint-posture: see the workspace lint comment in Cargo.toml