Skip to main content

grib/grid/
earth.rs

1use crate::def::grib2::template::param_set::EarthShape;
2
3impl EarthShape {
4    pub fn radii(&self) -> Option<(f64, f64)> {
5        let radii = match self.shape {
6            0 => (6367470.0, 6367470.0),
7            1 => {
8                let radius = f64::from(self.spherical_earth_radius.scaled_value)
9                    * f64::powf(10., f64::from(self.spherical_earth_radius.scale_factor));
10                (radius, radius)
11            }
12            2 => (6378160.0, 6356775.0),
13            3 => {
14                let (major, minor) = self.radii_defined();
15                (major * 1000., minor * 1000.)
16            }
17            4 => (6378137.0, 6356752.314),
18            5 => (6378137.0, 6356752.3142), // WGS84
19            6 => (6371229.0, 6371229.0),
20            7 => self.radii_defined(),
21            8 => (6371200.0, 6371200.0),
22            9.. => return None,
23        };
24        Some(radii)
25    }
26
27    fn radii_defined(&self) -> (f64, f64) {
28        let major = f64::from(self.major_axis.scaled_value)
29            * f64::powf(10., f64::from(self.major_axis.scale_factor));
30        let minor = f64::from(self.minor_axis.scaled_value)
31            * f64::powf(10., f64::from(self.minor_axis.scale_factor));
32        (major, minor)
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::{
40        TryFromSlice, def::grib2::template::param_set::ScaledValue, test_utils::decompress_to_vec,
41    };
42
43    #[test]
44    fn radii_for_shape_1() -> Result<(), Box<dyn std::error::Error>> {
45        let buf = decompress_to_vec(crate::test_utils::data::grib2::NOAA_NDFD_CRITFIREO)?;
46        let mut pos = 0x83;
47        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
48        let earth_expected = EarthShape {
49            shape: 1,
50            spherical_earth_radius: ScaledValue {
51                scale_factor: 0,
52                scaled_value: 6371200,
53            },
54            major_axis: ScaledValue {
55                scale_factor: 0,
56                scaled_value: 0,
57            },
58            minor_axis: ScaledValue {
59                scale_factor: 0,
60                scaled_value: 0,
61            },
62        };
63        assert_eq!(earth_actual, earth_expected);
64        assert_eq!(earth_actual.radii(), Some((6_371_200., 6_371_200.)));
65
66        Ok(())
67    }
68
69    #[test]
70    fn radii_for_shape_2() -> Result<(), Box<dyn std::error::Error>> {
71        let buf = decompress_to_vec(crate::test_utils::data::grib2::NOAA_MRMS_REFLECTIVITY)?;
72        let mut pos = 0x33;
73        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
74        let earth_expected = EarthShape {
75            shape: 2,
76            spherical_earth_radius: ScaledValue {
77                scale_factor: 1,
78                scaled_value: 6367470,
79            },
80            major_axis: ScaledValue {
81                scale_factor: 1,
82                scaled_value: 6378160,
83            },
84            minor_axis: ScaledValue {
85                scale_factor: 1,
86                scaled_value: 6356775,
87            },
88        };
89        assert_eq!(earth_actual, earth_expected);
90        assert_eq!(earth_actual.radii(), Some((6_378_160.0, 6_356_775.0)));
91
92        Ok(())
93    }
94
95    #[test]
96    fn radii_for_shape_4() -> Result<(), Box<dyn std::error::Error>> {
97        let buf = decompress_to_vec(crate::test_utils::data::grib2::JMA_TORNADO_NOWCAST)?;
98        let mut pos = 0x33;
99        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
100        let earth_expected = EarthShape {
101            shape: 4,
102            spherical_earth_radius: ScaledValue {
103                scale_factor: 0xff,
104                scaled_value: 0xffffffff,
105            },
106            major_axis: ScaledValue {
107                scale_factor: 1,
108                scaled_value: 63781370,
109            },
110            minor_axis: ScaledValue {
111                scale_factor: 1,
112                scaled_value: 63567523,
113            },
114        };
115        assert_eq!(earth_actual, earth_expected);
116        assert_eq!(earth_actual.radii(), Some((6_378_137.0, 6_356_752.314)));
117
118        Ok(())
119    }
120
121    #[test]
122    fn radii_for_shape_6() -> Result<(), Box<dyn std::error::Error>> {
123        let buf = decompress_to_vec(crate::test_utils::data::grib2::NOAA_GDAS_0_10)?;
124        let mut pos = 0x33;
125        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
126        let earth_expected = EarthShape {
127            shape: 6,
128            spherical_earth_radius: ScaledValue {
129                scale_factor: 0,
130                scaled_value: 0,
131            },
132            major_axis: ScaledValue {
133                scale_factor: 0,
134                scaled_value: 0,
135            },
136            minor_axis: ScaledValue {
137                scale_factor: 0,
138                scaled_value: 0,
139            },
140        };
141        assert_eq!(earth_actual, earth_expected);
142        assert_eq!(earth_actual.radii(), Some((6_371_229.0, 6_371_229.0)));
143
144        Ok(())
145    }
146}