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