manifold_rust/robust/exact/mod.rs
1// robust/exact/mod.rs — Exact geometric arithmetic for the robust boolean
2// engine (src/robust).
3//
4// Layered design:
5// rational.rs — BigRational point types (R2/R3) and correctly rounded
6// rational→f64 conversion.
7// predicates.rs — fully exact predicates and geometric constructions on
8// rational points; ground truth for everything.
9// filtered.rs — f64 entry points with Shewchuk-style static error-bound
10// filters that escalate to predicates.rs only when the
11// float computation cannot certify a sign.
12//
13// The exact boolean pipeline (src/boolean3.rs) never calls into this module.
14
15pub mod approx;
16pub mod filtered;
17pub mod intpred;
18pub mod predicates;
19pub mod rational;
20
21#[cfg(test)]
22mod tests;
23
24use num_rational::BigRational;
25use num_traits::Signed;
26
27/// Sign of an exactly evaluated quantity. The whole robust pipeline reasons
28/// in terms of signs; magnitudes only matter inside constructions.
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
30pub enum Sign {
31 Neg,
32 Zero,
33 Pos,
34}
35
36impl Sign {
37 /// Sign of a finite f64 (`-0.0` is `Zero`). Only meaningful when the
38 /// value is known to carry the correct sign of the exact quantity.
39 #[inline]
40 pub fn of_f64(v: f64) -> Sign {
41 if v > 0.0 {
42 Sign::Pos
43 } else if v < 0.0 {
44 Sign::Neg
45 } else {
46 Sign::Zero
47 }
48 }
49
50 #[inline]
51 pub fn of_rat(r: &BigRational) -> Sign {
52 if r.is_positive() {
53 Sign::Pos
54 } else if r.is_negative() {
55 Sign::Neg
56 } else {
57 Sign::Zero
58 }
59 }
60
61 /// The opposite sign (`Zero` stays `Zero`).
62 #[inline]
63 pub fn flip(self) -> Sign {
64 match self {
65 Sign::Neg => Sign::Pos,
66 Sign::Zero => Sign::Zero,
67 Sign::Pos => Sign::Neg,
68 }
69 }
70
71 #[inline]
72 pub fn as_i32(self) -> i32 {
73 match self {
74 Sign::Neg => -1,
75 Sign::Zero => 0,
76 Sign::Pos => 1,
77 }
78 }
79
80 #[inline]
81 pub fn is_zero(self) -> bool {
82 self == Sign::Zero
83 }
84}