grib/def/grib2/template3.rs
1use grib_template_derive::{Dump, TryFromSlice, WriteToBuffer};
2
3/// Grid definition template 3.0 - latitude/longitude (or equidistant
4/// cylindrical, or Plate Carrée).
5#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
6pub struct Template3_0 {
7 pub earth: param_set::EarthShape,
8 pub lat_lon: param_set::LatLonGrid,
9}
10
11/// Grid definition template 3.1 - rotated latitude/longitude (or equidistant
12/// cylindrical, or Plate Carrée).
13///
14/// # Examples
15///
16/// ```
17/// use std::io::Read;
18///
19/// use grib::{
20/// TryFromSlice,
21/// def::grib2::template::{Template3_1, param_set},
22/// };
23///
24/// fn main() -> Result<(), Box<dyn std::error::Error>> {
25/// let mut buf = Vec::new();
26///
27/// let f = std::fs::File::open(
28/// "testdata/20260219T00Z_MSC_HRDPS_CAPE_Sfc_RLatLon0.0225_PT000H.grib2",
29/// )?;
30/// let mut f = std::io::BufReader::new(f);
31/// f.read_to_end(&mut buf)?;
32///
33/// let mut pos = 0x33;
34/// let actual = Template3_1::try_from_slice(&buf, &mut pos)?;
35/// let expected = Template3_1 {
36/// earth: param_set::EarthShape {
37/// shape: 6,
38/// spherical_earth_radius: param_set::ScaledValue {
39/// scale_factor: 0xff,
40/// scaled_value: 0xffffffff,
41/// },
42/// major_axis: param_set::ScaledValue {
43/// scale_factor: 0xff,
44/// scaled_value: 0xffffffff,
45/// },
46/// minor_axis: param_set::ScaledValue {
47/// scale_factor: 0xff,
48/// scaled_value: 0xffffffff,
49/// },
50/// },
51/// lat_lon: param_set::LatLonGrid {
52/// grid: param_set::Grid {
53/// ni: 2540,
54/// nj: 1290,
55/// initial_production_domain_basic_angle: 0,
56/// basic_angle_subdivisions: 0xffffffff,
57/// first_point_lat: -12302501,
58/// first_point_lon: 345178780,
59/// resolution_and_component_flags: param_set::ResolutionAndComponentFlags(
60/// 0b00111000,
61/// ),
62/// last_point_lat: 16700001,
63/// last_point_lon: 42306283,
64/// },
65/// scanning_mode: param_set::ScanningMode(0b01000000),
66/// i_direction_inc: 22500,
67/// j_direction_inc: 22500,
68/// },
69/// rotation: param_set::Rotation {
70/// south_pole_lat: -36088520,
71/// south_pole_lon: 245305142,
72/// rot_angle: 0.,
73/// },
74/// };
75/// assert_eq!(actual, expected);
76///
77/// Ok(())
78/// }
79/// ```
80#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
81pub struct Template3_1 {
82 pub earth: param_set::EarthShape,
83 pub lat_lon: param_set::LatLonGrid,
84 pub rotation: param_set::Rotation,
85}
86
87/// Grid definition template 3.2 - stretched latitude/longitude (or equidistant
88/// cylindrical, or Plate Carrée).
89#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
90pub struct Template3_2 {
91 pub earth: param_set::EarthShape,
92 pub lat_lon: param_set::LatLonGrid,
93 pub stretching: param_set::Stretching,
94}
95
96/// Grid definition template 3.3 - stretched and rotated latitude/longitude (or
97/// equidistant cylindrical, or Plate Carrée).
98#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
99pub struct Template3_3 {
100 pub earth: param_set::EarthShape,
101 pub lat_lon: param_set::LatLonGrid,
102 pub rotation: param_set::Rotation,
103 pub stretching: param_set::Stretching,
104}
105
106/// Grid definition template 3.10 - Mercator.
107///
108/// # Examples
109///
110/// ```
111/// use std::io::{BufReader, Read};
112///
113/// use grib::{
114/// TryFromSlice,
115/// def::grib2::template::{Template3_10, param_set},
116/// };
117///
118/// fn main() -> Result<(), Box<dyn std::error::Error>> {
119/// let mut buf = Vec::new();
120///
121/// let f = std::fs::File::open("testdata/ds.wwa.bin.xz")?;
122/// let f = BufReader::new(f);
123/// let mut f = xz2::bufread::XzDecoder::new(f);
124/// f.read_to_end(&mut buf)?;
125///
126/// let mut pos = 0xa6;
127/// let actual = Template3_10::try_from_slice(&buf, &mut pos)?;
128/// let expected = Template3_10 {
129/// earth_shape: param_set::EarthShape {
130/// shape: 1,
131/// spherical_earth_radius: param_set::ScaledValue {
132/// scale_factor: 0,
133/// scaled_value: 6371200,
134/// },
135/// major_axis: param_set::ScaledValue {
136/// scale_factor: 0,
137/// scaled_value: 0,
138/// },
139/// minor_axis: param_set::ScaledValue {
140/// scale_factor: 0,
141/// scaled_value: 0,
142/// },
143/// },
144/// ni: 2517,
145/// nj: 1793,
146/// first_point_lat: -30419200,
147/// first_point_lon: 129906005,
148/// resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00000000),
149/// lad: 20000000,
150/// last_point_lat: 80010000,
151/// last_point_lon: 10710000,
152/// scanning_mode: param_set::ScanningMode(0b01010000),
153/// orientation: 0,
154/// di: 10000000,
155/// dj: 10000000,
156/// };
157/// assert_eq!(actual, expected);
158///
159/// Ok(())
160/// }
161/// ```
162#[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
163pub struct Template3_10 {
164 pub earth_shape: param_set::EarthShape,
165 /// Ni - number of points along a parallel.
166 pub ni: u32,
167 /// Nj - number of points along a meridian.
168 pub nj: u32,
169 /// La1 - latitude of first grid point.
170 pub first_point_lat: i32,
171 /// Lo1 - longitude of first grid point.
172 pub first_point_lon: u32,
173 pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
174 /// LaD - Latitude(s) at which the Mercator projection intersects the Earth
175 /// (Latitude(s) where Di and Dj are specified).
176 pub lad: i32,
177 /// La2 - latitude of last grid point.
178 pub last_point_lat: i32,
179 /// Lo2 - longitude of last grid point.
180 pub last_point_lon: u32,
181 pub scanning_mode: param_set::ScanningMode,
182 /// Orientation of the grid, angle between i direction on the map and the
183 /// equator (see Note 1).
184 pub orientation: u32,
185 /// Di - longitudinal direction grid length (see Note 2).
186 pub di: u32,
187 /// Dj - latitudinal direction grid length (see Note 2).
188 pub dj: u32,
189}
190
191/// Grid definition template 3.20 - polar stereographic projection.
192///
193/// # Examples
194///
195/// ```
196/// use std::io::{BufReader, Read};
197///
198/// use grib::{
199/// TryFromSlice,
200/// def::grib2::template::{Template3_20, param_set},
201/// };
202///
203/// fn main() -> Result<(), Box<dyn std::error::Error>> {
204/// let mut buf = Vec::new();
205///
206/// let f = std::fs::File::open(
207/// "testdata/CMC_RDPA_APCP-024-0100cutoff_SFC_0_ps10km_2023121806_000.grib2.xz",
208/// )?;
209/// let f = BufReader::new(f);
210/// let mut f = xz2::bufread::XzDecoder::new(f);
211/// f.read_to_end(&mut buf)?;
212///
213/// let mut pos = 0x33;
214/// let actual = Template3_20::try_from_slice(&buf, &mut pos)?;
215/// let expected = Template3_20 {
216/// earth_shape: param_set::EarthShape {
217/// shape: 6,
218/// spherical_earth_radius: param_set::ScaledValue {
219/// scale_factor: 0xff,
220/// scaled_value: 0xffffffff,
221/// },
222/// major_axis: param_set::ScaledValue {
223/// scale_factor: 0xff,
224/// scaled_value: 0xffffffff,
225/// },
226/// minor_axis: param_set::ScaledValue {
227/// scale_factor: 0xff,
228/// scaled_value: 0xffffffff,
229/// },
230/// },
231/// ni: 935,
232/// nj: 824,
233/// first_point_lat: 18145030,
234/// first_point_lon: 217107456,
235/// resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00001000),
236/// lad: 60000000,
237/// lov: 249000000,
238/// dx: 10000000,
239/// dy: 10000000,
240/// projection_centre: param_set::ProjectionCentreFlag(0b00000000),
241/// scanning_mode: param_set::ScanningMode(0b01000000),
242/// };
243/// assert_eq!(actual, expected);
244///
245/// Ok(())
246/// }
247/// ```
248#[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
249pub struct Template3_20 {
250 pub earth_shape: param_set::EarthShape,
251 /// Nx - number of points along the x-axis.
252 pub ni: u32,
253 /// Ny - number of points along the y-axis.
254 pub nj: u32,
255 /// La1 - latitude of first grid point.
256 pub first_point_lat: i32,
257 /// Lo1 - longitude of first grid point.
258 pub first_point_lon: u32,
259 pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
260 /// LaD - latitude where Dx and Dy are specified.
261 pub lad: i32,
262 /// LoV - orientation of the grid (see Note 2).
263 pub lov: i32,
264 /// Dx - x-direction grid length (see Note 3).
265 pub dx: u32,
266 /// Dy - y-direction grid length (see Note 3).
267 pub dy: u32,
268 pub projection_centre: param_set::ProjectionCentreFlag,
269 pub scanning_mode: param_set::ScanningMode,
270}
271
272/// Grid definition template 3.30 - Lambert conformal.
273///
274/// # Examples
275///
276/// ```
277/// use std::io::{BufReader, Read};
278///
279/// use grib::{
280/// TryFromSlice,
281/// def::grib2::template::{Template3_30, param_set},
282/// };
283///
284/// fn main() -> Result<(), Box<dyn std::error::Error>> {
285/// let mut buf = Vec::new();
286///
287/// let f = std::fs::File::open("testdata/ds.critfireo.bin.xz")?;
288/// let f = BufReader::new(f);
289/// let mut f = xz2::bufread::XzDecoder::new(f);
290/// f.read_to_end(&mut buf)?;
291///
292/// let mut pos = 0x83;
293/// let actual = Template3_30::try_from_slice(&buf, &mut pos)?;
294/// let expected = Template3_30 {
295/// earth_shape: param_set::EarthShape {
296/// shape: 1,
297/// spherical_earth_radius: param_set::ScaledValue {
298/// scale_factor: 0,
299/// scaled_value: 6371200,
300/// },
301/// major_axis: param_set::ScaledValue {
302/// scale_factor: 0,
303/// scaled_value: 0,
304/// },
305/// minor_axis: param_set::ScaledValue {
306/// scale_factor: 0,
307/// scaled_value: 0,
308/// },
309/// },
310/// ni: 2145,
311/// nj: 1377,
312/// first_point_lat: 20190000,
313/// first_point_lon: 238449996,
314/// resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00000000),
315/// lad: 25000000,
316/// lov: 265000000,
317/// dx: 2539703,
318/// dy: 2539703,
319/// projection_centre: param_set::ProjectionCentreFlag(0b00000000),
320/// scanning_mode: param_set::ScanningMode(0b01010000),
321/// latin1: 25000000,
322/// latin2: 25000000,
323/// south_pole_lat: -90000000,
324/// south_pole_lon: 0,
325/// };
326/// assert_eq!(actual, expected);
327///
328/// Ok(())
329/// }
330/// ```
331#[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
332pub struct Template3_30 {
333 pub earth_shape: param_set::EarthShape,
334 /// Nx - number of points along the x-axis.
335 pub ni: u32,
336 /// Ny - number of points along the y-axis.
337 pub nj: u32,
338 /// La1 - latitude of first grid point.
339 pub first_point_lat: i32,
340 /// Lo1 - longitude of first grid point.
341 pub first_point_lon: u32,
342 pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
343 /// LaD - latitude where Dx and Dy are specified.
344 pub lad: i32,
345 /// LoV - longitude of meridian parallel to y-axis along which latitude
346 /// increases as the y-coordinate increases.
347 pub lov: u32,
348 /// Dx - x-direction grid length (see Note 1).
349 pub dx: u32,
350 /// Dy - y-direction grid length (see Note 1).
351 pub dy: u32,
352 pub projection_centre: param_set::ProjectionCentreFlag,
353 pub scanning_mode: param_set::ScanningMode,
354 /// Latin 1 - first latitude from the pole at which the secant cone cuts the
355 /// sphere.
356 pub latin1: i32,
357 /// Latin 2 - second latitude from the pole at which the secant cone cuts
358 /// the sphere.
359 pub latin2: i32,
360 /// Latitude of the southern pole of projection.
361 pub south_pole_lat: i32,
362 /// Longitude of the southern pole of projection.
363 pub south_pole_lon: u32,
364}
365
366/// Grid definition template 3.40 - Gaussian latitude/longitude.
367#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
368pub struct Template3_40 {
369 pub earth: param_set::EarthShape,
370 pub gaussian: param_set::GaussianGrid,
371}
372
373/// Grid definition template 3.41 - rotated Gaussian latitude/longitude.
374#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
375pub struct Template3_41 {
376 pub earth: param_set::EarthShape,
377 pub gaussian: param_set::GaussianGrid,
378 pub rotation: param_set::Rotation,
379}
380
381/// Grid definition template 3.42 - stretched Gaussian latitude/longitude.
382#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
383pub struct Template3_42 {
384 pub earth: param_set::EarthShape,
385 pub gaussian: param_set::GaussianGrid,
386 pub stretching: param_set::Stretching,
387}
388
389/// Grid definition template 3.43 - stretched and rotated Gaussian
390/// latitude/longitude.
391#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
392pub struct Template3_43 {
393 pub earth: param_set::EarthShape,
394 pub gaussian: param_set::GaussianGrid,
395 pub rotation: param_set::Rotation,
396 pub stretching: param_set::Stretching,
397}
398
399/// Grid definition template 3.101 - general unstructured grid.
400#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
401pub struct Template3_101 {
402 /// Shape of the Earth (see Code table 3.2).
403 pub earth_shape: u8,
404 /// Number of grid used (defined by originating centre).
405 #[grib_template(num_octets = 3)]
406 pub grid_num: u32,
407 /// Number of grid in reference (to allow annotating for Arakawa C-grid on
408 /// arbitrary grid) (see Note).
409 pub ref_grid_num: u8,
410 /// Universally Unique Identifier of horizontal grid.
411 pub uuid: [u8; 16],
412}
413
414pub(crate) mod param_set {
415 use grib_template_derive::{Dump, TryFromSlice, WriteToBuffer};
416
417 use super::super::template::param_set::ScaledValue;
418
419 #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
420 pub struct EarthShape {
421 /// Shape of the Earth (see Code table 3.2).
422 pub shape: u8,
423 /// Radius of spherical Earth.
424 #[dump(doc(
425 scale_factor = "Scale factor of radius of spherical Earth.",
426 scaled_value = "Scaled value of radius of spherical Earth.",
427 ))]
428 pub spherical_earth_radius: ScaledValue<u8, u32>,
429 /// Major axis of oblate spheroid Earth.
430 #[dump(doc(
431 scale_factor = "Scale factor of major axis of oblate spheroid Earth.",
432 scaled_value = "Scaled value of major axis of oblate spheroid Earth.",
433 ))]
434 pub major_axis: ScaledValue<u8, u32>,
435 /// Minor axis of oblate spheroid Earth.
436 #[dump(doc(
437 scale_factor = "Scale factor of minor axis of oblate spheroid Earth.",
438 scaled_value = "Scaled value of minor axis of oblate spheroid Earth.",
439 ))]
440 pub minor_axis: ScaledValue<u8, u32>,
441 }
442
443 #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
444 pub struct LatLonGrid {
445 pub grid: Grid,
446 /// Di - i direction increment (see Notes 1 and 5).
447 pub i_direction_inc: u32,
448 /// Dj - j direction increment (see Notes 1 and 5).
449 pub j_direction_inc: u32,
450 pub scanning_mode: ScanningMode,
451 }
452
453 #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
454 pub struct GaussianGrid {
455 pub grid: Grid,
456 /// Di - i direction increment (see Notes 1 and 5).
457 pub i_direction_inc: u32,
458 /// N - number of parallels between a pole and the Equator (see Note 2).
459 pub n: u32,
460 pub scanning_mode: ScanningMode,
461 }
462
463 #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
464 pub struct Grid {
465 /// Ni - number of points along a parallel.
466 pub ni: u32,
467 /// Nj - number of points along a meridian.
468 pub nj: u32,
469 /// Basic angle of the initial production domain (see Note 1).
470 pub initial_production_domain_basic_angle: u32,
471 /// Subdivisions of basic angle used to define extreme longitudes and
472 /// latitudes, and direction increments (see Note 1).
473 pub basic_angle_subdivisions: u32,
474 /// La1 - latitude of first grid point (see Note 1).
475 pub first_point_lat: i32,
476 /// Lo1 - longitude of first grid point (see Note 1).
477 pub first_point_lon: u32,
478 pub resolution_and_component_flags: ResolutionAndComponentFlags,
479 /// La2 - latitude of last grid point (see Note 1).
480 pub last_point_lat: i32,
481 /// Lo2 - longitude of last grid point (see Note 1).
482 pub last_point_lon: u32,
483 }
484
485 #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
486 pub struct ProjectionCentreFlag(
487 /// Projection centre flag (see Flag table 3.5).
488 pub u8,
489 );
490
491 #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
492 pub struct ResolutionAndComponentFlags(
493 /// Resolution and component flags (see Flag table 3.3).
494 pub u8,
495 );
496
497 #[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
498 pub struct Rotation {
499 /// Latitude of the southern pole of projection.
500 pub south_pole_lat: i32,
501 /// Longitude of the southern pole of projection.
502 pub south_pole_lon: u32,
503 /// Angle of rotation of projection.
504 pub rot_angle: f32,
505 }
506
507 #[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
508 pub struct Stretching {
509 /// Latitude of the pole of stretching.
510 pub pole_lat: i32,
511 /// Longitude of the pole of stretching.
512 pub pole_lon: u32,
513 /// Stretching factor.
514 pub factor: u32,
515 }
516
517 #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
518 pub struct ScanningMode(
519 /// Scanning mode (flags - see Flag table 3.4).
520 pub u8,
521 );
522}