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}