Skip to main content

geospatial_types/
elevation.rs

1//! Elevation record types.
2
3use crate::coordinate::GeographicCoordinate;
4use serde::{Deserialize, Serialize};
5
6/// Elevation sampled at one coordinate.
7#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
8pub struct ElevationPoint {
9    /// Position the sample belongs to.
10    pub coordinate: GeographicCoordinate,
11    /// Elevation above mean sea level in meters.
12    pub elevation_meters: f64,
13}
14
15/// Elevation samples along a route used for profile rendering.
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct ElevationProfile {
18    /// Samples in traversal order.
19    pub points: Vec<ElevationPoint>,
20}
21
22impl ElevationProfile {
23    /// Largest elevation gain along the profile in meters.
24    pub fn maximum_elevation_gain_meters(&self) -> f64 {
25        let mut minimum_so_far = f64::INFINITY;
26        let mut maximum_gain = 0.0_f64;
27        for point in &self.points {
28            minimum_so_far = minimum_so_far.min(point.elevation_meters);
29            maximum_gain = maximum_gain.max(point.elevation_meters - minimum_so_far);
30        }
31        maximum_gain
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use super::{ElevationPoint, ElevationProfile};
38    use crate::coordinate::GeographicCoordinate;
39
40    fn point(latitude: f64, elevation_meters: f64) -> ElevationPoint {
41        ElevationPoint {
42            coordinate: GeographicCoordinate::from_degrees(latitude, 0.0).unwrap(),
43            elevation_meters,
44        }
45    }
46
47    #[test]
48    fn maximum_gain_ignores_dips_after_climbs() {
49        let profile = ElevationProfile {
50            points: vec![
51                point(0.0, 100.0),
52                point(1.0, 400.0),
53                point(2.0, 250.0),
54                point(3.0, 380.0),
55            ],
56        };
57        assert_eq!(profile.maximum_elevation_gain_meters(), 300.0);
58    }
59
60    #[test]
61    fn empty_profile_has_zero_gain() {
62        assert_eq!(
63            ElevationProfile { points: vec![] }.maximum_elevation_gain_meters(),
64            0.0
65        );
66    }
67}