#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Precision {
pub default_tolerance: f64,
pub min_tolerance: f64,
pub max_tolerance: f64,
pub angular_tolerance: f64,
pub parametric_tolerance: f64,
pub check_samples: usize,
}
impl Precision {
pub const DEFAULT: Precision = Precision {
default_tolerance: 1e-7,
min_tolerance: 1e-12,
max_tolerance: 1e-2,
angular_tolerance: 1e-12,
parametric_tolerance: 1e-7,
check_samples: 23,
};
pub fn is_consistent(&self) -> bool {
let finite_positive = |x: f64| x.is_finite() && x > 0.0;
finite_positive(self.min_tolerance)
&& finite_positive(self.default_tolerance)
&& finite_positive(self.max_tolerance)
&& finite_positive(self.angular_tolerance)
&& finite_positive(self.parametric_tolerance)
&& self.min_tolerance <= self.default_tolerance
&& self.default_tolerance <= self.max_tolerance
&& self.check_samples >= 1
}
}
impl Default for Precision {
fn default() -> Self {
Self::DEFAULT
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_are_consistent() {
assert!(Precision::DEFAULT.is_consistent());
assert_eq!(Precision::default(), Precision::DEFAULT);
}
#[test]
fn disordered_or_non_finite_is_inconsistent() {
let p = Precision {
min_tolerance: 1.0,
..Precision::DEFAULT
};
assert!(!p.is_consistent());
let p = Precision {
max_tolerance: f64::NAN,
..Precision::DEFAULT
};
assert!(!p.is_consistent());
let p = Precision {
check_samples: 0,
..Precision::DEFAULT
};
assert!(!p.is_consistent());
}
#[cfg(feature = "serde")]
#[test]
fn serde_round_trip() {
let p = Precision {
default_tolerance: 1e-6,
..Precision::DEFAULT
};
let text = serde_json::to_string(&p).unwrap();
let back: Precision = serde_json::from_str(&text).unwrap();
assert_eq!(p, back);
}
}