sounding_analysis/sounding/station_info.rs
1use metfor::Meters;
2use optional::Optioned;
3
4/// Station information including location data and identification number.
5#[derive(Debug, Clone, PartialEq, Default)]
6pub struct StationInfo {
7 /// station number, USAF number, eg 727730
8 num: Optioned<i32>,
9 /// station id, usually a 3 or 4 letter value
10 id: Option<String>,
11 /// Latitude and longitude.
12 location: Option<(f64, f64)>,
13 /// Elevation, this may be in model terrain which is not necessarily the same as the real world.
14 elevation: Optioned<Meters>,
15}
16
17impl StationInfo {
18 /// Create a new `StationInfo` object.
19 ///
20 /// # Arguments
21 /// station_num: The USAF station identifier, or None.
22 ///
23 /// location: The latitude and longitude as a tuple, or None.
24 ///
25 /// elevation: The elevation of the station **in meters**.
26 ///
27 /// # Examples
28 ///
29 /// ```rust
30 /// use metfor::{Meters, Feet};
31 /// use sounding_analysis::StationInfo;
32 /// use optional::{some, none};
33 ///
34 /// let _stn = StationInfo::new_with_values(12345, None, (45.2,-113.5), Meters(2000.0));
35 /// let _stn = StationInfo::new_with_values(12345, None, (45.2,-113.5), Feet(2000.0));
36 /// let _stn = StationInfo::new_with_values(12345, None, (45.2,-113.5), some(Meters(2000.0)));
37 /// let _stn = StationInfo::new_with_values(12345, None, (45.2,-113.5), some(Feet(2000.0)));
38 /// let _stn = StationInfo::new_with_values(12345, None, Some((45.2,-113.5)), Meters(2000.0));
39 /// let _stn = StationInfo::new_with_values(12345, None, Some((45.2,-113.5)), Feet(2000.0));
40 /// let _stn = StationInfo::new_with_values(12345, None, Some((45.2,-113.5)), some(Meters(2000.0)));
41 /// let _stn = StationInfo::new_with_values(12345, None, Some((45.2,-113.5)), some(Feet(2000.0)));
42 /// let _stn = StationInfo::new_with_values(Some(12345), None, None, Meters(2000.0));
43 /// let _stn = StationInfo::new_with_values(Some(12345), None, None, Feet(2000.0));
44 /// let _stn = StationInfo::new_with_values(None, None, (45.2,-113.5), some(Meters(2000.0)));
45 /// let _stn = StationInfo::new_with_values(None, None, (45.2,-113.5), some(Feet(2000.0)));
46 ///
47 /// // Note that lat-lon is an `Option` and not an `Optioned`
48 /// let _stn = StationInfo::new_with_values(some(12345), None, None, none::<Feet>());
49 /// let _stn = StationInfo::new_with_values(some(12345), None, None, none::<Meters>());
50 /// ```
51 #[inline]
52 pub fn new_with_values<S, T, U, V, W>(
53 station_num: T,
54 station_id: S,
55 location: U,
56 elevation: V,
57 ) -> Self
58 where
59 S: Into<Option<String>>,
60 T: Into<Optioned<i32>>,
61 U: Into<Option<(f64, f64)>>,
62 Optioned<W>: From<V>,
63 W: optional::Noned + metfor::Length,
64 Meters: From<W>,
65 {
66 let elev: Optioned<W> = Optioned::from(elevation);
67 let elev: Optioned<Meters> = elev.map_t(Meters::from);
68
69 StationInfo {
70 num: station_num.into(),
71 id: station_id.into(),
72 location: location.into(),
73 elevation: elev,
74 }
75 }
76
77 /// Create a new object with default values.
78 ///
79 /// # Examples
80 ///
81 /// ```rust
82 /// use sounding_analysis::StationInfo;
83 ///
84 /// assert!(StationInfo::new().station_num().is_none());
85 /// assert!(StationInfo::new().location().is_none());
86 /// assert!(StationInfo::new().elevation().is_none());
87 ///
88 /// ```
89 #[inline]
90 pub fn new() -> Self {
91 Self::default()
92 }
93
94 /// Builder method to add a station number.
95 ///
96 /// # Examples
97 ///
98 /// ```rust
99 /// use sounding_analysis::StationInfo;
100 ///
101 /// assert_eq!(StationInfo::new().with_station(12345).station_num().unwrap(), 12345);
102 /// assert_eq!(StationInfo::new().with_station(Some(12345)).station_num().unwrap(), 12345);
103 ///
104 /// ```
105 #[inline]
106 pub fn with_station<T>(mut self, number: T) -> Self
107 where
108 Optioned<i32>: From<T>,
109 {
110 self.num = Optioned::from(number);
111
112 self
113 }
114
115 /// Builder method to add a location.
116 ///
117 /// # Examples
118 ///
119 /// ```rust
120 /// use sounding_analysis::StationInfo;
121 ///
122 /// assert_eq!(
123 /// StationInfo::new().with_lat_lon((45.0, -116.0)).location().unwrap(), (45.0, -116.0));
124 /// assert_eq!(
125 /// StationInfo::new().with_lat_lon(Some((45.0, -116.0)))
126 /// .location()
127 /// .unwrap(),
128 /// (45.0, -116.0));
129 ///
130 /// ```
131 #[inline]
132 pub fn with_lat_lon<T>(mut self, coords: T) -> Self
133 where
134 Option<(f64, f64)>: From<T>,
135 {
136 self.location = Option::from(coords);
137 self
138 }
139
140 /// Builder method to add elevation.
141 ///
142 /// # Examples
143 ///```rust
144 /// use metfor::{Meters, Feet, Km};
145 /// use sounding_analysis::StationInfo;
146 /// use optional::{some, none};
147 ///
148 /// let _info = StationInfo::new().with_elevation(Feet(200.0));
149 /// let _info = StationInfo::new().with_elevation(Meters(200.0));
150 /// let _info = StationInfo::new().with_elevation(Km(2.0));
151 /// let _info = StationInfo::new().with_elevation(some(Feet(200.0)));
152 /// let _info = StationInfo::new().with_elevation(some(Meters(200.0)));
153 /// let _info = StationInfo::new().with_elevation(some(Km(2.0)));
154 /// let _info = StationInfo::new().with_elevation(none::<Feet>());
155 /// let _info = StationInfo::new().with_elevation(none::<Meters>());
156 /// let _info = StationInfo::new().with_elevation(none::<Km>());
157 ///```
158 #[inline]
159 pub fn with_elevation<T, U>(mut self, elev: T) -> Self
160 where
161 Optioned<U>: From<T>,
162 U: optional::Noned + metfor::Length,
163 Meters: From<U>,
164 {
165 let elevation: Optioned<U> = Optioned::from(elev);
166 let elevation: Optioned<Meters> = elevation.map_t(Meters::from);
167
168 self.elevation = elevation;
169 self
170 }
171
172 /// Builder method to add a station ID. These are usually 3 or 4 alphanumeric codes that may
173 /// not be unique to the location like the station number is supposed to be.
174 #[inline]
175 pub fn with_station_id<T>(mut self, station_id: T) -> Self
176 where
177 Option<String>: From<T>,
178 {
179 let id: Option<String> = Option::from(station_id);
180 self.id = id;
181 self
182 }
183
184 /// station number, USAF number, eg 727730
185 #[inline]
186 pub fn station_num(&self) -> Optioned<i32> {
187 self.num
188 }
189
190 /// Latitude and longitude.
191 #[inline]
192 pub fn location(&self) -> Option<(f64, f64)> {
193 self.location
194 }
195
196 /// Elevation in meters, this may be in model terrain, not necessarily the same as
197 /// the real world.
198 #[inline]
199 pub fn elevation(&self) -> Optioned<Meters> {
200 self.elevation
201 }
202
203 /// Get the station ID that was used with this station. This is normally a series of 3 or 4
204 /// letters. It is not unique to the location like the station number is supposed to be.
205 ///
206 /// # Examples
207 /// ```
208 /// use sounding_analysis::StationInfo;
209 ///
210 /// let info = StationInfo::new().with_station_id("KXLY".to_owned());
211 /// assert_eq!(Some("KXLY"), info.station_id());
212 /// ```
213 #[inline]
214 pub fn station_id(&self) -> Option<&str> {
215 self.id.as_ref().map(|s| s.as_ref())
216 }
217}