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::{TryFromSlice, test_utils::decompress_to_vec};
40
41    #[test]
42    fn radii_for_shape_1() -> Result<(), Box<dyn std::error::Error>> {
43        let buf = decompress_to_vec(crate::test_utils::data::grib2::NOAA_NDFD_CRITFIREO)?;
44        let mut pos = 0x83;
45        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
46        let earth_expected = EarthShape {
47            shape: 1,
48            spherical_earth_radius_scale_factor: 0,
49            spherical_earth_radius_scaled_value: 6371200,
50            major_axis_scale_factor: 0,
51            major_axis_scaled_value: 0,
52            minor_axis_scale_factor: 0,
53            minor_axis_scaled_value: 0,
54        };
55        assert_eq!(earth_actual, earth_expected);
56        assert_eq!(earth_actual.radii(), Some((6_371_200., 6_371_200.)));
57
58        Ok(())
59    }
60
61    #[test]
62    fn radii_for_shape_2() -> Result<(), Box<dyn std::error::Error>> {
63        let buf = decompress_to_vec(crate::test_utils::data::grib2::NOAA_MRMS_REFLECTIVITY)?;
64        let mut pos = 0x33;
65        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
66        let earth_expected = EarthShape {
67            shape: 2,
68            spherical_earth_radius_scale_factor: 1,
69            spherical_earth_radius_scaled_value: 6367470,
70            major_axis_scale_factor: 1,
71            major_axis_scaled_value: 6378160,
72            minor_axis_scale_factor: 1,
73            minor_axis_scaled_value: 6356775,
74        };
75        assert_eq!(earth_actual, earth_expected);
76        assert_eq!(earth_actual.radii(), Some((6_378_160.0, 6_356_775.0)));
77
78        Ok(())
79    }
80
81    #[test]
82    fn radii_for_shape_4() -> Result<(), Box<dyn std::error::Error>> {
83        let buf = decompress_to_vec(crate::test_utils::data::grib2::JMA_TORNADO_NOWCAST)?;
84        let mut pos = 0x33;
85        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
86        let earth_expected = EarthShape {
87            shape: 4,
88            spherical_earth_radius_scale_factor: 0xff,
89            spherical_earth_radius_scaled_value: 0xffffffff,
90            major_axis_scale_factor: 1,
91            major_axis_scaled_value: 63781370,
92            minor_axis_scale_factor: 1,
93            minor_axis_scaled_value: 63567523,
94        };
95        assert_eq!(earth_actual, earth_expected);
96        assert_eq!(earth_actual.radii(), Some((6_378_137.0, 6_356_752.314)));
97
98        Ok(())
99    }
100
101    #[test]
102    fn radii_for_shape_6() -> Result<(), Box<dyn std::error::Error>> {
103        let buf = decompress_to_vec(crate::test_utils::data::grib2::NOAA_GDAS_0_10)?;
104        let mut pos = 0x33;
105        let earth_actual = EarthShape::try_from_slice(&buf, &mut pos)?;
106        let earth_expected = EarthShape {
107            shape: 6,
108            spherical_earth_radius_scale_factor: 0,
109            spherical_earth_radius_scaled_value: 0,
110            major_axis_scale_factor: 0,
111            major_axis_scaled_value: 0,
112            minor_axis_scale_factor: 0,
113            minor_axis_scaled_value: 0,
114        };
115        assert_eq!(earth_actual, earth_expected);
116        assert_eq!(earth_actual.radii(), Some((6_371_229.0, 6_371_229.0)));
117
118        Ok(())
119    }
120}