1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use crate::{
ionex::{IonexKey, TEC},
prelude::{Epoch, Rinex},
};
impl Rinex {
/// Returns Iterator over TEC expressed in TECu (10^-16 m-2) per lattitude,
/// longitude in decimal degrees, and altitude in km.
pub fn ionex_tecu_latlong_ddeg_alt_km_iter(
&self,
) -> Box<dyn Iterator<Item = (Epoch, f64, f64, f64, f64)> + '_> {
Box::new(self.ionex_tec_maps_iter().map(|(k, v)| {
(
k.epoch,
k.coordinates.latitude_ddeg(),
k.coordinates.longitude_ddeg(),
k.coordinates.altitude_km(),
v.tecu(),
)
}))
}
/// Returns IONEX TEC map borders.
/// NB: this is only based on Header definitions. If provided
/// content did not follow those specs (incorrect), the returned value here will not
/// reflect actual content.
/// ## Output
/// - (lat_min, lat_max): southernmost and northernmost latitude, in decimal degrees
/// - (long_min, long_max): easternmost and westernmost longitude, in decimal degrees
pub fn tec_map_borders(&self) -> Option<((f64, f64), (f64, f64))> {
let ionex = self.header.ionex.as_ref()?;
Some((
(ionex.grid.latitude.start, ionex.grid.latitude.end),
(ionex.grid.longitude.start, ionex.grid.longitude.end),
))
}
/// Designs an iterator over RMS TEC exclusively
pub fn ionex_rms_tec_maps_iter(&self) -> Box<dyn Iterator<Item = (IonexKey, f64)> + '_> {
Box::new(self.ionex_tec_maps_iter().filter_map(|(k, tec)| {
if let Some(rms) = tec.rms_tec() {
Some((k, rms))
} else {
None
}
}))
}
/// Returns fixed altitude (in kilometers) if this is a 2D IONEX (only).
/// Note that this is only based on Header definitions. If provided
/// content does not follow those specs (incorrect data), the returned value here will not
/// reflect actual content.
pub fn ionex_2d_fixed_altitude_km(&self) -> Option<f64> {
if self.is_ionex_2d() {
let header = self.header.ionex.as_ref()?;
Some(header.grid.height.start)
} else {
None
}
}
/// Returns altitude range of the IONEX TEC maps, expressed as {min, max}
/// both in kilometers.
/// - if this is a 2D IONEX: you will obtain (min, min)
/// - if this is a 3D IONEX: you will obtain (min, max)
/// Note that this is only based on Header definitions. If provided
/// content does not follow those specs (incorrect data), the returned value here will not
/// reflect actual content.
pub fn ionex_altitude_range_km(&self) -> Option<(f64, f64)> {
let header = self.header.ionex.as_ref()?;
Some((header.grid.height.start, header.grid.height.end))
}
/// Designs an TEC isosurface iterator starting at lowest altitude,
/// ending at highest altitude. See [Self::ionex_tec_maps_altitude_range] for
/// useful information.
pub fn ionex_tec_isosurface_iter(&self) -> Box<dyn Iterator<Item = (IonexKey, TEC)> + '_> {
Box::new([].into_iter())
}
/// Designs an RMS TEC isosurface iterator starting at lowest altitude,
/// ending at highest altitude. See [Self::ionex_tec_maps_altitude_range] for
/// useful information.
pub fn ionex_rms_tec_isosurface_iter(&self) -> Box<dyn Iterator<Item = (IonexKey, TEC)> + '_> {
Box::new([].into_iter())
}
}