Skip to main content

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}