Skip to main content

arris_math/
tolerance.rs

1//! The tolerance pair an algorithm takes.
2
3use crate::Precision;
4
5/// What a geometric algorithm needs to decide "the same" and "parallel":
6/// a length and an angle. Derived from the model's [`Precision`] by
7/// [`Precision::tolerance`] or from an entity's own tolerance by the
8/// operation that owns it — never a literal in an algorithm
9/// (`docs/DATA-MODEL.md` §Tolerances).
10///
11/// ```
12/// use arris_math::{Precision, Tolerance};
13///
14/// let tol: Tolerance = Precision::DEFAULT.tolerance();
15/// assert_eq!(tol.linear, Precision::DEFAULT.default_tolerance);
16/// assert_eq!(tol.angular, Precision::DEFAULT.angular_tolerance);
17/// ```
18#[derive(Debug, Clone, Copy, PartialEq)]
19pub struct Tolerance {
20    /// Two points closer than this are the same point; a distance below
21    /// it is zero.
22    pub linear: f64,
23    /// Two directions within this angle (radians) are parallel; two
24    /// surfaces meeting at less than it are tangent.
25    pub angular: f64,
26}
27
28impl Tolerance {
29    /// A tolerance from its two parts.
30    pub const fn new(linear: f64, angular: f64) -> Self {
31        Tolerance { linear, angular }
32    }
33
34    /// `true` when both parts are finite and positive.
35    pub fn is_consistent(&self) -> bool {
36        self.linear.is_finite()
37            && self.linear > 0.0
38            && self.angular.is_finite()
39            && self.angular > 0.0
40    }
41}
42
43impl Precision {
44    /// The tolerance an algorithm without an entity of its own uses:
45    /// `default_tolerance` for lengths, `angular_tolerance` for angles.
46    pub const fn tolerance(&self) -> Tolerance {
47        Tolerance::new(self.default_tolerance, self.angular_tolerance)
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn default_precision_gives_a_consistent_tolerance() {
57        assert!(Precision::DEFAULT.tolerance().is_consistent());
58        assert!(!Tolerance::new(0.0, 1e-12).is_consistent());
59        assert!(!Tolerance::new(1e-7, f64::NAN).is_consistent());
60    }
61}