Skip to main content

use_inversion/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use use_coordinate::GeometryError;
5use use_point::Point2;
6
7/// A planar geometric inversion represented by center and radius.
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Inversion {
10    center: Point2,
11    radius: f64,
12}
13
14impl Inversion {
15    /// Creates an inversion with a finite center and positive finite radius.
16    ///
17    /// # Errors
18    ///
19    /// Returns a [`GeometryError`] when the center is non-finite or the radius is invalid.
20    pub fn try_new(center: Point2, radius: f64) -> Result<Self, GeometryError> {
21        let center = center.validate()?;
22
23        if !radius.is_finite() {
24            return Err(GeometryError::NonFiniteRadius(radius));
25        }
26
27        if radius <= 0.0 {
28            return Err(GeometryError::NegativeRadius(radius));
29        }
30
31        Ok(Self { center, radius })
32    }
33
34    /// Returns the inversion center.
35    #[must_use]
36    pub const fn center(self) -> Point2 {
37        self.center
38    }
39
40    /// Returns the inversion radius.
41    #[must_use]
42    pub const fn radius(self) -> f64 {
43        self.radius
44    }
45
46    /// Returns the squared inversion radius.
47    #[must_use]
48    pub const fn radius_squared(self) -> f64 {
49        self.radius * self.radius
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::Inversion;
56    use use_coordinate::GeometryError;
57    use use_point::Point2;
58
59    #[test]
60    fn validates_inversion_radius() {
61        let inversion = Inversion::try_new(Point2::origin(), 2.0).expect("valid inversion");
62
63        assert_eq!(inversion.center(), Point2::origin());
64        assert_eq!(inversion.radius(), 2.0);
65        assert_eq!(inversion.radius_squared(), 4.0);
66        assert_eq!(
67            Inversion::try_new(Point2::origin(), 0.0),
68            Err(GeometryError::NegativeRadius(0.0))
69        );
70    }
71}