grib/
grid.rs

1use helpers::RegularGridIterator;
2
3pub use self::{
4    earth::EarthShapeDefinition,
5    gaussian::{compute_gaussian_latitudes, GaussianGridDefinition},
6    lambert::LambertGridDefinition,
7    latlon::LatLonGridDefinition,
8    polar_stereographic::PolarStereographicGridDefinition,
9};
10
11/// An iterator over latitudes and longitudes of grid points in a submessage.
12///
13/// This `enum` is created by the [`latlons`] method on [`SubMessage`]. See its
14/// documentation for more.
15///
16/// [`latlons`]: crate::context::SubMessage::latlons
17/// [`SubMessage`]: crate::context::SubMessage
18#[derive(Clone)]
19pub enum GridPointIterator {
20    LatLon(RegularGridIterator),
21    Lambert(std::vec::IntoIter<(f32, f32)>),
22}
23
24impl Iterator for GridPointIterator {
25    type Item = (f32, f32);
26
27    fn next(&mut self) -> Option<Self::Item> {
28        match self {
29            Self::LatLon(iter) => iter.next(),
30            Self::Lambert(iter) => iter.next(),
31        }
32    }
33
34    fn size_hint(&self) -> (usize, Option<usize>) {
35        match self {
36            Self::LatLon(iter) => iter.size_hint(),
37            Self::Lambert(iter) => iter.size_hint(),
38        }
39    }
40}
41
42/// An iterator over `(i, j)` of grid points.
43///
44/// This `struct` is created by the [`ij`] method. See its documentation for
45/// more.
46///
47/// [`ij`]: LatLonGridDefinition::ij
48#[derive(Clone)]
49pub struct GridPointIndexIterator {
50    major_len: usize,
51    minor_len: usize,
52    scanning_mode: ScanningMode,
53    major_pos: usize,
54    minor_pos: usize,
55    increments: bool,
56}
57
58impl GridPointIndexIterator {
59    pub(crate) fn new(i_len: usize, j_len: usize, scanning_mode: ScanningMode) -> Self {
60        let (major_len, minor_len) = if scanning_mode.is_consecutive_for_i() {
61            (j_len, i_len)
62        } else {
63            (i_len, j_len)
64        };
65
66        Self {
67            major_len,
68            minor_len,
69            scanning_mode,
70            minor_pos: 0,
71            major_pos: 0,
72            increments: true,
73        }
74    }
75}
76
77impl Iterator for GridPointIndexIterator {
78    type Item = (usize, usize);
79
80    fn next(&mut self) -> Option<Self::Item> {
81        if self.major_pos == self.major_len {
82            return None;
83        }
84
85        let minor = if self.increments {
86            self.minor_pos
87        } else {
88            self.minor_len - self.minor_pos - 1
89        };
90        let major = self.major_pos;
91
92        self.minor_pos += 1;
93        if self.minor_pos == self.minor_len {
94            self.major_pos += 1;
95            self.minor_pos = 0;
96            if self.scanning_mode.scans_alternating_rows() {
97                self.increments = !self.increments;
98            }
99        }
100
101        if self.scanning_mode.is_consecutive_for_i() {
102            Some((minor, major))
103        } else {
104            Some((major, minor))
105        }
106    }
107
108    fn size_hint(&self) -> (usize, Option<usize>) {
109        let len = (self.major_len - self.major_pos) * self.minor_len - self.minor_pos;
110        (len, Some(len))
111    }
112}
113
114#[derive(Debug, PartialEq, Eq, Clone, Copy)]
115pub struct ScanningMode(pub u8);
116
117impl ScanningMode {
118    /// Returns `true` if points of the first row or column scan in the `+i`
119    /// (`+x`) direction.
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// assert_eq!(
125    ///     grib::ScanningMode(0b00000000).scans_positively_for_i(),
126    ///     true
127    /// );
128    /// ```
129    pub fn scans_positively_for_i(&self) -> bool {
130        self.0 & 0b10000000 == 0
131    }
132
133    /// Returns `true` if points of the first row or column scan in the `+j`
134    /// (`+y`) direction.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// assert_eq!(
140    ///     grib::ScanningMode(0b00000000).scans_positively_for_j(),
141    ///     false
142    /// );
143    /// ```
144    pub fn scans_positively_for_j(&self) -> bool {
145        self.0 & 0b01000000 != 0
146    }
147
148    /// Returns `true` if adjacent points in `i` (`x`) direction are
149    /// consecutive.
150    ///
151    /// # Examples
152    ///
153    /// ```
154    /// assert_eq!(grib::ScanningMode(0b00000000).is_consecutive_for_i(), true);
155    /// ```
156    pub fn is_consecutive_for_i(&self) -> bool {
157        self.0 & 0b00100000 == 0
158    }
159
160    /// Returns `true` if adjacent rows scans in the opposite direction.
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// assert_eq!(
166    ///     grib::ScanningMode(0b00000000).scans_alternating_rows(),
167    ///     false
168    /// );
169    /// ```
170    pub fn scans_alternating_rows(&self) -> bool {
171        self.0 & 0b00010000 != 0
172    }
173
174    pub(crate) fn has_unsupported_flags(&self) -> bool {
175        self.0 & 0b00001111 != 0
176    }
177}
178
179#[derive(Debug, PartialEq, Eq, Clone, Copy)]
180pub struct ProjectionCentreFlag(pub u8);
181
182impl ProjectionCentreFlag {
183    /// Returns `true` if North Pole is on the projection plane. Otherwise (i.e.
184    /// if South Pole is on), returns `false`.
185    ///
186    /// # Examples
187    ///
188    /// ```
189    /// assert_eq!(
190    ///     grib::ProjectionCentreFlag(0b00000000).contains_north_pole_on_projection_plane(),
191    ///     true
192    /// );
193    /// ```
194    pub fn contains_north_pole_on_projection_plane(&self) -> bool {
195        self.0 & 0b10000000 == 0
196    }
197
198    /// Returns `true` if projection is bipolar and symmetric. Otherwise (i.e.
199    /// if only one projection centre is used), returns `false`.
200    ///
201    /// # Examples
202    ///
203    /// ```
204    /// assert_eq!(grib::ProjectionCentreFlag(0b00000000).is_bipolar(), false);
205    /// ```
206    pub fn is_bipolar(&self) -> bool {
207        self.0 & 0b01000000 != 0
208    }
209
210    #[allow(dead_code)]
211    pub(crate) fn has_unsupported_flags(&self) -> bool {
212        self.0 & 0b00111111 != 0
213    }
214}
215
216mod earth;
217mod gaussian;
218mod helpers;
219mod lambert;
220mod latlon;
221mod polar_stereographic;