Skip to main content

navcore_math/
position.rs

1//! A geographic position.
2
3/// A position on the sphere, in degrees.
4///
5/// Latitude is positive north, longitude positive east, matching both the
6/// Signal K vocabulary the core adopts (`navigation.position`) and GeoJSON.
7/// Note the field order is lat-then-lon while GeoJSON coordinates are
8/// lon-then-lat; the constructor names the arguments so the swap has to be
9/// deliberate.
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct Position {
12    /// Degrees north of the equator, `-90.0..=90.0`.
13    pub lat_deg: f64,
14    /// Degrees east of Greenwich, normally `-180.0..=180.0`.
15    pub lon_deg: f64,
16}
17
18impl Position {
19    /// A position from latitude and longitude in degrees.
20    #[must_use]
21    pub const fn new(lat_deg: f64, lon_deg: f64) -> Self {
22        Self { lat_deg, lon_deg }
23    }
24
25    /// True when both components are finite and in range.
26    ///
27    /// Worth calling on anything that came off a wire: a GPS that has lost
28    /// its fix is a far more common source of an out-of-range latitude than
29    /// a bug is.
30    #[must_use]
31    pub fn is_valid(&self) -> bool {
32        self.lat_deg.is_finite()
33            && self.lon_deg.is_finite()
34            && self.lat_deg >= -90.0
35            && self.lat_deg <= 90.0
36            && self.lon_deg >= -180.0
37            && self.lon_deg <= 180.0
38    }
39
40    pub(crate) fn lat_rad(&self) -> f64 {
41        self.lat_deg.to_radians()
42    }
43
44    pub(crate) fn lon_rad(&self) -> f64 {
45        self.lon_deg.to_radians()
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn validity_catches_what_a_lost_fix_produces() {
55        assert!(Position::new(45.0, 13.0).is_valid());
56        assert!(Position::new(-90.0, 180.0).is_valid());
57        assert!(!Position::new(91.0, 0.0).is_valid());
58        assert!(!Position::new(0.0, 181.0).is_valid());
59        assert!(!Position::new(f64::NAN, 0.0).is_valid());
60    }
61}