irox_units/shapes/
elliptical.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2023 IROX Contributors
3
4//!
5//! `Ellipse` struct, describes an ellipse using two `CircularDimension`
6//! axes and an optional `CompassDirection` orientation of the first axis
7//!
8
9use core::fmt::{Display, Formatter};
10
11use crate::shapes::CircularDimension;
12use crate::units::compass::CompassDirection;
13
14///
15/// A discrete measurement of an Ellipse.  An Ellipse is a circle with two
16/// [`CircularDimension`]s offset by 90° to each other.
17/// The `Ellipse::first_axis` orientation is indicated by `Ellipse::orientation`
18/// and the `Ellipse::second_axis` is oriented orthogonally to the first.
19#[derive(Debug, Copy, Clone, PartialEq, Default)]
20pub struct Ellipse {
21    first_axis: CircularDimension,
22    second_axis: CircularDimension,
23    orientation: Option<CompassDirection>,
24}
25
26impl Display for Ellipse {
27    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
28        match self.orientation {
29            Some(o) => {
30                write!(f, "{} / {} {}", self.first_axis, self.second_axis, o)
31            }
32            None => {
33                write!(f, "{} / {}", self.first_axis, self.second_axis)
34            }
35        }
36    }
37}
38
39impl Ellipse {
40    #[must_use]
41    pub fn new(first_axis: CircularDimension, second_axis: CircularDimension) -> Ellipse {
42        Ellipse {
43            first_axis,
44            second_axis,
45            orientation: None,
46        }
47    }
48
49    #[must_use]
50    pub fn semi_major_axis(&self) -> CircularDimension {
51        if self.first_axis > self.second_axis {
52            return self.first_axis.as_radius();
53        }
54        self.second_axis.as_radius()
55    }
56
57    #[must_use]
58    pub fn semi_minor_axis(&self) -> CircularDimension {
59        if self.first_axis > self.second_axis {
60            return self.second_axis.as_radius();
61        }
62        self.first_axis.as_radius()
63    }
64
65    #[must_use]
66    pub fn major_axis(&self) -> CircularDimension {
67        if self.first_axis > self.second_axis {
68            return self.first_axis.as_diameter();
69        }
70        self.second_axis.as_diameter()
71    }
72
73    #[must_use]
74    pub fn minor_axis(&self) -> CircularDimension {
75        if self.first_axis > self.second_axis {
76            return self.second_axis.as_diameter();
77        }
78        self.first_axis.as_diameter()
79    }
80
81    #[must_use]
82    pub fn orientation(&self) -> Option<CompassDirection> {
83        self.orientation
84    }
85
86    #[must_use]
87    pub fn with_orientation(self, orientation: CompassDirection) -> Ellipse {
88        Ellipse {
89            first_axis: self.first_axis,
90            second_axis: self.second_axis,
91            orientation: Some(orientation),
92        }
93    }
94}
95
96impl From<CircularDimension> for Ellipse {
97    fn from(value: CircularDimension) -> Self {
98        Ellipse {
99            first_axis: value,
100            second_axis: value,
101            orientation: None,
102        }
103    }
104}
105
106impl From<&CircularDimension> for Ellipse {
107    fn from(value: &CircularDimension) -> Self {
108        Ellipse {
109            first_axis: *value,
110            second_axis: *value,
111            orientation: None,
112        }
113    }
114}